mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Merge remote-tracking branch 'upstream/master' into libarchive
Merge fork with upstream for pull request.
This commit is contained in:
commit
e87e583bca
4
.bazelignore
Normal file
4
.bazelignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Using CMake or own WORKSPACE
|
||||
oss-internship-2020
|
||||
# Uses its own WORKSPACE
|
||||
sandboxed_api/examples/hello_sapi
|
12
.gitmodules
vendored
12
.gitmodules
vendored
|
@ -1,12 +1,18 @@
|
|||
[submodule "oss-internship-2020/sapi_lodepng/lodepng"]
|
||||
path = oss-internship-2020/lodepng/lodepng
|
||||
url = https://github.com/lvandeve/lodepng
|
||||
[submodule "oss-internship-2020/jsonnet/jsonnet"]
|
||||
path = oss-internship-2020/jsonnet/jsonnet
|
||||
url = https://github.com/google/jsonnet.git
|
||||
[submodule "oss-internship-2020/openjpeg/openjpeg"]
|
||||
path = oss-internship-2020/openjpeg/openjpeg
|
||||
url = https://github.com/uclouvain/openjpeg.git
|
||||
[submodule "oss-internship-2020/pffft/master"]
|
||||
path = oss-internship-2020/pffft/master
|
||||
url = https://bitbucket.org/jpommier/pffft/src/master/
|
||||
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
|
||||
path = oss-internship-2020/curl/curl_wrapper/curl
|
||||
url = https://github.com/curl/curl
|
||||
[submodule "oss-internship-2020/gdal/gdal"]
|
||||
path = oss-internship-2020/gdal/gdal
|
||||
url = https://github.com/OSGeo/gdal/tree/master/gdal
|
||||
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
|
||||
path = oss-internship-2020/curl/curl_wrapper/curl
|
||||
url = git@github.com:curl/curl.git
|
||||
|
|
|
@ -44,6 +44,9 @@ include(SapiBuildDefs)
|
|||
# Allow the header generator to auto-configure include paths
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Allow the header generator to auto-configure include paths
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
if (SAPI_FORCE_COLOR_OUTPUT)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # GCC
|
||||
add_compile_options(-fdiagnostics-color=always)
|
||||
|
|
|
@ -132,44 +132,44 @@ function(add_sapi_library)
|
|||
set(_sapi_embed_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(_sapi_embed_name "${_sapi_NAME}")
|
||||
endif()
|
||||
|
||||
set(_sapi_isystem "${_sapi_NAME}.isystem}")
|
||||
list(APPEND _sapi_generator_args
|
||||
"--sapi_name=${_sapi_LIBRARY_NAME}"
|
||||
"--sapi_out=${_sapi_gen_header}"
|
||||
"--sapi_embed_dir=${_sapi_embed_dir}"
|
||||
"--sapi_embed_name=${_sapi_embed_name}"
|
||||
"--sapi_functions=${_sapi_funcs}"
|
||||
"--sapi_ns=${_sapi_NAMESPACE}"
|
||||
"--sapi_isystem=${_sapi_isystem}"
|
||||
)
|
||||
list(JOIN _sapi_full_inputs "," _sapi_full_inputs)
|
||||
if(SAPI_ENABLE_GENERATOR)
|
||||
add_custom_command(
|
||||
OUTPUT "${_sapi_gen_header}"
|
||||
COMMAND sapi_generator_tool
|
||||
"--sapi_name=${_sapi_LIBRARY_NAME}"
|
||||
"--sapi_out=${_sapi_gen_header}"
|
||||
"--sapi_embed_dir=${_sapi_embed_dir}"
|
||||
"--sapi_embed_name=${_sapi_embed_name}"
|
||||
"--sapi_functions=${_sapi_funcs}"
|
||||
"--sapi_ns=${_sapi_NAMESPACE}"
|
||||
${_sapi_full_inputs}
|
||||
COMMENT "Generating interface"
|
||||
DEPENDS ${_sapi_INPUTS}
|
||||
VERBATIM
|
||||
list(APPEND _sapi_generator_command
|
||||
sapi_generator_tool
|
||||
-p "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
${_sapi_generator_args}
|
||||
${_sapi_full_inputs}
|
||||
)
|
||||
else()
|
||||
set(_sapi_isystem "${_sapi_NAME}.isystem")
|
||||
list(JOIN _sapi_full_inputs "," _sapi_full_inputs)
|
||||
add_custom_command(
|
||||
OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}"
|
||||
COMMAND sh -c
|
||||
"${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \
|
||||
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \
|
||||
> \"${_sapi_isystem}\""
|
||||
COMMAND "${SAPI_PYTHON3_EXECUTABLE}" -B
|
||||
"${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py"
|
||||
"--sapi_name=${_sapi_LIBRARY_NAME}"
|
||||
"--sapi_out=${_sapi_gen_header}"
|
||||
"--sapi_embed_dir=${_sapi_embed_dir}"
|
||||
"--sapi_embed_name=${_sapi_embed_name}"
|
||||
"--sapi_functions=${_sapi_funcs}"
|
||||
"--sapi_ns=${_sapi_NAMESPACE}"
|
||||
"--sapi_isystem=${_sapi_isystem}"
|
||||
"--sapi_in=${_sapi_full_inputs}"
|
||||
COMMENT "Generating interface"
|
||||
VERBATIM
|
||||
list(APPEND _sapi_generator_command
|
||||
"${SAPI_PYTHON3_EXECUTABLE}" -B
|
||||
"${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py"
|
||||
${_sapi_generator_args}
|
||||
"--sapi_in=${_sapi_full_inputs}"
|
||||
)
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}"
|
||||
COMMAND sh -c
|
||||
"${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \
|
||||
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \
|
||||
> \"${_sapi_isystem}\""
|
||||
COMMAND ${_sapi_generator_command}
|
||||
COMMENT "Generating interface"
|
||||
DEPENDS ${_sapi_INPUTS}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# Library with the interface
|
||||
if(NOT _sapi_SOURCES)
|
||||
|
|
|
@ -12,15 +12,15 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(libcurl_sandbox)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
option(CURL_SAPI_ENABLE_EXAMPLES "" ON)
|
||||
option(CURL_SAPI_ENABLE_TESTS "" ON)
|
||||
option(SAPI_CURL_ENABLE_EXAMPLES "" ON)
|
||||
option(SAPI_CURL_ENABLE_TESTS "" ON)
|
||||
|
||||
# Add callbacks used by examples and tests
|
||||
if (CURL_SAPI_ENABLE_EXAMPLES OR CURL_SAPI_ENABLE_TESTS)
|
||||
|
@ -35,8 +35,8 @@ add_subdirectory(curl_wrapper)
|
|||
|
||||
# Setup Sandboxed API
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ENABLE_EXAMPLES ${CURL_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_TESTS ${CURL_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_EXAMPLES ${SAPI_CURL_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_TESTS ${SAPI_CURL_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
||||
add_subdirectory(
|
||||
"${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
|
@ -125,7 +125,7 @@ add_sapi_library(curl_sapi
|
|||
|
||||
LIBRARY_NAME Curl
|
||||
|
||||
NAMESPACE ""
|
||||
NAMESPACE curl
|
||||
)
|
||||
|
||||
# Include generated SAPI header
|
||||
|
@ -134,11 +134,11 @@ target_include_directories(curl_sapi INTERFACE
|
|||
)
|
||||
|
||||
# Add examples
|
||||
if (CURL_SAPI_ENABLE_EXAMPLES)
|
||||
if (SAPI_CURL_ENABLE_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# Add tests
|
||||
if (CURL_SAPI_ENABLE_TESTS)
|
||||
if (SAPI_CURL_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
|
@ -38,12 +38,15 @@ Variadic methods are currently not supported by Sandboxed API. To solve this,
|
|||
these methods are defined with an additional explicit parameter in
|
||||
`custom_curl.h`.
|
||||
|
||||
The methods are: - `curl_easy_setopt`. Use `curl_easy_setopt_ptr`,
|
||||
`curl_easy_setopt_long` or `curl_easy_setopt_curl_off_t` instead. -
|
||||
`curl_easy_getinfo`. Use `curl_easy_getinfo_ptr` instead. - `curl_multi_setopt`.
|
||||
Use `curl_multi_setopt_ptr`, `curl_multi_setopt_long` or
|
||||
`curl_multi_setopt_curl_off_t` instead. - `curl_share_setopt`. Use
|
||||
`curl_share_setopt_ptr` or `curl_share_setopt_long` instead
|
||||
The methods are:
|
||||
|
||||
- `curl_easy_setopt`. Use `curl_easy_setopt_ptr`, `curl_easy_setopt_long` or
|
||||
`curl_easy_setopt_curl_off_t` instead.
|
||||
- `curl_easy_getinfo`. Use `curl_easy_getinfo_ptr` instead.
|
||||
- `curl_multi_setopt`. Use `curl_multi_setopt_ptr`, `curl_multi_setopt_long`
|
||||
or `curl_multi_setopt_curl_off_t` instead.
|
||||
- `curl_share_setopt`. Use `curl_share_setopt_ptr` or `curl_share_setopt_long`
|
||||
instead
|
||||
|
||||
#### Methods with incomplete array arguments
|
||||
|
||||
|
@ -51,8 +54,10 @@ Incomplete array arguments are currently not supported by Sandboxed API. To
|
|||
solve this, methods taking an incomplete array argument have a wrapper in
|
||||
`custom_curl.h`, and take a pointer as the argument.
|
||||
|
||||
The methods are: - `curl_multi_poll`. Use `curl_multi_poll_sapi` instead. -
|
||||
`curl_multi_wait`. Use `curl_multi_wait_sapi` instead.
|
||||
The methods are:
|
||||
|
||||
- `curl_multi_poll`. Use `curl_multi_poll_sapi` instead.
|
||||
- `curl_multi_wait`. Use `curl_multi_wait_sapi` instead.
|
||||
|
||||
#### Methods with conflicts on the generated header
|
||||
|
||||
|
@ -60,11 +65,15 @@ Some methods create conflicts on the generated header because of redefined
|
|||
`#define` directives from files included by the header. To solve this, the
|
||||
conflicting types and methods are redefined in `custom_curl.h`.
|
||||
|
||||
The types are: - `time_t`. Use `time_t_sapi` instead. - `fd_set`. Use
|
||||
`fd_set_sapi` instead.
|
||||
The types are:
|
||||
|
||||
The methods are: - `curl_getdate`. Use `curl_getdate_sapi` instead. -
|
||||
`curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead.
|
||||
- `time_t`. Use `time_t_sapi` instead.
|
||||
- `fd_set`. Use `fd_set_sapi` instead.
|
||||
|
||||
The methods are:
|
||||
|
||||
- `curl_getdate`. Use `curl_getdate_sapi` instead.
|
||||
- `curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead.
|
||||
|
||||
#### Function pointers
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef TESTS_CALLBACKS_H
|
||||
#define TESTS_CALLBACKS_H
|
||||
#ifndef CALLBACKS_H_
|
||||
#define CALLBACKS_H_
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
@ -21,4 +21,4 @@
|
|||
extern "C" size_t WriteToMemory(char* contents, size_t size, size_t num_bytes,
|
||||
void* userp);
|
||||
|
||||
#endif // TESTS_CALLBACKS_H
|
||||
#endif // CALLBACKS_H_
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
// Wrapper for curl library
|
||||
|
||||
#ifndef CURL_WRAPPER_H
|
||||
#define CURL_WRAPPER_H
|
||||
#ifndef CURL_WRAPPER_H_
|
||||
#define CURL_WRAPPER_H_
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
@ -77,6 +77,7 @@ CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
|
|||
// The wrapper method is needed to make the variadic argument explicit
|
||||
CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
|
||||
long parameter);
|
||||
}
|
||||
|
||||
#endif // CURL_WRAPPER_H
|
||||
} // extern "C"
|
||||
|
||||
#endif // CURL_WRAPPER_H_
|
||||
|
|
|
@ -19,59 +19,67 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Example1() {
|
||||
// Initialize sandbox2 and sapi
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Initialize the curl session
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the library to follow a redirection
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_FOLLOWLOCATION, 1l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Disable authentication of peer certificate
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_SSL_VERIFYPEER, 0l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the library to follow a redirection
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Disable authentication of peer certificate
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
if (absl::Status status = Example1(); !status.ok()) {
|
||||
LOG(ERROR) << "Example1 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -20,87 +20,89 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
namespace {
|
||||
|
||||
absl::Status Example2() {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Generate pointer to WriteMemoryCallback function
|
||||
void* function_ptr;
|
||||
status = sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel().Symbol failed: " << status;
|
||||
}
|
||||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
SAPI_RETURN_IF_ERROR(
|
||||
sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr));
|
||||
sapi::v::RemotePtr write_to_memory(function_ptr);
|
||||
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set WriteMemoryCallback as the write function
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEFUNCTION,
|
||||
&write_to_memory));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Pass 'chunk' struct to the callback function
|
||||
sapi::v::LenVal chunk(0);
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA, chunk.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEDATA,
|
||||
chunk.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set a user agent
|
||||
sapi::v::ConstCStr user_agent("libcurl-agent/1.0");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
|
||||
user_agent.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_USERAGENT,
|
||||
user_agent.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Retrieve memory size
|
||||
status = sandbox.TransferFromSandboxee(&chunk);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "sandbox.TransferFromSandboxee failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&chunk));
|
||||
std::cout << "memory size: " << chunk.GetDataSize() << " bytes" << std::endl;
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
if (absl::Status status = Example2(); !status.ok()) {
|
||||
LOG(ERROR) << "Example2 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
||||
namespace {
|
||||
|
||||
class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox {
|
||||
public:
|
||||
CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
|
||||
std::string ca_certificates)
|
||||
|
@ -42,7 +44,7 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
|||
.AddFile(ssl_key)
|
||||
.AddFile(ca_certificates);
|
||||
// Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox
|
||||
return CurlSapiSandbox::ModifyPolicy(policy_builder.get());
|
||||
return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get());
|
||||
}
|
||||
|
||||
std::string ssl_certificate;
|
||||
|
@ -50,116 +52,121 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
|||
std::string ca_certificates;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Get input parameters (should be absolute paths)
|
||||
if (argc != 5) {
|
||||
LOG(FATAL) << "wrong number of arguments (4 expected)";
|
||||
}
|
||||
std::string ssl_certificate = argv[1];
|
||||
std::string ssl_key = argv[2];
|
||||
std::string ssl_key_password = argv[3];
|
||||
std::string ca_certificates = argv[4];
|
||||
|
||||
absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
|
||||
std::string ssl_key_password,
|
||||
std::string ca_certificates) {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize curl easy handle
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
// Specify URL to get (using HTTPS)
|
||||
sapi::v::ConstCStr url("https://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the SSL certificate type to "PEM"
|
||||
sapi::v::ConstCStr ssl_cert_type("PEM");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE,
|
||||
ssl_cert_type.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE,
|
||||
ssl_cert_type.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the certificate for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT,
|
||||
sapi_ssl_certificate.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT,
|
||||
sapi_ssl_certificate.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the private key for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY, sapi_ssl_key.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY,
|
||||
sapi_ssl_key.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the password used to protect the private key
|
||||
sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD,
|
||||
sapi_ssl_key_password.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD,
|
||||
sapi_ssl_key_password.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the file with the certificates vaildating the server
|
||||
sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO,
|
||||
sapi_ca_certificates.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO,
|
||||
sapi_ca_certificates.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Verify the authenticity of the server
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_SSL_VERIFYPEER, 1L));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl easy handle
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
// Get input parameters (should be absolute paths)
|
||||
if (argc != 5) {
|
||||
LOG(ERROR) << "wrong number of arguments (4 expected)";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]);
|
||||
!status.ok()) {
|
||||
LOG(ERROR) << "Example3 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -21,107 +21,113 @@
|
|||
#include "curl_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
namespace {
|
||||
|
||||
absl::Status Example4() {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Number of running handles
|
||||
sapi::v::Int still_running(1);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize http_handle
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr http_handle(curl_handle.value());
|
||||
if (!http_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: http_handle is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr http_handle(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&http_handle, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize multi_handle
|
||||
absl::StatusOr<CURLM*> curlm_handle = api.curl_multi_init();
|
||||
if (!curlm_handle.ok()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: " << curlm_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr multi_handle(curlm_handle.value());
|
||||
if (!multi_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: multi_handle is NULL";
|
||||
curl::CURLM* curlm_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curlm_handle, api.curl_multi_init());
|
||||
sapi::v::RemotePtr multi_handle(curlm_handle);
|
||||
if (!curlm_handle) {
|
||||
return absl::UnavailableError(
|
||||
"curl_multi_init failed: multi_handle is NULL");
|
||||
}
|
||||
|
||||
// Add http_handle to the multi stack
|
||||
curl_code = api.curl_multi_add_handle(&multi_handle, &http_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_add_handle failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_multi_add_handle(&multi_handle, &http_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_add_handle failed: " + curl_code);
|
||||
}
|
||||
|
||||
while (still_running.GetValue()) {
|
||||
sapi::v::Int numfds(0);
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_multi_perform(&multi_handle, still_running.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_mutli_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_perform(
|
||||
&multi_handle, still_running.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_mutli_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
if (still_running.GetValue()) {
|
||||
// Wait for an event or timeout
|
||||
sapi::v::NullPtr null_ptr;
|
||||
curl_code = api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
|
||||
numfds.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_poll_sapi failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
curl_code, api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
|
||||
numfds.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_poll_sapi failed: " +
|
||||
curl_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove http_handle from the multi stack
|
||||
curl_code = api.curl_multi_remove_handle(&multi_handle, &http_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_remove_handle failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_multi_remove_handle(&multi_handle, &http_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_remove_handle failed: " +
|
||||
curl_code);
|
||||
}
|
||||
|
||||
// Cleanup http_handle
|
||||
status = api.curl_easy_cleanup(&http_handle);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&http_handle));
|
||||
|
||||
// Cleanup multi_handle
|
||||
curl_code = api.curl_multi_cleanup(&multi_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_cleanup failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_cleanup(&multi_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_cleanup failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
if (absl::Status status = Example4(); !status.ok()) {
|
||||
LOG(ERROR) << "Example4 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -15,87 +15,90 @@
|
|||
// Sandboxed version of multithread.c
|
||||
// Multithreaded HTTP GET requests
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <future> // NOLINT(build/c++11)
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
void pull_one_url(const std::string& url, CurlApi& api) {
|
||||
namespace {
|
||||
|
||||
absl::Status pull_one_url(const std::string& url, curl::CurlApi& api) {
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr sapi_url(url.c_str());
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, sapi_url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
sapi_url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
absl::Status status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
// Cleanup curl easy handle
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
const std::vector<std::string> urls = {
|
||||
"http://example.com", "http://example.edu", "http://example.net",
|
||||
"http://example.org"};
|
||||
|
||||
absl::Status Example5() {
|
||||
// Initialize sandbox2 and sapi
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Create the threads (by using futures)
|
||||
std::vector<std::future<absl::Status>> futures;
|
||||
for (auto& url : urls) {
|
||||
futures.emplace_back(
|
||||
std::async(pull_one_url, std::ref(url), std::ref(api)));
|
||||
}
|
||||
|
||||
// Join the threads and check for errors
|
||||
for (auto& future : futures) {
|
||||
SAPI_RETURN_IF_ERROR(future.get());
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Create the threads
|
||||
std::vector<std::thread> threads;
|
||||
for (auto& url : urls) {
|
||||
threads.emplace_back(pull_one_url, std::ref(url), std::ref(api));
|
||||
}
|
||||
|
||||
// Join the threads
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
if (absl::Status status = Example5(); !status.ok()) {
|
||||
LOG(ERROR) << "Example5 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/transaction.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class CurlTransaction : public sapi::Transaction {
|
||||
public:
|
||||
explicit CurlTransaction(std::unique_ptr<sapi::Sandbox> sandbox)
|
||||
|
@ -36,7 +38,7 @@ class CurlTransaction : public sapi::Transaction {
|
|||
};
|
||||
|
||||
absl::Status CurlTransaction::Main() {
|
||||
CurlApi api(sandbox());
|
||||
curl::CurlApi api(sandbox());
|
||||
|
||||
// Initialize the curl session
|
||||
SAPI_ASSIGN_OR_RETURN(void* curl_remote, api.curl_easy_init());
|
||||
|
@ -47,13 +49,13 @@ absl::Status CurlTransaction::Main() {
|
|||
sapi::v::ConstCStr url("http://example.com");
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
int setopt_url_code,
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
|
||||
"curl_easy_setopt_ptr failed");
|
||||
|
||||
// Perform the request
|
||||
SAPI_ASSIGN_OR_RETURN(int perform_code, api.curl_easy_perform(&curl));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
|
||||
"curl_easy_perform failed");
|
||||
|
||||
// Cleanup curl
|
||||
|
@ -63,8 +65,10 @@ absl::Status CurlTransaction::Main() {
|
|||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CurlTransaction curl{std::make_unique<CurlSapiSandbox>()};
|
||||
CurlTransaction curl{std::make_unique<curl::CurlSapiSandbox>()};
|
||||
absl::Status status = curl.Run();
|
||||
CHECK(status.ok()) << "CurlTransaction failed";
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
#include "curl_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
|
||||
|
||||
class CurlSapiSandbox : public CurlSandbox {
|
||||
namespace curl {
|
||||
|
||||
class CurlSapiSandbox : public curl::CurlSandbox {
|
||||
protected:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder* policy_builder) override {
|
||||
|
@ -64,4 +66,6 @@ class CurlSapiSandbox : public CurlSandbox {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace curl
|
||||
|
||||
#endif // SANDBOX_H_
|
||||
|
|
|
@ -28,17 +28,17 @@
|
|||
int CurlTestUtils::port_;
|
||||
std::thread CurlTestUtils::server_thread_;
|
||||
|
||||
absl::Status CurlTestUtils::CurlTestSetUp() {
|
||||
absl::Status curl::tests::CurlTestUtils::CurlTestSetUp() {
|
||||
// Initialize sandbox2 and sapi
|
||||
sandbox_ = std::make_unique<CurlSapiSandbox>();
|
||||
sandbox_ = std::make_unique<curl::CurlSapiSandbox>();
|
||||
absl::Status init = sandbox_->Init();
|
||||
if (!init.ok()) {
|
||||
return init;
|
||||
}
|
||||
api_ = std::make_unique<CurlApi>(sandbox_.get());
|
||||
api_ = std::make_unique<curl::CurlApi>(sandbox_.get());
|
||||
|
||||
// Initialize curl
|
||||
absl::StatusOr<CURL*> curl_handle = api_->curl_easy_init();
|
||||
absl::StatusOr<curl::CURL*> curl_handle = api_->curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
return curl_handle.status();
|
||||
}
|
||||
|
@ -51,23 +51,24 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
|
||||
// Specify request URL
|
||||
sapi::v::ConstCStr sapi_url(kUrl.data());
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL,
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_URL,
|
||||
sapi_url.PtrBefore());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
// Set port
|
||||
curl_code = api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_);
|
||||
curl_code =
|
||||
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_PORT, port_);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_long returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -83,12 +84,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
|
||||
// Set WriteToMemory as the write function
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
curl_code = api_->curl_easy_setopt_ptr(
|
||||
curl_.get(), curl::CURLOPT_WRITEFUNCTION, &remote_function_ptr);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -96,12 +97,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
|
||||
// Pass memory chunk object to the callback
|
||||
chunk_ = std::make_unique<sapi::v::LenVal>(0);
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA,
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_WRITEDATA,
|
||||
chunk_->PtrBoth());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -110,18 +111,18 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CurlTestUtils::CurlTestTearDown() {
|
||||
absl::Status curl::tests::CurlTestUtils::CurlTestTearDown() {
|
||||
// Cleanup curl
|
||||
return api_->curl_easy_cleanup(curl_.get());
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> CurlTestUtils::PerformRequest() {
|
||||
absl::StatusOr<std::string> curl::tests::CurlTestUtils::PerformRequest() {
|
||||
// Perform the request
|
||||
absl::StatusOr<int> curl_code = api_->curl_easy_perform(curl_.get());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_perform returned with the error code " + curl_code.value());
|
||||
}
|
||||
|
@ -267,7 +268,7 @@ void ServerLoop(int listening_socket, sockaddr_in socket_address) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void CurlTestUtils::StartMockServer() {
|
||||
void curl::tests::CurlTestUtils::StartMockServer() {
|
||||
// Get the socket file descriptor
|
||||
int listening_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
namespace curl::tests {
|
||||
|
||||
// Helper class that can be used to test Curl Sandboxed
|
||||
class CurlTestUtils {
|
||||
protected:
|
||||
|
@ -39,8 +41,8 @@ class CurlTestUtils {
|
|||
// Responds with the POST request fields to a POST request
|
||||
static void StartMockServer();
|
||||
|
||||
std::unique_ptr<CurlSapiSandbox> sandbox_;
|
||||
std::unique_ptr<CurlApi> api_;
|
||||
std::unique_ptr<curl::CurlSapiSandbox> sandbox_;
|
||||
std::unique_ptr<curl::CurlApi> api_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> curl_;
|
||||
|
||||
static std::thread server_thread_;
|
||||
|
@ -52,4 +54,6 @@ class CurlTestUtils {
|
|||
std::unique_ptr<sapi::v::LenVal> chunk_;
|
||||
};
|
||||
|
||||
} // namespace curl::tests
|
||||
|
||||
#endif // TESTS_H_
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include "test_utils.h" // NOLINT(build/include)
|
||||
|
||||
class CurlTest : public CurlTestUtils, public ::testing::Test {
|
||||
namespace {
|
||||
|
||||
class CurlTest : public curl::tests::CurlTestUtils, public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Start mock server, get port number and check for any error
|
||||
|
@ -38,9 +40,9 @@ TEST_F(CurlTest, EffectiveUrl) {
|
|||
// Get effective URL
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int getinfo_code,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_EFFECTIVE_URL,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_EFFECTIVE_URL,
|
||||
effective_url_ptr.PtrBoth()));
|
||||
ASSERT_EQ(getinfo_code, CURLE_OK);
|
||||
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
|
||||
|
||||
// Store effective URL in a string
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string effective_url,
|
||||
|
@ -74,9 +76,9 @@ TEST_F(CurlTest, ResponseCode) {
|
|||
// Get response code
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int getinfo_code,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_RESPONSE_CODE,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_RESPONSE_CODE,
|
||||
response_code.PtrBoth()));
|
||||
ASSERT_EQ(getinfo_code, CURLE_OK);
|
||||
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
|
||||
|
||||
// Check response code
|
||||
ASSERT_EQ(response_code.GetValue(), 200);
|
||||
|
@ -120,19 +122,21 @@ TEST_F(CurlTest, POSTResponse) {
|
|||
// Set the size of the POST fields
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_post_fields_size,
|
||||
api_->curl_easy_setopt_long(curl_.get(), CURLOPT_POSTFIELDSIZE,
|
||||
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_POSTFIELDSIZE,
|
||||
post_fields.GetSize()));
|
||||
ASSERT_EQ(setopt_post_fields_size, CURLE_OK);
|
||||
ASSERT_EQ(setopt_post_fields_size, curl::CURLE_OK);
|
||||
|
||||
// Set the POST fields
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_post_fields,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_POSTFIELDS,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_POSTFIELDS,
|
||||
post_fields.PtrBefore()));
|
||||
ASSERT_EQ(setopt_post_fields, CURLE_OK);
|
||||
ASSERT_EQ(setopt_post_fields, curl::CURLE_OK);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
|
||||
|
||||
// Compare response with expected response
|
||||
ASSERT_EQ(std::string(post_fields.GetData()), response);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -24,6 +24,7 @@ cc_library(
|
|||
srcs = ["guetzli_entry_points.cc"],
|
||||
hdrs = ["guetzli_entry_points.h"],
|
||||
deps = [
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_sandboxed_api//sandboxed_api:lenval_core",
|
||||
"@com_google_sandboxed_api//sandboxed_api:vars",
|
||||
"@guetzli//:guetzli_lib",
|
||||
|
@ -53,9 +54,7 @@ sapi_library(
|
|||
cc_binary(
|
||||
name = "guetzli_sandboxed",
|
||||
srcs = ["guetzli_sandboxed.cc"],
|
||||
deps = [
|
||||
":guetzli_sapi",
|
||||
],
|
||||
deps = [":guetzli_sapi"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "guetzli/jpeg_data_reader.h"
|
||||
#include "guetzli/quality.h"
|
||||
#include "png.h" // NOLINT(build/include)
|
||||
#include "absl/status/statusor.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/util/statusor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -51,7 +51,7 @@ sapi::LenValStruct CreateLenValFromData(const void* data, size_t size) {
|
|||
return {size, new_data};
|
||||
}
|
||||
|
||||
sapi::StatusOr<std::string> ReadFromFd(int fd) {
|
||||
absl::StatusOr<std::string> ReadFromFd(int fd) {
|
||||
struct stat file_data;
|
||||
int status = fstat(fd, &file_data);
|
||||
|
||||
|
@ -70,9 +70,9 @@ sapi::StatusOr<std::string> ReadFromFd(int fd) {
|
|||
return result;
|
||||
}
|
||||
|
||||
sapi::StatusOr<GuetzliInitData> PrepareDataForProcessing(
|
||||
absl::StatusOr<GuetzliInitData> PrepareDataForProcessing(
|
||||
const ProcessingParams& processing_params) {
|
||||
sapi::StatusOr<std::string> input = ReadFromFd(processing_params.remote_fd);
|
||||
absl::StatusOr<std::string> input = ReadFromFd(processing_params.remote_fd);
|
||||
|
||||
if (!input.ok()) {
|
||||
return input.status();
|
||||
|
@ -96,7 +96,7 @@ inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) {
|
|||
}
|
||||
|
||||
// Modified version of ReadPNG from original guetzli.cc
|
||||
sapi::StatusOr<ImageData> ReadPNG(const std::string& data) {
|
||||
absl::StatusOr<ImageData> ReadPNG(const std::string& data) {
|
||||
std::vector<uint8_t> rgb;
|
||||
int xsize, ysize;
|
||||
png_structp png_ptr =
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "guetzli_transaction.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/util/statusor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ TEST_F(GuetzliSapiTest, ProcessRGB) {
|
|||
*processing_params.mutable_data() = {
|
||||
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
|
||||
sapi::v::LenVal output(0);
|
||||
sapi::StatusOr<bool> processing_result =
|
||||
absl::StatusOr<bool> processing_result =
|
||||
api_->ProcessRgb(processing_params.PtrBefore(), output.PtrBoth());
|
||||
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing rgb data";
|
||||
std::string reference_data =
|
||||
|
@ -108,7 +108,7 @@ TEST_F(GuetzliSapiTest, ProcessJpeg) {
|
|||
*processing_params.mutable_data() = {
|
||||
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
|
||||
sapi::v::LenVal output(0);
|
||||
sapi::StatusOr<bool> processing_result =
|
||||
absl::StatusOr<bool> processing_result =
|
||||
api_->ProcessJpeg(processing_params.PtrBefore(), output.PtrBoth());
|
||||
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing jpg data";
|
||||
std::string reference_data =
|
||||
|
|
|
@ -99,7 +99,7 @@ absl::Status GuetzliTransaction::LinkOutFile(int out_fd) const {
|
|||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
sapi::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const {
|
||||
absl::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const {
|
||||
static const unsigned char kPNGMagicBytes[] = {
|
||||
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
|
||||
};
|
||||
|
|
|
@ -48,7 +48,7 @@ class GuetzliTransaction : public sapi::Transaction {
|
|||
absl::Status Main() final;
|
||||
|
||||
absl::Status LinkOutFile(int out_fd) const;
|
||||
sapi::StatusOr<ImageType> GetImageTypeFromFd(int fd) const;
|
||||
absl::StatusOr<ImageType> GetImageTypeFromFd(int fd) const;
|
||||
|
||||
const TransactionParams params_;
|
||||
ImageType image_type_ = ImageType::kJpeg;
|
||||
|
|
58
oss-internship-2020/jsonnet/CMakeLists.txt
Normal file
58
oss-internship-2020/jsonnet/CMakeLists.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http:#www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(jsonnet-sapi C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
add_subdirectory(jsonnet)
|
||||
|
||||
add_subdirectory(examples)
|
||||
|
||||
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
add_sapi_library(jsonnet_sapi
|
||||
FUNCTIONS c_jsonnet_evaluate_snippet
|
||||
c_jsonnet_make
|
||||
c_jsonnet_destroy
|
||||
c_read_input
|
||||
c_write_output_file
|
||||
c_jsonnet_realloc
|
||||
c_jsonnet_evaluate_snippet_multi
|
||||
c_write_multi_output_files
|
||||
c_write_output_stream
|
||||
c_jsonnet_evaluate_snippet_stream
|
||||
c_jsonnet_fmt_snippet
|
||||
INPUTS jsonnet_helper.h
|
||||
LIBRARY jsonnet_helper
|
||||
LIBRARY_NAME Jsonnet
|
||||
NAMESPACE ""
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_sapi PUBLIC jsonnet_helper)
|
||||
|
||||
add_subdirectory(tests)
|
84
oss-internship-2020/jsonnet/README.md
Normal file
84
oss-internship-2020/jsonnet/README.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Jsonnet Sandboxed API
|
||||
|
||||
This library provides sandboxed version of the
|
||||
[Jsonnet](https://github.com/google/jsonnet) library.
|
||||
|
||||
## Examples
|
||||
|
||||
The `examples/` directory contains code to produce three command-line tools --
|
||||
`jsonnet_sandboxed`, `jsonnet_yaml_stream_sandboxed` and
|
||||
`jsonnet_multiple_files_sandboxed` to evaluate jsonnet code. The first one
|
||||
enables the user to evaluate jsonnet code held in one file and writing to one
|
||||
output file. The second evaluates one jsonnet file into one file, which can be
|
||||
interepreted as YAML stream. The third one is for evaluating one jsonnet file
|
||||
into multiple output files. All three tools are based on what can be found
|
||||
[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnet.cpp).
|
||||
|
||||
Apart from these, there is also a file producing `jsonnet_formatter_sandboxed`
|
||||
executable. It is based on a tool found from
|
||||
[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnetfmt.cpp). It is
|
||||
a jsonnet code formatter -- it changes poorly written jsonnet files into their
|
||||
canonical form.
|
||||
|
||||
## Build
|
||||
|
||||
To build these examples, after cloning the whole Sandbox API project, you also
|
||||
need to run
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
anywhere in the project tree in order to clone the `jsonnet` submodule.
|
||||
Then in the `sandboxed-api/oss-internship-2020/jsonnet` run
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -G Ninja
|
||||
ninja
|
||||
```
|
||||
|
||||
To run `jsonnet_sandboxed` (or `jsonnet_yaml_stream_sandboxed` or
|
||||
`jsonnet_formatter_sandboxed` in a similar way):
|
||||
|
||||
```
|
||||
cd examples
|
||||
./jsonnet_sandboxed \
|
||||
absolute/path/to/the/input_file.jsonnet \
|
||||
absolute/path/to/the/output_file
|
||||
```
|
||||
|
||||
To run `jsonnet_mutiple_files_sandboxed`:
|
||||
|
||||
```
|
||||
cd examples
|
||||
./jsonnet_mutiple_files_sandboxed \
|
||||
absolute/path/to/the/input_file.jsonnet \
|
||||
absolute/path/to/the/output_directory
|
||||
```
|
||||
|
||||
All three tools support evaluating one input file (possibly relying on multiple
|
||||
other files, e.x. by jsonnet `import` command; the files must be held in the
|
||||
same directory as input file) into one or more output files. Example jsonnet
|
||||
codes to evaluate in a one-in-one-out manner can be found
|
||||
[here](https://github.com/google/jsonnet/tree/master/examples). Example code
|
||||
producing multiple output files or YAML stream files can be found in the
|
||||
`examples/jsonnet_codes` directory (along with some other examples copied with
|
||||
minimal changes from the library files), in files called
|
||||
`multiple_files_example.jsonnet` and `yaml_stream_example.jsonnet`,
|
||||
respectively. In the `examples/jsonnet_codes_expected_output` directory one can
|
||||
found outputs the mentioned above files' evaluation should produce.
|
||||
|
||||
The formatter reads one input file and produces one output file as a result.
|
||||
Example code for this tool can also be found in `examples/jsonnet_codes`
|
||||
directory, in a file called `formatter_example.jsonnet`.
|
||||
|
||||
## Testing
|
||||
|
||||
A few tests prepared with a use of
|
||||
[Google Test](https://github.com/google/googletest) framework can be found in
|
||||
the `tests/` directory. To run them type:
|
||||
|
||||
```
|
||||
cd tests
|
||||
./tests
|
||||
```
|
75
oss-internship-2020/jsonnet/examples/CMakeLists.txt
Normal file
75
oss-internship-2020/jsonnet/examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gen_files")
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/jsonnet/cmd/jsonnet.cpp" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/jsonnet.patch" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/gen_files && patch < ${PROJECT_SOURCE_DIR}/jsonnet.patch > /dev/null
|
||||
COMMAND mv ${PROJECT_BINARY_DIR}/gen_files/jsonnet.cpp ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
)
|
||||
|
||||
list(APPEND JSONNET_SAPI_HEADERS
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/headers
|
||||
${PROJECT_BINARY_DIR}/gen_files
|
||||
)
|
||||
|
||||
add_library(jsonnet_helper STATIC
|
||||
${PROJECT_SOURCE_DIR}/jsonnet_helper.cc
|
||||
${PROJECT_SOURCE_DIR}/jsonnet_helper.h
|
||||
${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.h
|
||||
${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.cpp
|
||||
${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_helper PUBLIC
|
||||
${JSONNET_SAPI_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_helper
|
||||
libjsonnet_for_binaries
|
||||
)
|
||||
|
||||
foreach(exe base multiple_files yaml_stream formatter)
|
||||
add_executable(jsonnet_${exe}_sandboxed
|
||||
jsonnet_${exe}_example.cc
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_${exe}_sandboxed PRIVATE
|
||||
libjsonnet
|
||||
jsonnet_helper
|
||||
jsonnet_sapi
|
||||
sandbox2::file_base
|
||||
sandbox2::fileops
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_${exe}_sandboxed PUBLIC
|
||||
${JSONNET_SAPI_HEADERS}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(jsonnet_base_transacted
|
||||
jsonnet_base_transaction.cc
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_base_transacted PRIVATE
|
||||
libjsonnet
|
||||
jsonnet_helper
|
||||
jsonnet_sapi
|
||||
sapi::sapi
|
||||
)
|
95
oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc
Normal file
95
oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetBaseSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file "
|
||||
"are in the same directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "jsonnet_base_transaction.h" // NOLINT(build/include)
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetTransaction::Main() {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
JsonnetApi api(sandbox());
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
TRANSACTION_FAIL_IF_NOT(error.GetValue() == 0,
|
||||
"Jsonnet code evaluation failed.");
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(success, "Writing to output file failed.");
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
JsonnetTransaction jsonnet_transaction(in_file, out_file);
|
||||
|
||||
auto result = jsonnet_transaction.Run();
|
||||
|
||||
LOG(INFO) << "Transaction result: " << result.message();
|
||||
CHECK(result.ok());
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
concat_array: [1, 2, 3] + [4],
|
||||
concat_string: '123' + 4,
|
||||
equality1: 1 == '1',
|
||||
equality2: [{}, { x: 3 - 1 }]
|
||||
== [{}, { x: 2 }],
|
||||
ex1: 1 + 2 * 3 / (4 + 5),
|
||||
// Bitwise operations first cast to int.
|
||||
ex2: self.ex1 | 3,
|
||||
// Modulo operator.
|
||||
ex3: self.ex1 % 2,
|
||||
// Boolean logic
|
||||
ex4: (4 > 3) && (1 <= 3) || false,
|
||||
// Mixing objects together
|
||||
obj: { a: 1, b: 2 } + { b: 3, c: 4 },
|
||||
// Test if a field is in an object
|
||||
obj_member: 'foo' in { foo: 1 },
|
||||
// String formatting
|
||||
str1: 'The value of self.ex2 is '
|
||||
+ self.ex2 + '.',
|
||||
str2: 'The value of self.ex2 is %g.'
|
||||
% self.ex2,
|
||||
str3: 'ex1=%0.2f, ex2=%0.2f'
|
||||
% [self.ex1, self.ex2],
|
||||
// By passing self, we allow ex1 and ex2 to
|
||||
// be extracted internally.
|
||||
str4: 'ex1=%(ex1)0.2f, ex2=%(ex2)0.2f'
|
||||
% self,
|
||||
// Do textual templating of entire files:
|
||||
str5: |||
|
||||
ex1=%(ex1)0.2f
|
||||
ex2=%(ex2)0.2f
|
||||
||| % self,
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This is a poorly written jsonnet file. Given to the formatter executable will be changed into a canonical jsonnet file form.
|
||||
local b = import "somefile.libsonnet"; # comment
|
||||
local a = import "differentfile.libsonnet"; // another comment in different style
|
||||
|
||||
local SomeStuff = {bar: "foo"};
|
||||
|
||||
local funtion_to_do_addition(x,y)=x+y;
|
||||
|
||||
{
|
||||
"this": ((3)) ,
|
||||
"that that":
|
||||
funtion_to_do_addition(4,2),
|
||||
arrArr: [[
|
||||
1, 2, 5
|
||||
],
|
||||
3, 10, 19
|
||||
]
|
||||
} + SomeStuff
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
local martinis = import 'martinis.libsonnet';
|
||||
|
||||
{
|
||||
'Vodka Martini': martinis['Vodka Martini'],
|
||||
Manhattan: {
|
||||
ingredients: [
|
||||
{ kind: 'Rye', qty: 2.5 },
|
||||
{ kind: 'Sweet Red Vermouth', qty: 1 },
|
||||
{ kind: 'Angostura', qty: 'dash' },
|
||||
],
|
||||
garnish: importstr 'garnish.txt',
|
||||
served: 'Straight Up',
|
||||
},
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This is a jsonnet code which evaluates to mutliple output files.
|
||||
{
|
||||
"first_file.json": {
|
||||
name: 'This is the first file created by the multiple-files example code.',
|
||||
caption: 'The other one\'s name is -> ' + $["second_file.json"].name,
|
||||
},
|
||||
"second_file.json": {
|
||||
name: 'And that is the other one.',
|
||||
caption: 'If it was the first one, variable name would hold what\'s in <first_name> variable.',
|
||||
first_name: $["first_file.json"].name,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
local utils = import 'utils.libsonnet';
|
||||
{
|
||||
Negroni: {
|
||||
// Divide 3oz among the 3 ingredients.
|
||||
ingredients: utils.equal_parts(3, [
|
||||
'Farmers Gin',
|
||||
'Sweet Red Vermouth',
|
||||
'Campari',
|
||||
]),
|
||||
garnish: 'Orange Peel',
|
||||
served: 'On The Rocks',
|
||||
},
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
equal_parts(size, ingredients)::
|
||||
// Define a function-scoped variable.
|
||||
local qty = size / std.length(ingredients);
|
||||
// Return an array.
|
||||
[
|
||||
{ kind: i, qty: qty }
|
||||
for i in ingredients
|
||||
],
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This is a jsonnet code which evaluates to json file, which can be interpreted as YAML stream.
|
||||
local
|
||||
first_object = {
|
||||
name: 'First object\'s name.',
|
||||
age: 'Just created!',
|
||||
},
|
||||
second_object = {
|
||||
name: 'Hi, my name is <second_object>.',
|
||||
sibling: first_object.name
|
||||
};
|
||||
|
||||
[first_object, second_object]
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"concat_array": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"concat_string": "1234",
|
||||
"equality1": false,
|
||||
"equality2": true,
|
||||
"ex1": 1.6666666666666665,
|
||||
"ex2": 3,
|
||||
"ex3": 1.6666666666666665,
|
||||
"ex4": true,
|
||||
"obj": {
|
||||
"a": 1,
|
||||
"b": 3,
|
||||
"c": 4
|
||||
},
|
||||
"obj_member": true,
|
||||
"str1": "The value of self.ex2 is 3.",
|
||||
"str2": "The value of self.ex2 is 3.",
|
||||
"str3": "ex1=1.67, ex2=3.00",
|
||||
"str4": "ex1=1.67, ex2=3.00",
|
||||
"str5": "ex1=1.67\nex2=3.00\n"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"caption": "The other one's name is -> And that is the other one.",
|
||||
"name": "This is the first file created by the multiple-files example code."
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"Negroni": {
|
||||
"garnish": "Orange Peel",
|
||||
"ingredients": [
|
||||
{
|
||||
"kind": "Farmers Gin",
|
||||
"qty": 1
|
||||
},
|
||||
{
|
||||
"kind": "Sweet Red Vermouth",
|
||||
"qty": 1
|
||||
},
|
||||
{
|
||||
"kind": "Campari",
|
||||
"qty": 1
|
||||
}
|
||||
],
|
||||
"served": "On The Rocks"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"caption": "If it was the first one, variable name would hold what's in <first_name> variable.",
|
||||
"first_name": "This is the first file created by the multiple-files example code.",
|
||||
"name": "And that is the other one."
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
{
|
||||
"age": "Just created!",
|
||||
"name": "First object's name."
|
||||
}
|
||||
---
|
||||
{
|
||||
"name": "Hi, my name is <second_object>.",
|
||||
"sibling": "First object's name."
|
||||
}
|
||||
...
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
class JsonnetSapiSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetSapiSandbox(std::string in_file, std::string out_file)
|
||||
: in_file_(std::move(in_file)), out_file_(std::move(out_file)) {}
|
||||
|
||||
// We need only the input file here, not the whole input directory
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false)
|
||||
.AddFile(in_file_, true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
};
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetSapiSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_fmt_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
class JsonnetSapiSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetSapiSandbox(std::string in_file, std::string out_directory)
|
||||
: in_file_(std::move(in_file)),
|
||||
out_directory_(std::move(out_directory)) {}
|
||||
|
||||
// We need a slightly different policy than the default one
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(sandbox2::file::CleanPath(&out_directory_[0]),
|
||||
"/output",
|
||||
/*is_ro=*/false)
|
||||
.AddDirectoryAt(dirname(&in_file_[0]), "/input", true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_directory_;
|
||||
};
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetSapiSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_multi(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file "
|
||||
"are in the same directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetBaseSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_stream(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue())
|
||||
<< "Jsonnet code evaluation failed: " << error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file are in the same "
|
||||
"directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
55
oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h
Normal file
55
oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef JSONNET_BASE_SANDBOX_H_
|
||||
#define JSONNET_BASE_SANDBOX_H_
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/transaction.h"
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
class JsonnetBaseSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetBaseSandbox(std::string in_file, std::string out_file)
|
||||
: in_file_(in_file), out_file_(out_file) {}
|
||||
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder *) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false)
|
||||
.AddDirectoryAt(dirname(&in_file_[0]), "/input", true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
};
|
||||
|
||||
#endif // JSONNET_BASE_SANDBOX_H_
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef JSNONNET_BASE_TRANSACTION_H_
|
||||
#define JSNONNET_BASE_TRANSACTION_H_
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
|
||||
class JsonnetTransaction : public sapi::Transaction {
|
||||
public:
|
||||
JsonnetTransaction(std::string in_file, std::string out_file)
|
||||
: sapi::Transaction(
|
||||
std::make_unique<JsonnetBaseSandbox>(in_file, out_file)),
|
||||
in_file_(in_file),
|
||||
out_file_(out_file) {
|
||||
sapi::Transaction::set_retry_count(0); // Try once, no retries
|
||||
sapi::Transaction::SetTimeLimit(0); // Infinite time limit
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
|
||||
absl::Status Main() override;
|
||||
};
|
||||
|
||||
#endif // JSNONNET_BASE_TRANSACTION_H_
|
57
oss-internship-2020/jsonnet/headers/jsonnet_tests.h
Normal file
57
oss-internship-2020/jsonnet/headers/jsonnet_tests.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef JSONNET_TESTS_H_
|
||||
#define JSONNET_TESTS_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
class JsonnetTestHelper {
|
||||
protected:
|
||||
enum Evaluation { kBase, kMultipleFiles, kYamlStream };
|
||||
|
||||
void TestSetUp();
|
||||
void TestTearDown();
|
||||
|
||||
void ReadInput(const char* filename);
|
||||
void EvaluateJsonnetCode(Evaluation type, bool expected_correct);
|
||||
void WriteOutput(const char* filename_or_directory, Evaluation type);
|
||||
std::string ReadOutput(const char* filename);
|
||||
|
||||
std::unique_ptr<JsonnetBaseSandbox> sandbox_;
|
||||
std::unique_ptr<JsonnetApi> api_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> input_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> output_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> vm_;
|
||||
|
||||
std::string input_filename_in_sandboxee_;
|
||||
bool jsonnet_vm_was_used_;
|
||||
bool input_was_read_;
|
||||
};
|
||||
|
||||
#endif // JSONNET_TESTS_H_
|
1
oss-internship-2020/jsonnet/jsonnet
Submodule
1
oss-internship-2020/jsonnet/jsonnet
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3e25595d5c4acd32a1c3951a57471986b90d3bad
|
664
oss-internship-2020/jsonnet/jsonnet.patch
Normal file
664
oss-internship-2020/jsonnet/jsonnet.patch
Normal file
|
@ -0,0 +1,664 @@
|
|||
--- jsonnet.cpp 2020-09-09 12:15:33.687539042 +0000
|
||||
+++ write_helper.cpp 2020-09-25 15:38:37.317147682 +0000
|
||||
@@ -14,559 +14,125 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
-#include <cassert>
|
||||
-#include <cstdlib>
|
||||
-#include <cstring>
|
||||
+// We need two functions defined in jsonnet.cpp file, used for writing output
|
||||
+// (multiple files and yaml streams) -- with minor changes (e.x. return type).
|
||||
|
||||
-#include <exception>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
-#include <list>
|
||||
#include <map>
|
||||
-#include <sstream>
|
||||
-#include <string>
|
||||
#include <vector>
|
||||
|
||||
-#include "utils.h"
|
||||
+#include "jsonnet_helper.h" // NOLINT(build/include)
|
||||
|
||||
-extern "C" {
|
||||
-#include <libjsonnet.h>
|
||||
-}
|
||||
-
|
||||
-#ifdef _WIN32
|
||||
-const char PATH_SEP = ';';
|
||||
-#else
|
||||
-const char PATH_SEP = ':';
|
||||
-#endif
|
||||
-
|
||||
-void version(std::ostream &o)
|
||||
-{
|
||||
- o << "Jsonnet commandline interpreter " << jsonnet_version() << std::endl;
|
||||
-}
|
||||
-
|
||||
-void usage(std::ostream &o)
|
||||
-{
|
||||
- version(o);
|
||||
- o << "\n";
|
||||
- o << "jsonnet {<option>} <filename>\n";
|
||||
- o << "\n";
|
||||
- o << "Available options:\n";
|
||||
- o << " -h / --help This message\n";
|
||||
- o << " -e / --exec Treat filename as code\n";
|
||||
- o << " -J / --jpath <dir> Specify an additional library search dir (right-most wins)\n";
|
||||
- o << " -o / --output-file <file> Write to the output file rather than stdout\n";
|
||||
- o << " -m / --multi <dir> Write multiple files to the directory, list files on stdout\n";
|
||||
- o << " -y / --yaml-stream Write output as a YAML stream of JSON documents\n";
|
||||
- o << " -S / --string Expect a string, manifest as plain text\n";
|
||||
- o << " -s / --max-stack <n> Number of allowed stack frames\n";
|
||||
- o << " -t / --max-trace <n> Max length of stack trace before cropping\n";
|
||||
- o << " --gc-min-objects <n> Do not run garbage collector until this many\n";
|
||||
- o << " --gc-growth-trigger <n> Run garbage collector after this amount of object growth\n";
|
||||
- o << " --version Print version\n";
|
||||
- o << "Available options for specifying values of 'external' variables:\n";
|
||||
- o << "Provide the value as a string:\n";
|
||||
- o << " -V / --ext-str <var>[=<val>] If <val> is omitted, get from environment var <var>\n";
|
||||
- o << " --ext-str-file <var>=<file> Read the string from the file\n";
|
||||
- o << "Provide a value as Jsonnet code:\n";
|
||||
- o << " --ext-code <var>[=<code>] If <code> is omitted, get from environment var <var>\n";
|
||||
- o << " --ext-code-file <var>=<file> Read the code from the file\n";
|
||||
- o << "Available options for specifying values of 'top-level arguments':\n";
|
||||
- o << "Provide the value as a string:\n";
|
||||
- o << " -A / --tla-str <var>[=<val>] If <val> is omitted, get from environment var <var>\n";
|
||||
- o << " --tla-str-file <var>=<file> Read the string from the file\n";
|
||||
- o << "Provide a value as Jsonnet code:\n";
|
||||
- o << " --tla-code <var>[=<code>] If <code> is omitted, get from environment var <var>\n";
|
||||
- o << " --tla-code-file <var>=<file> Read the code from the file\n";
|
||||
- o << "Environment variables:\n";
|
||||
- o << "JSONNET_PATH is a colon (semicolon on Windows) separated list of directories added\n";
|
||||
- o << "in reverse order before the paths specified by --jpath (i.e. left-most wins)\n";
|
||||
- o << "E.g. JSONNET_PATH=a:b jsonnet -J c -J d is equivalent to:\n";
|
||||
- o << "JSONNET_PATH=d:c:a:b jsonnet\n";
|
||||
- o << "jsonnet -J b -J a -J c -J d\n";
|
||||
- o << "\n";
|
||||
- o << "In all cases:\n";
|
||||
- o << "<filename> can be - (stdin)\n";
|
||||
- o << "Multichar options are expanded e.g. -abc becomes -a -b -c.\n";
|
||||
- o << "The -- option suppresses option processing for subsequent arguments.\n";
|
||||
- o << "Note that since filenames and jsonnet programs can begin with -, it is advised to\n";
|
||||
- o << "use -- if the argument is unknown, e.g. jsonnet -- \"$FILENAME\".";
|
||||
- o << std::endl;
|
||||
-}
|
||||
-
|
||||
-/** Class for representing configuration read from command line flags. */
|
||||
-struct JsonnetConfig {
|
||||
- std::vector<std::string> inputFiles;
|
||||
- std::string outputFile;
|
||||
- bool filenameIsCode;
|
||||
-
|
||||
- // EVAL flags
|
||||
- bool evalMulti;
|
||||
- bool evalStream;
|
||||
- std::string evalMultiOutputDir;
|
||||
-
|
||||
- JsonnetConfig()
|
||||
- : filenameIsCode(false),
|
||||
- evalMulti(false),
|
||||
- evalStream(false)
|
||||
- {
|
||||
- }
|
||||
-};
|
||||
-
|
||||
-bool get_var_val(const std::string &var_val, std::string &var, std::string &val)
|
||||
-{
|
||||
- size_t eq_pos = var_val.find_first_of('=', 0);
|
||||
- if (eq_pos == std::string::npos) {
|
||||
- var = var_val;
|
||||
- const char *val_cstr = ::getenv(var.c_str());
|
||||
- if (val_cstr == nullptr) {
|
||||
- std::cerr << "ERROR: environment variable " << var << " was undefined." << std::endl;
|
||||
- return false;
|
||||
- }
|
||||
- val = val_cstr;
|
||||
- } else {
|
||||
- var = var_val.substr(0, eq_pos);
|
||||
- val = var_val.substr(eq_pos + 1, std::string::npos);
|
||||
- }
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-bool get_var_file(const std::string &var_file, const std::string &imp, std::string &var, std::string &val)
|
||||
-{
|
||||
- size_t eq_pos = var_file.find_first_of('=', 0);
|
||||
- if (eq_pos == std::string::npos) {
|
||||
- std::cerr << "ERROR: argument not in form <var>=<file> \"" << var_file << "\"."
|
||||
- << std::endl;
|
||||
- return false;
|
||||
- }
|
||||
- var = var_file.substr(0, eq_pos);
|
||||
- const std::string path = var_file.substr(eq_pos + 1, std::string::npos);
|
||||
-
|
||||
- size_t b, e;
|
||||
- val.erase().append(imp).append(" @'");
|
||||
- // duplicate all the single quotes in @path to make a quoted string
|
||||
- for (b = 0; (e = path.find("'", b)) != std::string::npos; b = e + 1) {
|
||||
- val.append(path.substr(b, e - b + 1)).push_back('\'');
|
||||
+/** Writes output files for multiple file output */
|
||||
+bool write_multi_output_files(char *output, const std::string &output_dir, bool show_output_file_names) {
|
||||
+ // If multiple file output is used, then iterate over each string from
|
||||
+ // the sequence of strings returned by jsonnet_evaluate_snippet_multi,
|
||||
+ // construct pairs of filename and content, and write each output file.
|
||||
+ std::map<std::string, std::string> r;
|
||||
+ for (const char *c = output; *c != '\0';) {
|
||||
+ const char *filename = c;
|
||||
+ const char *c2 = c;
|
||||
+ while (*c2 != '\0') ++c2;
|
||||
+ ++c2;
|
||||
+ const char *json = c2;
|
||||
+ while (*c2 != '\0') ++c2;
|
||||
+ ++c2;
|
||||
+ c = c2;
|
||||
+ r[filename] = json;
|
||||
+ }
|
||||
+
|
||||
+ std::ostream *o;
|
||||
+ std::ofstream f;
|
||||
+
|
||||
+ o = &std::cout;
|
||||
+
|
||||
+ for (const auto &pair : r) {
|
||||
+ const std::string &new_content = pair.second;
|
||||
+ const std::string &filename = output_dir + pair.first;
|
||||
+ if (show_output_file_names) {
|
||||
+ (*o) << filename << std::endl;
|
||||
}
|
||||
- val.append(path.substr(b)).push_back('\'');
|
||||
-
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-enum ArgStatus {
|
||||
- ARG_CONTINUE,
|
||||
- ARG_SUCCESS,
|
||||
- ARG_FAILURE,
|
||||
-};
|
||||
-
|
||||
-/** Parse the command line arguments, configuring the Jsonnet VM context and
|
||||
- * populating the JsonnetConfig.
|
||||
- */
|
||||
-static ArgStatus process_args(int argc, const char **argv, JsonnetConfig *config, JsonnetVm *vm)
|
||||
-{
|
||||
- auto args = simplify_args(argc, argv);
|
||||
- std::vector<std::string> remaining_args;
|
||||
-
|
||||
- unsigned i = 0;
|
||||
-
|
||||
- for (; i < args.size(); ++i) {
|
||||
- const std::string &arg = args[i];
|
||||
- if (arg == "-h" || arg == "--help") {
|
||||
- usage(std::cout);
|
||||
- return ARG_SUCCESS;
|
||||
- } else if (arg == "-v" || arg == "--version") {
|
||||
- version(std::cout);
|
||||
- return ARG_SUCCESS;
|
||||
- } else if (arg == "-e" || arg == "--exec") {
|
||||
- config->filenameIsCode = true;
|
||||
- } else if (arg == "-o" || arg == "--output-file") {
|
||||
- std::string output_file = next_arg(i, args);
|
||||
- if (output_file.length() == 0) {
|
||||
- std::cerr << "ERROR: -o argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- config->outputFile = output_file;
|
||||
- } else if (arg == "--") {
|
||||
- // All subsequent args are not options.
|
||||
- while ((++i) < args.size())
|
||||
- remaining_args.push_back(args[i]);
|
||||
- break;
|
||||
- } else if (arg == "-s" || arg == "--max-stack") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 1) {
|
||||
- std::cerr << "ERROR: invalid --max-stack value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_max_stack(vm, l);
|
||||
- } else if (arg == "-J" || arg == "--jpath") {
|
||||
- std::string dir = next_arg(i, args);
|
||||
- if (dir.length() == 0) {
|
||||
- std::cerr << "ERROR: -J argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (dir[dir.length() - 1] != '/') {
|
||||
- dir += '/';
|
||||
- }
|
||||
- jsonnet_jpath_add(vm, dir.c_str());
|
||||
- } else if (arg == "-V" || arg == "--ext-str") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-E" || arg == "--var" || arg == "--env") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval -E, --var and --env are deprecated,"
|
||||
- << " please use -V or --ext-str." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-str-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-F" || arg == "--file") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval -F and --file are deprecated,"
|
||||
- << " please use --ext-str-file." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-code") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--code-var" || arg == "--code-env") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval --code-var and --code-env are deprecated,"
|
||||
- << " please use --ext-code." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-code-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--code-file") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval --code-file is deprecated,"
|
||||
- << " please use --ext-code-file." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-A" || arg == "--tla-str") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-str-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-code") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-code-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
-
|
||||
- } else if (arg == "--gc-min-objects") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 0) {
|
||||
- std::cerr << "ERROR: invalid --gc-min-objects value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_gc_min_objects(vm, l);
|
||||
- } else if (arg == "-t" || arg == "--max-trace") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 0) {
|
||||
- std::cerr << "ERROR: invalid --max-trace value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_max_trace(vm, l);
|
||||
- } else if (arg == "--gc-growth-trigger") {
|
||||
- std::string num = next_arg(i, args);
|
||||
- char *ep;
|
||||
- double v = std::strtod(num.c_str(), &ep);
|
||||
- if (*ep != '\0' || num.length() == 0) {
|
||||
- std::cerr << "ERROR: invalid number \"" << num << "\"" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (v < 0) {
|
||||
- std::cerr << "ERROR: invalid --gc-growth-trigger \"" << num << "\""
|
||||
- << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_gc_growth_trigger(vm, v);
|
||||
- } else if (arg == "-m" || arg == "--multi") {
|
||||
- config->evalMulti = true;
|
||||
- std::string output_dir = next_arg(i, args);
|
||||
- if (output_dir.length() == 0) {
|
||||
- std::cerr << "ERROR: -m argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (output_dir[output_dir.length() - 1] != '/') {
|
||||
- output_dir += '/';
|
||||
- }
|
||||
- config->evalMultiOutputDir = output_dir;
|
||||
- } else if (arg == "-y" || arg == "--yaml-stream") {
|
||||
- config->evalStream = true;
|
||||
- } else if (arg == "-S" || arg == "--string") {
|
||||
- jsonnet_string_output(vm, 1);
|
||||
- } else if (arg.length() > 1 && arg[0] == '-') {
|
||||
- std::cerr << "ERROR: unrecognized argument: " << arg << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- } else {
|
||||
- remaining_args.push_back(args[i]);
|
||||
+ {
|
||||
+ std::ifstream exists(filename.c_str());
|
||||
+ if (exists.good()) {
|
||||
+ std::string existing_content;
|
||||
+ existing_content.assign(std::istreambuf_iterator<char>(exists),
|
||||
+ std::istreambuf_iterator<char>());
|
||||
+ if (existing_content == new_content) {
|
||||
+ // Do not bump the timestamp on the file if its content is
|
||||
+ // the same. This may trigger other tools (e.g. make) to do
|
||||
+ // unnecessary work.
|
||||
+ continue;
|
||||
}
|
||||
+ }
|
||||
}
|
||||
-
|
||||
- const char *want = config->filenameIsCode ? "code" : "filename";
|
||||
- if (remaining_args.size() == 0) {
|
||||
- std::cerr << "ERROR: must give " << want << "\n" << std::endl;
|
||||
- usage(std::cerr);
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
-
|
||||
- if (remaining_args.size() > 1) {
|
||||
- std::string filename = remaining_args[0];
|
||||
- std::cerr << "ERROR: only one " << want << " is allowed\n" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- config->inputFiles = remaining_args;
|
||||
- return ARG_CONTINUE;
|
||||
-}
|
||||
-
|
||||
-/** Writes output files for multiple file output */
|
||||
-static bool write_multi_output_files(JsonnetVm *vm, char *output, const std::string &output_dir,
|
||||
- const std::string &output_file)
|
||||
-{
|
||||
- // If multiple file output is used, then iterate over each string from
|
||||
- // the sequence of strings returned by jsonnet_evaluate_snippet_multi,
|
||||
- // construct pairs of filename and content, and write each output file.
|
||||
- std::map<std::string, std::string> r;
|
||||
- for (const char *c = output; *c != '\0';) {
|
||||
- const char *filename = c;
|
||||
- const char *c2 = c;
|
||||
- while (*c2 != '\0')
|
||||
- ++c2;
|
||||
- ++c2;
|
||||
- const char *json = c2;
|
||||
- while (*c2 != '\0')
|
||||
- ++c2;
|
||||
- ++c2;
|
||||
- c = c2;
|
||||
- r[filename] = json;
|
||||
- }
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
-
|
||||
- std::ostream *o;
|
||||
std::ofstream f;
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- o = &std::cout;
|
||||
- } else {
|
||||
- f.open(output_file.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- o = &f;
|
||||
+ f.open(filename.c_str());
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Opening output file: " + filename;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
+ }
|
||||
+ f << new_content;
|
||||
+ f.close();
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + filename;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
}
|
||||
+ }
|
||||
|
||||
- for (const auto &pair : r) {
|
||||
- const std::string &new_content = pair.second;
|
||||
- const std::string &filename = output_dir + pair.first;
|
||||
- (*o) << filename << std::endl;
|
||||
- {
|
||||
- std::ifstream exists(filename.c_str());
|
||||
- if (exists.good()) {
|
||||
- std::string existing_content;
|
||||
- existing_content.assign(std::istreambuf_iterator<char>(exists),
|
||||
- std::istreambuf_iterator<char>());
|
||||
- if (existing_content == new_content) {
|
||||
- // Do not bump the timestamp on the file if its content is
|
||||
- // the same. This may trigger other tools (e.g. make) to do
|
||||
- // unnecessary work.
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- std::ofstream f;
|
||||
- f.open(filename.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Opening output file: " + filename;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- f << new_content;
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + filename;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
+ std::cout.flush();
|
||||
|
||||
- if (output_file.empty()) {
|
||||
- std::cout.flush();
|
||||
- } else {
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- return true;
|
||||
+ return true;
|
||||
}
|
||||
|
||||
/** Writes output files for YAML stream output */
|
||||
-static bool write_output_stream(JsonnetVm *vm, char *output, const std::string &output_file)
|
||||
-{
|
||||
- std::ostream *o;
|
||||
- std::ofstream f;
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- o = &std::cout;
|
||||
- } else {
|
||||
- f.open(output_file.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- o = &f;
|
||||
- }
|
||||
-
|
||||
- // If YAML stream output is used, then iterate over each string from
|
||||
- // the sequence of strings returned by jsonnet_evaluate_snippet_stream,
|
||||
- // and add the --- and ... as defined by the YAML spec.
|
||||
- std::vector<std::string> r;
|
||||
- for (const char *c = output; *c != '\0';) {
|
||||
- const char *json = c;
|
||||
- while (*c != '\0')
|
||||
- ++c;
|
||||
- ++c;
|
||||
- r.emplace_back(json);
|
||||
- }
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- for (const auto &str : r) {
|
||||
- (*o) << "---\n";
|
||||
- (*o) << str;
|
||||
- }
|
||||
- if (r.size() > 0)
|
||||
- (*o) << "...\n";
|
||||
- o->flush();
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- std::cout.flush();
|
||||
- } else {
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
+bool write_output_stream(char *output, const std::string &output_file) {
|
||||
+ std::ostream *o;
|
||||
+ std::ofstream f;
|
||||
+
|
||||
+ if (output_file.empty()) {
|
||||
+ o = &std::cout;
|
||||
+ } else {
|
||||
+ f.open(output_file.c_str());
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + output_file;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
+ }
|
||||
+ o = &f;
|
||||
+ }
|
||||
+
|
||||
+ // If YAML stream output is used, then iterate over each string from
|
||||
+ // the sequence of strings returned by jsonnet_evaluate_snippet_stream,
|
||||
+ // and add the --- and ... as defined by the YAML spec.
|
||||
+ std::vector<std::string> r;
|
||||
+ for (const char *c = output; *c != '\0';) {
|
||||
+ const char *json = c;
|
||||
+ while (*c != '\0') ++c;
|
||||
+ ++c;
|
||||
+ r.emplace_back(json);
|
||||
+ }
|
||||
+
|
||||
+ for (const auto &str : r) {
|
||||
+ (*o) << "---\n";
|
||||
+ (*o) << str;
|
||||
+ }
|
||||
+ if (r.size() > 0) (*o) << "...\n";
|
||||
+ o->flush();
|
||||
+
|
||||
+ if (output_file.empty()) {
|
||||
+ std::cout.flush();
|
||||
+ } else {
|
||||
+ f.close();
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + output_file;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
}
|
||||
+ }
|
||||
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-int main(int argc, const char **argv)
|
||||
-{
|
||||
- try {
|
||||
- JsonnetVm *vm = jsonnet_make();
|
||||
- JsonnetConfig config;
|
||||
- if (const char *jsonnet_path_env = getenv("JSONNET_PATH")) {
|
||||
- std::list<std::string> jpath;
|
||||
- std::istringstream iss(jsonnet_path_env);
|
||||
- std::string path;
|
||||
- while (std::getline(iss, path, PATH_SEP)) {
|
||||
- jpath.push_front(path);
|
||||
- }
|
||||
- for (const std::string &path : jpath) {
|
||||
- jsonnet_jpath_add(vm, path.c_str());
|
||||
- }
|
||||
- }
|
||||
- ArgStatus arg_status = process_args(argc, argv, &config, vm);
|
||||
- if (arg_status != ARG_CONTINUE) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return arg_status == ARG_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- // Evaluate input Jsonnet and handle any errors from Jsonnet VM.
|
||||
- int error;
|
||||
- char *output;
|
||||
- assert(config.inputFiles.size() == 1);
|
||||
-
|
||||
- // Read input file.
|
||||
- std::string input;
|
||||
- if (!read_input(config.filenameIsCode, &config.inputFiles[0], &input)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- if (config.evalMulti) {
|
||||
- output = jsonnet_evaluate_snippet_multi(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- } else if (config.evalStream) {
|
||||
- output = jsonnet_evaluate_snippet_stream(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- } else {
|
||||
- output = jsonnet_evaluate_snippet(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- }
|
||||
-
|
||||
- if (error) {
|
||||
- std::cerr << output;
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- // Write output JSON.
|
||||
- if (config.evalMulti) {
|
||||
- if (!write_multi_output_files(
|
||||
- vm, output, config.evalMultiOutputDir, config.outputFile)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- } else if (config.evalStream) {
|
||||
- if (!write_output_stream(vm, output, config.outputFile)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- } else {
|
||||
- bool successful = write_output_file(output, config.outputFile);
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- if (!successful) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_SUCCESS;
|
||||
-
|
||||
- } catch (const std::bad_alloc &) {
|
||||
- // Avoid further allocation attempts
|
||||
- fputs("Internal out-of-memory error (please report this)\n", stderr);
|
||||
- } catch (const std::exception &e) {
|
||||
- std::cerr << "Internal error (please report this): " << e.what() << std::endl;
|
||||
- } catch (...) {
|
||||
- std::cerr << "An unknown exception occurred (please report this)." << std::endl;
|
||||
- }
|
||||
- return EXIT_FAILURE;
|
||||
+ return true;
|
||||
}
|
76
oss-internship-2020/jsonnet/jsonnet_helper.cc
Normal file
76
oss-internship-2020/jsonnet/jsonnet_helper.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "jsonnet_helper.h" // NOLINT(build/include)
|
||||
|
||||
#include <cstring>
|
||||
|
||||
struct JsonnetVm* c_jsonnet_make(void) {
|
||||
return jsonnet_make();
|
||||
}
|
||||
|
||||
void c_jsonnet_destroy(struct JsonnetVm* vm) { return jsonnet_destroy(vm); }
|
||||
|
||||
char* c_jsonnet_evaluate_snippet(struct JsonnetVm* vm, const char* filename,
|
||||
char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_jsonnet_evaluate_snippet_multi(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet_multi(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_jsonnet_evaluate_snippet_stream(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet_stream(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_read_input(bool filename_is_code, const char* filename) {
|
||||
std::string s_filename(filename);
|
||||
std::string s_input;
|
||||
bool check = read_input(filename_is_code, &s_filename, &s_input);
|
||||
char* c_input = strdup(s_input.c_str());
|
||||
if (check) return c_input;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void c_free_input(char* input) { free(input); }
|
||||
|
||||
bool c_write_output_file(const char* output, const char* output_file) {
|
||||
std::string s_output_file(output_file);
|
||||
return write_output_file(output, s_output_file);
|
||||
}
|
||||
|
||||
bool c_write_multi_output_files(char* output, char* output_dir,
|
||||
bool show_output_file_names) {
|
||||
std::string s_output_dir(output_dir);
|
||||
return write_multi_output_files(output, s_output_dir, show_output_file_names);
|
||||
}
|
||||
|
||||
bool c_write_output_stream(char* output, char* output_file) {
|
||||
std::string s_output_file(output_file);
|
||||
return write_output_stream(output, s_output_file);
|
||||
}
|
||||
|
||||
char* c_jsonnet_realloc(struct JsonnetVm* vm, char* str, size_t sz) {
|
||||
return jsonnet_realloc(vm, str, sz);
|
||||
}
|
||||
|
||||
char* c_jsonnet_fmt_snippet(struct JsonnetVm* vm, const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_fmt_snippet(vm, filename, snippet, error);
|
||||
}
|
66
oss-internship-2020/jsonnet/jsonnet_helper.h
Normal file
66
oss-internship-2020/jsonnet/jsonnet_helper.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef JSONNET_HELPER_H_
|
||||
#define JSONNET_HELPER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <libjsonnet.h> // NOLINT(build/include)
|
||||
#include <libjsonnet_fmt.h> // NOLINT(build/include)
|
||||
}
|
||||
|
||||
#include "jsonnet/cmd/utils.h" // NOLINT(build/include)
|
||||
|
||||
extern "C" struct JsonnetVm* c_jsonnet_make(void);
|
||||
|
||||
extern "C" void c_jsonnet_destroy(struct JsonnetVm* vm);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet(struct JsonnetVm* vm,
|
||||
const char* filename, char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet_multi(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet_stream(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_read_input(bool filename_is_code, const char* filename);
|
||||
|
||||
extern "C" void c_free_input(char* input);
|
||||
|
||||
extern "C" bool c_write_output_file(const char* output,
|
||||
const char* output_file);
|
||||
|
||||
extern "C" char* c_jsonnet_realloc(struct JsonnetVm* vm, char* str, size_t sz);
|
||||
|
||||
extern "C" bool c_write_multi_output_files(char* output, char* output_dir,
|
||||
bool show_output_file_names);
|
||||
|
||||
bool write_multi_output_files(char* output, const std::string& output_dir,
|
||||
bool show_output_file_names);
|
||||
|
||||
extern "C" bool c_write_output_stream(char* output, char* output_file);
|
||||
|
||||
bool write_output_stream(char* output, const std::string& output_file);
|
||||
|
||||
extern "C" char* c_jsonnet_fmt_snippet(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error);
|
||||
|
||||
#endif // JSONNET_HELPER_H_
|
42
oss-internship-2020/jsonnet/tests/CMakeLists.txt
Normal file
42
oss-internship-2020/jsonnet/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http:#www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
# We need to prepare convenient directories so the tests will be able to access them
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_input)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_output)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_expected_output)
|
||||
|
||||
add_custom_target(test_preparation ALL
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/examples/jsonnet_codes/* ${PROJECT_BINARY_DIR}/tests/tests_input
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/examples/jsonnet_codes_expected_output/* ${PROJECT_BINARY_DIR}/tests/tests_expected_output
|
||||
)
|
||||
|
||||
add_executable(tests
|
||||
${PROJECT_SOURCE_DIR}/headers/jsonnet_tests.h
|
||||
jsonnet_tests.cc
|
||||
jsonnet_tests_utils.cc
|
||||
)
|
||||
|
||||
target_include_directories(tests PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/headers
|
||||
)
|
||||
|
||||
target_link_libraries(tests
|
||||
jsonnet_sapi sapi::sapi
|
||||
gtest gmock gtest_main
|
||||
)
|
||||
|
||||
gtest_discover_tests(tests)
|
113
oss-internship-2020/jsonnet/tests/jsonnet_tests.cc
Normal file
113
oss-internship-2020/jsonnet/tests/jsonnet_tests.cc
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "jsonnet_tests.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
class JsonnetTest : public JsonnetTestHelper, public testing::Test {
|
||||
protected:
|
||||
void SetUp() override { TestSetUp(); }
|
||||
void TearDown() override { TestTearDown(); }
|
||||
};
|
||||
|
||||
// Basic test
|
||||
TEST_F(JsonnetTest, SetUp_TearDown) {
|
||||
ASSERT_FALSE(jsonnet_vm_was_used_);
|
||||
ASSERT_FALSE(input_was_read_);
|
||||
}
|
||||
|
||||
// One file evaluation to one file
|
||||
TEST_F(JsonnetTest, One_file_no_dependencies) {
|
||||
constexpr char kInputFile[] = "arith.jsonnet";
|
||||
constexpr char kOutputFile[] = "arith_output";
|
||||
constexpr char kOutputToRead[] = "tests_output/arith_output";
|
||||
constexpr char kOutputToExpect[] = "tests_expected_output/arith.golden";
|
||||
|
||||
Read_input(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, true);
|
||||
WriteOutput(kOutputFile, kBase);
|
||||
|
||||
std::string produced_output = ReadOutput(kOutputToRead);
|
||||
std::string expected_output = ReadOutput(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to one file, dependent on some other files
|
||||
TEST_F(JsonnetTest, One_file_some_dependencies) {
|
||||
constexpr char kInputFile[] = "negroni.jsonnet";
|
||||
constexpr char kOutputFile[] = "negroni_output";
|
||||
constexpr char kOutputToRead[] = "tests_output/negroni_output";
|
||||
constexpr char kOutputToExpect[] = "tests_expected_output/negroni.golden";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, true);
|
||||
WriteOutput(kOutputFile, kBase);
|
||||
|
||||
const std::string produced_output = Read_output(kOutputToRead);
|
||||
const std::string expected_output = Read_output(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to two files
|
||||
TEST_F(JsonnetTest, Multiple_files) {
|
||||
constexpr char kInputFile[] = "multiple_files_example.jsonnet";
|
||||
constexpr char kOutputFile[] = "";
|
||||
constexpr char kOutputToRead1[] = "tests_output/first_file.json";
|
||||
constexpr char kOutputToRead2[] = "tests_output/second_file.json";
|
||||
constexpr char kOutputToExpect1[] = "tests_expected_output/first_file.json";
|
||||
constexpr char kOutputToExpect2[] = "tests_expected_output/second_file.json";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kMultipleFiles, true);
|
||||
WriteOutput(kOutputFile, kMultipleFiles);
|
||||
|
||||
const std::string produced_output_1 = ReadOutput(kOutputToRead1);
|
||||
const std::string produced_output_2 = ReadOutput(kOutputToRead2);
|
||||
const std::string expected_output_1 = ReadOutput(kOutputToExpect1);
|
||||
const std::string expected_output_2 = ReadOutput(kOutputToExpect2);
|
||||
|
||||
ASSERT_STREQ(produced_output_1.c_str(), expected_output_1.c_str());
|
||||
ASSERT_STREQ(produced_output_2.c_str(), expected_output_2.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to yaml stream format
|
||||
TEST_F(JsonnetTest, Yaml_stream) {
|
||||
constexpr char kInputFile[] = "yaml_stream_example.jsonnet";
|
||||
constexpr char kOutputFile[] = "yaml_stream_example.yaml";
|
||||
constexpr char kOutputToRead[] = "tests_output/yaml_stream_example.yaml";
|
||||
constexpr char kOutputToExpect[] =
|
||||
"tests_expected_output/yaml_stream_example.yaml";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kYamlStream, true);
|
||||
WriteOutput(kOutputFile, kYamlStream);
|
||||
|
||||
const std::string produced_output = ReadOutput(kOutputToRead);
|
||||
const std::string expected_output = ReadOutput(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file depended on some other files not accessible by the sandbox
|
||||
TEST_F(JsonnetTest, Bad_evaluation) {
|
||||
constexpr char kInputFile[] = "imports.jsonnet";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, false);
|
||||
}
|
||||
|
||||
} // namespace
|
160
oss-internship-2020/jsonnet/tests/jsonnet_tests_utils.cc
Normal file
160
oss-internship-2020/jsonnet/tests/jsonnet_tests_utils.cc
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "jsonnet_tests.h" // NOLINT(build/include)
|
||||
|
||||
// Prepares what is needed to perform a test.
|
||||
void JsonnetTestHelper::TestSetUp() {
|
||||
// Get paths to where input and output is stored.
|
||||
char buffer[256];
|
||||
int error = readlink("/proc/self/exe", buffer, 256);
|
||||
ASSERT_GE(error, 0);
|
||||
|
||||
std::pair<absl::string_view, absl::string_view> parts_of_path =
|
||||
sandbox2::file::SplitPath(buffer);
|
||||
absl::string_view binary_path = parts_of_path.first;
|
||||
|
||||
std::string input_path =
|
||||
sandbox2::file::JoinPath(binary_path, "tests_input", "dummy_input");
|
||||
std::string output_path =
|
||||
sandbox2::file::JoinPath(binary_path, "tests_output", "dummy_input");
|
||||
|
||||
// Set up sandbox and api.
|
||||
sandbox_ = absl::make_unique<JsonnetBaseSandbox>(input_path, output_path);
|
||||
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||
api_ = absl::make_unique<JsonnetApi>(sandbox_.get());
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(JsonnetVm * vm_ptr, api_->c_jsonnet_make());
|
||||
vm_ = absl::make_unique<sapi::v::RemotePtr>(vm_ptr);
|
||||
|
||||
jsonnet_vm_was_used_ = false;
|
||||
input_was_read_ = false;
|
||||
}
|
||||
|
||||
// Cleans up after a test.
|
||||
void JsonnetTestHelper::TestTearDown() {
|
||||
if (jsonnet_vm_was_used_) {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(char* result,
|
||||
api_->c_jsonnet_realloc(vm_.get(), output_.get(), 0));
|
||||
}
|
||||
ASSERT_THAT(api_->c_jsonnet_destroy(vm_.get()), sapi::IsOk());
|
||||
if (input_was_read_) {
|
||||
ASSERT_THAT(api_->c_free_input(input_.get()), sapi::IsOk());
|
||||
}
|
||||
}
|
||||
|
||||
// Reads input from file.
|
||||
void JsonnetTestHelper::ReadInput(const char* filename) {
|
||||
std::string in_file_in_sandboxee(std::string("/input/") +
|
||||
basename(const_cast<char*>(&filename[0])));
|
||||
input_filename_in_sandboxee_ = std::move(in_file_in_sandboxee);
|
||||
sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(char* input_ptr,
|
||||
api_->c_read_input(0, in_file_var.PtrBefore()));
|
||||
input_ = absl::make_unique<sapi::v::RemotePtr>(input_ptr);
|
||||
|
||||
input_was_read_ = true;
|
||||
}
|
||||
|
||||
// Evaluates jsonnet code.
|
||||
void JsonnetTestHelper::Evaluate_jsonnet_code(Evaluation type,
|
||||
bool expected_correct) {
|
||||
sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
|
||||
sapi::v::Int error;
|
||||
char* output_ptr;
|
||||
|
||||
switch (type) {
|
||||
case kBase: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
|
||||
case kMultipleFiles: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet_multi(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
|
||||
case kYamlStream: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet_stream(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (expected_correct) {
|
||||
ASSERT_THAT(error.GetValue(), testing::Eq(0));
|
||||
} else {
|
||||
ASSERT_THAT(error.GetValue(), testing::Eq(1));
|
||||
}
|
||||
|
||||
output_ = absl::make_unique<sapi::v::RemotePtr>(output_ptr);
|
||||
|
||||
jsonnet_vm_was_used_ = true;
|
||||
}
|
||||
|
||||
// Writes output to file.
|
||||
void JsonnetTestHelper::WriteOutput(const char* filename_or_directory,
|
||||
Evaluation type) {
|
||||
bool success;
|
||||
|
||||
switch (type) {
|
||||
case kBase: {
|
||||
std::string out_file_in_sandboxee(
|
||||
std::string("/output/") +
|
||||
basename(const_cast<char*>(&filename_or_directory[0])));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
success,
|
||||
api_->c_write_output_file(output_.get(), out_file_var.PtrBefore()));
|
||||
break;
|
||||
}
|
||||
case kMultipleFiles: {
|
||||
std::string out_file_in_sandboxee(std::string("/output/"));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(success,
|
||||
api_->c_write_multi_output_files(
|
||||
output_.get(), out_file_var.PtrBefore(), false));
|
||||
break;
|
||||
}
|
||||
|
||||
case kYamlStream: {
|
||||
std::string out_file_in_sandboxee(
|
||||
std::string("/output/") +
|
||||
basename(const_cast<char*>(&filename_or_directory[0])));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
success,
|
||||
api_->c_write_output_stream(output_.get(), out_file_var.PtrBefore()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_THAT(success, testing::Eq(true));
|
||||
}
|
||||
|
||||
// Reads the output written to a file by library function / expected output
|
||||
std::string JsonnetTestHelper::ReadOutput(const char* filename) {
|
||||
std::ifstream input_stream(filename);
|
||||
std::string contents((std::istreambuf_iterator<char>(input_stream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
return contents;
|
||||
}
|
3
oss-internship-2020/lodepng/.gitignore
vendored
Normal file
3
oss-internship-2020/lodepng/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
.clang-format
|
||||
.cache
|
80
oss-internship-2020/lodepng/CMakeLists.txt
Normal file
80
oss-internship-2020/lodepng/CMakeLists.txt
Normal file
|
@ -0,0 +1,80 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(lodepng_sapi CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 17)
|
||||
|
||||
# Apply the patches to the header file.
|
||||
add_custom_command(
|
||||
OUTPUT "${PROJECT_BINARY_DIR}/lodepng/lodepng.h" "${PROJECT_BINARY_DIR}/lodepng/lodepng.cpp"
|
||||
COMMENT "Applying patch to header file."
|
||||
COMMAND cp -r "${PROJECT_SOURCE_DIR}/lodepng" "${PROJECT_BINARY_DIR}/"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/patches/header.patch" "${PROJECT_BINARY_DIR}/lodepng/"
|
||||
COMMAND cd "${PROJECT_BINARY_DIR}/lodepng" && patch < header.patch
|
||||
)
|
||||
|
||||
# Build static library.
|
||||
add_library(lodepng STATIC
|
||||
"${PROJECT_BINARY_DIR}/lodepng/lodepng.cpp"
|
||||
"${PROJECT_BINARY_DIR}/lodepng/lodepng.h"
|
||||
)
|
||||
|
||||
target_include_directories(lodepng PUBLIC "${PROJECT_BINARY_DIR}/lodepng")
|
||||
|
||||
# Build SAPI library
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
add_sapi_library(
|
||||
lodepng_sapi
|
||||
|
||||
FUNCTIONS
|
||||
lodepng_decode_memory
|
||||
lodepng_decode32
|
||||
lodepng_decode24
|
||||
|
||||
lodepng_decode_file
|
||||
lodepng_decode32_file
|
||||
lodepng_decode24_file
|
||||
|
||||
lodepng_encode_memory
|
||||
lodepng_encode32
|
||||
lodepng_encode24
|
||||
|
||||
lodepng_encode_file
|
||||
lodepng_encode32_file
|
||||
lodepng_encode24_file
|
||||
|
||||
lodepng_save_file
|
||||
lodepng_load_file
|
||||
|
||||
INPUTS "${PROJECT_BINARY_DIR}/lodepng/lodepng.h"
|
||||
LIBRARY lodepng
|
||||
LIBRARY_NAME Lodepng
|
||||
NAMESPACE ""
|
||||
)
|
||||
|
||||
target_include_directories(lodepng_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
|
||||
)
|
||||
|
||||
add_subdirectory(examples)
|
42
oss-internship-2020/lodepng/README.md
Normal file
42
oss-internship-2020/lodepng/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# LodePNG Sandboxed API
|
||||
|
||||
Sandboxed version of the [LodePNG](https://github.com/lvandeve/lodepng) library, using [Sandboxed API](https://github.com/google/sandboxed-api)
|
||||
|
||||
## Details
|
||||
|
||||
With Sandboxed API, many of the library's functions can be sandboxed. However, they need the `extern "C"` keyword defined so that name mangling does not happen, which is why a patch that adds it is used. The only differences are found in the header file. An alternative to this is to define another library that wraps every needed function, specifying the required keyword.
|
||||
|
||||
Even if many of the functions from the library can be sandboxed, there are some that are not supported (those which have `std::vector` parameters, overloaded functions etc.). If you really need these functions, a solution is to implement a custom library that wraps around these functions in order to make them compatible.
|
||||
|
||||
## Patches
|
||||
|
||||
In the **patches** folder there is a patch file that adds `extern "C"` to the required functions in the header file in order to sandbox them. This patch is applied automatically during the build phase.
|
||||
|
||||
## Build
|
||||
|
||||
First, run `git submodule update --init --recursive` to update submodules.
|
||||
After this, run the following commands:
|
||||
|
||||
`mkdir -p build && cd build`
|
||||
|
||||
`cmake .. -G Ninja`
|
||||
|
||||
`cmake --build .`
|
||||
|
||||
|
||||
The example binary files can be found in `build/examples`.
|
||||
|
||||
## Examples
|
||||
|
||||
The code found in the **examples** folder features a basic use case of the library. An image is generated, encoded into a file and then decoded to check that the values are the same. The encoding part was based on [this example](https://github.com/lvandeve/lodepng/blob/master/examples/example_encode.c) while decoding was based on [this](https://github.com/lvandeve/lodepng/blob/master/examples/example_decode.c).
|
||||
|
||||
This example code is structured as:
|
||||
- `main_unsandboxed.cc` - unsandboxed example
|
||||
- `main_sandboxed.cc` - sandboxed version of the example
|
||||
- `main_unit_test.cc` - tests(using [Google Test](https://github.com/google/googletest)).
|
||||
|
||||
On top of those files, there are other files used by all three of the examples:
|
||||
- `sandbox.h` - custom sandbox policy
|
||||
- `helpers.h` and `helpers.cc` - constants and functions used in the main files.
|
||||
|
||||
The executables generated from these files will create a temporary directory in the current working path. Inside that directory the two generated **png** files will be created. At the end, the directory is deleted. If those programs do not stop midway or return a failure code, then everything works fine.
|
70
oss-internship-2020/lodepng/examples/CMakeLists.txt
Normal file
70
oss-internship-2020/lodepng/examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Build the unsandboxed main
|
||||
add_executable(lodepng_unsandboxed
|
||||
main_unsandboxed.cc
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(lodepng_unsandboxed PRIVATE
|
||||
lodepng
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::file_base
|
||||
sandbox2::fileops
|
||||
glog::glog
|
||||
)
|
||||
|
||||
# Build the sandboxed main
|
||||
add_executable(lodepng_sandboxed
|
||||
main_sandboxed.cc
|
||||
sandbox.h
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(lodepng_sandboxed PRIVATE
|
||||
lodepng_sapi
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
sapi::vars
|
||||
sapi::status
|
||||
glog::glog
|
||||
)
|
||||
|
||||
# Build the unit tests
|
||||
include(GoogleTest)
|
||||
enable_testing()
|
||||
|
||||
add_executable(main_unit_test
|
||||
main_unit_test.cc
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(main_unit_test PRIVATE
|
||||
lodepng_sapi
|
||||
absl::memory
|
||||
absl::strings
|
||||
absl::time
|
||||
glog::glog
|
||||
sapi::flags
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
sapi::status
|
||||
sapi::test_main
|
||||
sapi::vars
|
||||
)
|
||||
gtest_discover_tests(main_unit_test)
|
43
oss-internship-2020/lodepng/examples/helpers.cc
Normal file
43
oss-internship-2020/lodepng/examples/helpers.cc
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
std::vector<uint8_t> GenerateValues() {
|
||||
std::vector<uint8_t> image;
|
||||
image.reserve(kImgLen);
|
||||
|
||||
for (int y = 0; y < kHeight; ++y) {
|
||||
for (int x = 0; x < kWidth; ++x) {
|
||||
image.push_back(255 * !(x & y));
|
||||
image.push_back(x ^ y);
|
||||
image.push_back(x | y);
|
||||
image.push_back(255);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
std::string CreateTempDirAtCWD() {
|
||||
std::string cwd = sandbox2::file_util::fileops::GetCWD();
|
||||
CHECK(!cwd.empty()) << "Could not get current working directory";
|
||||
cwd.append("/");
|
||||
|
||||
absl::StatusOr<std::string> result = sandbox2::CreateTempDir(cwd);
|
||||
CHECK(result.ok()) << "Could not create temporary directory";
|
||||
return result.value();
|
||||
}
|
39
oss-internship-2020/lodepng/examples/helpers.h
Normal file
39
oss-internship-2020/lodepng/examples/helpers.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LODEPNG_EXAMPLES_HELPERS_H_
|
||||
#define LODEPNG_EXAMPLES_HELPERS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
inline constexpr size_t kWidth = 512;
|
||||
inline constexpr size_t kHeight = 512;
|
||||
inline constexpr size_t kImgLen = kWidth * kHeight * 4;
|
||||
|
||||
// Returns a vector that contains values used for testing.
|
||||
// This part of code is taken from
|
||||
// https://github.com/lvandeve/lodepng/blob/master/examples/example_encode.c#L96-L104.
|
||||
// The generated image contains square fractals.
|
||||
std::vector<uint8_t> GenerateValues();
|
||||
|
||||
// Creates a temporary directory in the current working directory and returns
|
||||
// the path.
|
||||
std::string CreateTempDirAtCWD();
|
||||
|
||||
#endif // LODEPNG_EXAMPLES_HELPERS_H_
|
193
oss-internship-2020/lodepng/examples/main_sandboxed.cc
Normal file
193
oss-internship-2020/lodepng/examples/main_sandboxed.cc
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
|
||||
void EncodeDecodeOneStep(SapiLodepngSandbox& sandbox, LodepngApi& api) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image.
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
CHECK(std::copy(image.begin(), image.end(), sapi_image.GetData()))
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated1.png");
|
||||
|
||||
absl::StatusOr<unsigned int> result = api.lodepng_encode32_file(
|
||||
sapi_filename.PtrBefore(), sapi_image.PtrBefore(), kWidth, kHeight);
|
||||
|
||||
CHECK(result.ok()) << "encode32_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from encode32_file call";
|
||||
|
||||
// After the image has been encoded, decode it to check that the
|
||||
// pixel values are the same.
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_image_ptr(0);
|
||||
|
||||
result = api.lodepng_decode32_file(
|
||||
sapi_image_ptr.PtrBoth(), sapi_width.PtrBoth(), sapi_height.PtrBoth(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "decode32_file call failes";
|
||||
CHECK(!result.value()) << "Unexpected result from decode32_file call";
|
||||
|
||||
CHECK(sapi_width.GetValue() == kWidth) << "Widths differ";
|
||||
CHECK(sapi_height.GetValue() == kHeight) << "Heights differ";
|
||||
|
||||
// The pixels have been allocated inside the sandboxed process
|
||||
// memory, so we need to transfer them to this process.
|
||||
// Transferring the memory has the following steps:
|
||||
// 1) define an array with the required length.
|
||||
// 2) set the remote pointer for the array to specify where the memory
|
||||
// that will be transferred is located.
|
||||
// 3) transfer the memory to this process (this step is why we need
|
||||
// the pointer and the length).
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_image_ptr.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_pixels).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Now, we can compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
// Free the memory allocated inside the sandbox.
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_image_ptr.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
}
|
||||
|
||||
void EncodeDecodeTwoSteps(SapiLodepngSandbox& sandbox, LodepngApi& api) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image into memory first.
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
CHECK(std::copy(image.begin(), image.end(), sapi_image.GetData()))
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated2.png");
|
||||
|
||||
sapi::v::ULLong sapi_pngsize;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr(0);
|
||||
|
||||
// Encode it into memory.
|
||||
absl::StatusOr<unsigned int> result =
|
||||
api.lodepng_encode32(sapi_png_ptr.PtrBoth(), sapi_pngsize.PtrBoth(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight);
|
||||
|
||||
CHECK(result.ok()) << "encode32 call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from encode32 call";
|
||||
|
||||
// The new array (pointed to by sapi_png_ptr) is allocated
|
||||
// inside the sandboxed process so we need to transfer it to this
|
||||
// process.
|
||||
sapi::v::Array<uint8_t> sapi_png_array(sapi_pngsize.GetValue());
|
||||
sapi_png_array.SetRemote(sapi_png_ptr.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_png_array).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Write the image into the file (from memory).
|
||||
result =
|
||||
api.lodepng_save_file(sapi_png_array.PtrBefore(), sapi_pngsize.GetValue(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "save_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from save_file call";
|
||||
|
||||
// Now, decode the image using the 2 steps in order to compare the values.
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr2(0);
|
||||
sapi::v::ULLong sapi_pngsize2;
|
||||
|
||||
// Load the file in memory.
|
||||
result =
|
||||
api.lodepng_load_file(sapi_png_ptr2.PtrBoth(), sapi_pngsize2.PtrBoth(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "load_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from load_file call";
|
||||
|
||||
CHECK(sapi_pngsize.GetValue() == sapi_pngsize2.GetValue())
|
||||
<< "Png sizes differ";
|
||||
|
||||
// Transfer the png array.
|
||||
sapi::v::Array<uint8_t> sapi_png_array2(sapi_pngsize2.GetValue());
|
||||
sapi_png_array2.SetRemote(sapi_png_ptr2.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_png_array2).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// After the file is loaded, decode it so we have access to the values
|
||||
// directly.
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr3(0);
|
||||
result = api.lodepng_decode32(
|
||||
sapi_png_ptr3.PtrBoth(), sapi_width.PtrBoth(), sapi_height.PtrBoth(),
|
||||
sapi_png_array2.PtrBefore(), sapi_pngsize2.GetValue());
|
||||
|
||||
CHECK(result.ok()) << "decode32 call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from decode32 call";
|
||||
|
||||
CHECK(sapi_width.GetValue() == kWidth) << "Widths differ";
|
||||
CHECK(sapi_height.GetValue() == kHeight) << "Heights differ";
|
||||
|
||||
// Transfer the pixels so they can be used here.
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_png_ptr3.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_pixels).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
// Free the memory allocated inside the sandbox.
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr2.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr3.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
CHECK(sandbox2::file_util::fileops::Exists(images_path, false))
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
||||
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
EncodeDecodeOneStep(sandbox, api);
|
||||
EncodeDecodeTwoSteps(sandbox, api);
|
||||
|
||||
if (sandbox2::file_util::fileops::DeleteRecursively(images_path)) {
|
||||
LOG(WARNING) << "Temporary folder could not be deleted";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
213
oss-internship-2020/lodepng/examples/main_unit_test.cc
Normal file
213
oss-internship-2020/lodepng/examples/main_unit_test.cc
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
using ::sapi::IsOk;
|
||||
using ::testing::Eq;
|
||||
using ::testing::IsTrue;
|
||||
using ::testing::NotNull;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(HelpersTest, CreateTempDirAtCWD) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
TEST(HelpersTest, GenerateValues) {
|
||||
EXPECT_THAT(GenerateValues().size(), Eq(kImgLen));
|
||||
}
|
||||
|
||||
TEST(LodePngTest, Init) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox init";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
// Generate an image, encode it, decode it and compare the pixels with the
|
||||
// initial values.
|
||||
TEST(LodePngTest, EncodeDecodeOneStep) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox initialization";
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
EXPECT_THAT(std::copy(image.begin(), image.end(), sapi_image.GetData()),
|
||||
IsTrue())
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated1.png");
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
unsigned int result,
|
||||
api.lodepng_encode32_file(sapi_filename.PtrBefore(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from encode32_file call";
|
||||
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_image_ptr(0);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(result,
|
||||
api.lodepng_decode32_file(
|
||||
sapi_image_ptr.PtrBoth(), sapi_width.PtrBoth(),
|
||||
sapi_height.PtrBoth(), sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from decode32_file call";
|
||||
|
||||
EXPECT_THAT(sapi_width.GetValue(), Eq(kWidth)) << "Widths differ";
|
||||
EXPECT_THAT(sapi_height.GetValue(), Eq(kHeight)) << "Heights differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_image_ptr.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_pixels), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
EXPECT_THAT(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen),
|
||||
IsTrue())
|
||||
<< "Values differ";
|
||||
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_image_ptr.GetValue()), IsOk())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
// Similar to the previous test, only that we use encoding by saving the data in
|
||||
// memory and then writing it to the file and decoding by first decoding in
|
||||
// memory and then getting the actual pixel values.
|
||||
TEST(LodePngTest, EncodeDecodeTwoSteps) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox init";
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
EXPECT_THAT(std::copy(image.begin(), image.end(), sapi_image.GetData()),
|
||||
IsTrue())
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated2.png");
|
||||
|
||||
sapi::v::ULLong sapi_pngsize;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr(0);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
unsigned int result,
|
||||
api.lodepng_encode32(sapi_png_ptr.PtrBoth(), sapi_pngsize.PtrBoth(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from encode32 call";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_png_array(sapi_pngsize.GetValue());
|
||||
sapi_png_array.SetRemote(sapi_png_ptr.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_png_array), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_save_file(sapi_png_array.PtrBefore(), sapi_pngsize.GetValue(),
|
||||
sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from save_file call";
|
||||
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr2(0);
|
||||
sapi::v::ULLong sapi_pngsize2;
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_load_file(sapi_png_ptr2.PtrBoth(), sapi_pngsize2.PtrBoth(),
|
||||
sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from load_file call";
|
||||
|
||||
EXPECT_THAT(sapi_pngsize.GetValue(), Eq(sapi_pngsize2.GetValue()))
|
||||
<< "Png sizes differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_png_array2(sapi_pngsize2.GetValue());
|
||||
sapi_png_array2.SetRemote(sapi_png_ptr2.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_png_array2), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr3(0);
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_decode32(sapi_png_ptr3.PtrBoth(), sapi_width.PtrBoth(),
|
||||
sapi_height.PtrBoth(), sapi_png_array2.PtrBefore(),
|
||||
sapi_pngsize2.GetValue()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from decode32 call";
|
||||
|
||||
EXPECT_THAT(sapi_width.GetValue(), Eq(kWidth)) << "Widths differ";
|
||||
EXPECT_THAT(sapi_height.GetValue(), Eq(kHeight)) << "Heights differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_png_ptr3.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_pixels), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
EXPECT_THAT(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen),
|
||||
IsTrue())
|
||||
<< "Values differ";
|
||||
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr.GetValue()), IsOk());
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr2.GetValue()), IsOk());
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr3.GetValue()), IsOk());
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
} // namespace
|
116
oss-internship-2020/lodepng/examples/main_unsandboxed.cc
Normal file
116
oss-internship-2020/lodepng/examples/main_unsandboxed.cc
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
#include "lodepng.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
void EncodeDecodeOneStep(const std::string& images_path) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image.
|
||||
const std::string filename =
|
||||
sandbox2::file::JoinPath(images_path, "/out_generated1.png");
|
||||
unsigned int result =
|
||||
lodepng_encode32_file(filename.c_str(), image.data(), kWidth, kHeight);
|
||||
|
||||
CHECK(!result) << "Unexpected result from encode32_file call";
|
||||
|
||||
// After the image has been encoded, decode it to check that the
|
||||
// pixel values are the same.
|
||||
unsigned int width, height;
|
||||
uint8_t* image2 = 0;
|
||||
|
||||
result = lodepng_decode32_file(&image2, &width, &height, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from decode32_file call";
|
||||
|
||||
CHECK(width == kWidth) << "Widths differ";
|
||||
CHECK(height == kHeight) << "Heights differ";
|
||||
|
||||
// Now, we can compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), image2, image2 + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
free(image2);
|
||||
}
|
||||
|
||||
void EncodeDecodeTwoSteps(const std::string& images_path) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image into memory first.
|
||||
const std::string filename =
|
||||
sandbox2::file::JoinPath(images_path, "/out_generated2.png");
|
||||
uint8_t* png;
|
||||
size_t pngsize;
|
||||
|
||||
unsigned int result =
|
||||
lodepng_encode32(&png, &pngsize, image.data(), kWidth, kHeight);
|
||||
|
||||
CHECK(!result) << "Unexpected result from encode32 call";
|
||||
|
||||
// Write the image into the file (from memory).
|
||||
result = lodepng_save_file(png, pngsize, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from save_file call";
|
||||
|
||||
// Now, decode the image using the 2 steps in order to compare the values.
|
||||
unsigned int width, height;
|
||||
uint8_t* png2;
|
||||
size_t pngsize2;
|
||||
|
||||
// Load the file in memory.
|
||||
result = lodepng_load_file(&png2, &pngsize2, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from load_file call";
|
||||
CHECK(pngsize == pngsize2) << "Png sizes differ";
|
||||
|
||||
uint8_t* image2;
|
||||
result = lodepng_decode32(&image2, &width, &height, png2, pngsize2);
|
||||
|
||||
CHECK(!result) << "Unexpected result from decode32 call";
|
||||
CHECK(width == kWidth) << "Widths differ";
|
||||
CHECK(height == kHeight) << "Heights differ";
|
||||
|
||||
// Compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), image2, image2 + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
free(png);
|
||||
free(png2);
|
||||
free(image2);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
CHECK(sandbox2::file_util::fileops::Exists(images_path, false))
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
EncodeDecodeOneStep(images_path);
|
||||
EncodeDecodeTwoSteps(images_path);
|
||||
|
||||
if (sandbox2::file_util::fileops::DeleteRecursively(images_path)) {
|
||||
LOG(WARNING) << "Temporary folder could not be deleted";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
49
oss-internship-2020/lodepng/examples/sandbox.h
Normal file
49
oss-internship-2020/lodepng/examples/sandbox.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LODEPNG_EXAMPLES_SANDBOX_H_
|
||||
#define LODEPNG_EXAMPLES_SANDBOX_H_
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include "lodepng_sapi.sapi.h" // NOLINT(build/include)
|
||||
|
||||
class SapiLodepngSandbox : public LodepngSandbox {
|
||||
public:
|
||||
explicit SapiLodepngSandbox(const std::string& images_path)
|
||||
: images_path_(images_path) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowOpen()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowStat()
|
||||
.AddDirectoryAt(images_path_, "/output/", /*is_ro=*/false)
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_lseek,
|
||||
__NR_close,
|
||||
})
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
const std::string images_path_;
|
||||
};
|
||||
|
||||
#endif // LODEPNG_EXAMPLES_SANDBOX__
|
86
oss-internship-2020/lodepng/patches/header.patch
Normal file
86
oss-internship-2020/lodepng/patches/header.patch
Normal file
|
@ -0,0 +1,86 @@
|
|||
--- lodepng.h 2020-09-11 08:41:22.280259945 +0000
|
||||
+++ lodepng2.h 2020-09-11 08:45:17.134266042 +0000
|
||||
@@ -89,6 +89,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -126,6 +128,9 @@
|
||||
bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types.
|
||||
Return value: LodePNG error code (0 means no error).
|
||||
*/
|
||||
+
|
||||
+extern "C" {
|
||||
+
|
||||
unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const unsigned char* in, size_t insize,
|
||||
LodePNGColorType colortype, unsigned bitdepth);
|
||||
@@ -154,10 +159,12 @@
|
||||
/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/
|
||||
unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const char* filename);
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
||||
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_ENCODER
|
||||
/*
|
||||
Converts raw pixel data into a PNG image in memory. The colortype and bitdepth
|
||||
@@ -204,6 +211,9 @@
|
||||
/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/
|
||||
unsigned lodepng_encode24_file(const char* filename,
|
||||
const unsigned char* image, unsigned w, unsigned h);
|
||||
+
|
||||
+}
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
#endif /*LODEPNG_COMPILE_ENCODER*/
|
||||
|
||||
@@ -219,6 +229,8 @@
|
||||
unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
||||
const std::vector<unsigned char>& in,
|
||||
LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
|
||||
+
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_DISK
|
||||
/*
|
||||
Converts PNG file from disk to raw pixel data in memory.
|
||||
@@ -251,6 +263,7 @@
|
||||
unsigned encode(const std::string& filename,
|
||||
const std::vector<unsigned char>& in, unsigned w, unsigned h,
|
||||
LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
|
||||
+
|
||||
#endif /* LODEPNG_COMPILE_DISK */
|
||||
#endif /* LODEPNG_COMPILE_ENCODER */
|
||||
} /* namespace lodepng */
|
||||
@@ -318,6 +331,7 @@
|
||||
|
||||
extern const LodePNGCompressSettings lodepng_default_compress_settings;
|
||||
void lodepng_compress_settings_init(LodePNGCompressSettings* settings);
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_ENCODER*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_PNG
|
||||
@@ -943,6 +957,8 @@
|
||||
#endif /*LODEPNG_COMPILE_ZLIB*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_DISK
|
||||
+
|
||||
+extern "C" {
|
||||
/*
|
||||
Load a file from disk into buffer. The function allocates the out buffer, and
|
||||
after usage you should free it.
|
||||
@@ -962,6 +978,7 @@
|
||||
return value: error code (0 means ok)
|
||||
*/
|
||||
unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);
|
||||
+}
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
|
@ -73,12 +73,12 @@ int main(int argc, char* argv[]) {
|
|||
sapi::v::ConstCStr in_file_v(in_file.c_str());
|
||||
|
||||
// Initialize library's main data-holders.
|
||||
sapi::StatusOr<opj_stream_t*> stream =
|
||||
absl::StatusOr<opj_stream_t*> stream =
|
||||
api.opj_stream_create_default_file_stream(in_file_v.PtrBefore(), 1);
|
||||
CHECK(stream.ok()) << "Stream initialization failed: " << stream.status();
|
||||
sapi::v::RemotePtr stream_pointer(stream.value());
|
||||
|
||||
sapi::StatusOr<opj_codec_t*> codec = api.opj_create_decompress(OPJ_CODEC_JP2);
|
||||
absl::StatusOr<opj_codec_t*> codec = api.opj_create_decompress(OPJ_CODEC_JP2);
|
||||
CHECK(codec.ok()) << "Codec initialization failed: " << stream.status();
|
||||
sapi::v::RemotePtr codec_pointer(codec.value());
|
||||
|
||||
|
@ -86,7 +86,7 @@ int main(int argc, char* argv[]) {
|
|||
status = api.opj_set_default_decoder_parameters(parameters.PtrBoth());
|
||||
CHECK(status.ok()) << "Parameters initialization failed " << status;
|
||||
|
||||
sapi::StatusOr<OPJ_BOOL> bool_status =
|
||||
absl::StatusOr<OPJ_BOOL> bool_status =
|
||||
api.opj_setup_decoder(&codec_pointer, parameters.PtrBefore());
|
||||
CHECK(bool_status.ok() && bool_status.value()) << "Decoder setup failed";
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ sapi_library(
|
|||
cc_binary(
|
||||
name = "hello",
|
||||
srcs = ["hello_main.cc"],
|
||||
includes = ["."], # To find the generated header
|
||||
deps = [":hello_sapi"],
|
||||
)
|
||||
|
||||
|
@ -50,7 +49,6 @@ cc_binary(
|
|||
cc_binary(
|
||||
name = "hello_transacted",
|
||||
srcs = ["hello_transacted.cc"],
|
||||
includes = ["."], # To find the generated header
|
||||
deps = [
|
||||
":hello_sapi",
|
||||
"@com_google_absl//absl/memory",
|
||||
|
|
|
@ -201,7 +201,7 @@ absl::Status Sandbox::Init() {
|
|||
ModifyExecutor(executor.get());
|
||||
|
||||
s2_ = absl::make_unique<sandbox2::Sandbox2>(std::move(executor),
|
||||
std::move(s2p));
|
||||
std::move(s2p), CreateNotifier());
|
||||
auto res = s2_->RunAsync();
|
||||
|
||||
comms_ = s2_->comms();
|
||||
|
|
|
@ -141,6 +141,9 @@ class Sandbox {
|
|||
// Modifies the Executor object if needed.
|
||||
virtual void ModifyExecutor(sandbox2::Executor* executor) {}
|
||||
|
||||
// Provides a custom notifier for sandboxee events. May return nullptr.
|
||||
virtual std::unique_ptr<sandbox2::Notify> CreateNotifier() { return nullptr; }
|
||||
|
||||
// Exits the sandboxee.
|
||||
void Exit() const;
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
|
|||
|
||||
// Creates a new Buffer of the specified size, backed by a temporary file that
|
||||
// will be immediately deleted.
|
||||
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(int64_t size) {
|
||||
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(size_t size) {
|
||||
int fd;
|
||||
if (!util::CreateMemFd(&fd)) {
|
||||
return absl::InternalError("Could not create buffer temp file");
|
||||
|
|
|
@ -41,7 +41,7 @@ class Buffer final {
|
|||
|
||||
// Creates a new Buffer of the specified size, backed by a temporary file that
|
||||
// will be immediately deleted.
|
||||
static absl::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(int64_t size);
|
||||
static absl::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(size_t size);
|
||||
|
||||
// Returns a pointer to the buffer, which is read/write.
|
||||
uint8_t* data() const { return buf_; }
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
namespace sandbox2 {
|
||||
|
||||
const char kForkServerDisableEnv[] = "SANDBOX2_NOFORKSERVER";
|
||||
|
||||
pid_t ForkClient::SendRequest(const ForkRequest& request, int exec_fd,
|
||||
int comms_fd, int user_ns_fd, pid_t* init_pid) {
|
||||
// Acquire the channel ownership for this request (transaction).
|
||||
|
|
|
@ -17,34 +17,35 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace sandbox2 {
|
||||
|
||||
// Envvar indicating that this process should not start the fork-server.
|
||||
ABSL_CONST_INIT extern const char kForkServerDisableEnv[];
|
||||
constexpr inline char kForkServerDisableEnv[] = "SANDBOX2_NOFORKSERVER";
|
||||
|
||||
class Comms;
|
||||
class ForkRequest;
|
||||
|
||||
class ForkClient {
|
||||
public:
|
||||
explicit ForkClient(Comms* comms) : comms_(comms) {}
|
||||
|
||||
ForkClient(const ForkClient&) = delete;
|
||||
ForkClient& operator=(const ForkClient&) = delete;
|
||||
|
||||
explicit ForkClient(Comms* comms) : comms_(comms) {}
|
||||
|
||||
// Sends the fork request over the supplied Comms channel.
|
||||
pid_t SendRequest(const ForkRequest& request, int exec_fd, int comms_fd,
|
||||
int user_ns_fd = -1, pid_t* init_pid = nullptr);
|
||||
|
||||
private:
|
||||
// Comms channel connecting with the ForkServer. Not owned by the object.
|
||||
Comms* comms_;
|
||||
Comms* comms_ ABSL_GUARDED_BY(comms_mutex_);
|
||||
// Mutex locking transactions (requests) over the Comms channel.
|
||||
absl::Mutex comms_mutex_;
|
||||
};
|
||||
|
||||
} // namespace sandbox2
|
||||
|
||||
#endif // SANDBOXED_API_SANDBOX2_FORK_CLIENT_H_
|
||||
|
|
|
@ -45,6 +45,7 @@ target_link_libraries(sapi_generator PUBLIC
|
|||
absl::memory
|
||||
absl::random_random
|
||||
absl::status
|
||||
absl::statusor
|
||||
absl::strings
|
||||
clangFormat
|
||||
clangFrontendTool
|
||||
|
@ -59,12 +60,15 @@ add_executable(sapi_generator_tool
|
|||
)
|
||||
target_link_libraries(sapi_generator_tool PRIVATE
|
||||
sapi::base
|
||||
sandbox2::file_helpers
|
||||
sandbox2::fileops
|
||||
sapi::generator
|
||||
)
|
||||
|
||||
if(SAPI_ENABLE_TESTS)
|
||||
add_executable(sapi_generator_test
|
||||
frontend_action_test_util.cc
|
||||
frontend_action_test_util.h
|
||||
emitter_test.cc
|
||||
)
|
||||
target_link_libraries(sapi_generator_test PRIVATE
|
||||
|
|
|
@ -23,9 +23,13 @@
|
|||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "sandboxed_api/tools/clang_generator/diagnostics.h"
|
||||
#include "sandboxed_api/tools/clang_generator/generator.h"
|
||||
#include "sandboxed_api/util/status_macros.h"
|
||||
|
||||
namespace sapi {
|
||||
|
@ -106,6 +110,30 @@ constexpr absl::string_view kClassFooterTemplate = R"(
|
|||
};
|
||||
)";
|
||||
|
||||
namespace internal {
|
||||
|
||||
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
|
||||
const std::string& code) {
|
||||
// Configure code style based on Google style, but enforce pointer alignment
|
||||
clang::format::FormatStyle style =
|
||||
clang::format::getGoogleStyle(clang::format::FormatStyle::LK_Cpp);
|
||||
style.DerivePointerAlignment = false;
|
||||
style.PointerAlignment = clang::format::FormatStyle::PAS_Left;
|
||||
|
||||
clang::tooling::Replacements replacements = clang::format::reformat(
|
||||
style, code, llvm::makeArrayRef(clang::tooling::Range(0, code.size())),
|
||||
filename);
|
||||
|
||||
llvm::Expected<std::string> formatted_header =
|
||||
clang::tooling::applyAllReplacements(code, replacements);
|
||||
if (!formatted_header) {
|
||||
return absl::InternalError(llvm::toString(formatted_header.takeError()));
|
||||
}
|
||||
return *formatted_header;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
std::string GetIncludeGuard(absl::string_view filename) {
|
||||
if (filename.empty()) {
|
||||
static auto* bit_gen = new absl::BitGen();
|
||||
|
@ -250,7 +278,8 @@ absl::StatusOr<std::string> EmitFunction(const clang::FunctionDecl* decl) {
|
|||
}
|
||||
|
||||
absl::StatusOr<std::string> EmitHeader(
|
||||
std::vector<clang::FunctionDecl*> functions, const QualTypeSet& types,
|
||||
const std::vector<std::string>& functions,
|
||||
const Emitter::RenderedTypesMap& rendered_types,
|
||||
const GeneratorOptions& options) {
|
||||
std::string out;
|
||||
const std::string include_guard = GetIncludeGuard(options.out_file);
|
||||
|
@ -276,45 +305,19 @@ absl::StatusOr<std::string> EmitHeader(
|
|||
}
|
||||
|
||||
// Emit type dependencies
|
||||
// TODO(cblichmann): Coalesce namespaces
|
||||
std::string out_types = "// Types this API depends on\n";
|
||||
bool added_types = false;
|
||||
for (const clang::QualType& qual : types) {
|
||||
clang::TypeDecl* decl = nullptr;
|
||||
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
||||
decl = typedef_type->getDecl();
|
||||
} else if (const auto* enum_type = qual->getAs<clang::EnumType>()) {
|
||||
decl = enum_type->getDecl();
|
||||
} else {
|
||||
decl = qual->getAsRecordDecl();
|
||||
}
|
||||
if (!decl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<std::string> ns_path = GetNamespacePath(decl);
|
||||
std::string nested_ns_name;
|
||||
if (!ns_path.empty()) {
|
||||
if (const auto& ns_root = ns_path.front();
|
||||
ns_root == "std" || ns_root == "sapi" || ns_root == "__gnu_cxx") {
|
||||
// Filter out any and all declarations from the C++ standard library,
|
||||
// from SAPI itself and from other well-known namespaces. This avoids
|
||||
// re-declaring things like standard integer types, for example.
|
||||
continue;
|
||||
if (!rendered_types.empty()) {
|
||||
absl::StrAppend(&out, "// Types this API depends on\n");
|
||||
for (const auto& [ns_name, types] : rendered_types) {
|
||||
if (!ns_name.empty()) {
|
||||
absl::StrAppend(&out, "namespace ", ns_name, " {\n");
|
||||
}
|
||||
for (const auto& type : types) {
|
||||
absl::StrAppend(&out, type, ";\n");
|
||||
}
|
||||
if (!ns_name.empty()) {
|
||||
absl::StrAppend(&out, "} // namespace ", ns_name, "\n\n");
|
||||
}
|
||||
nested_ns_name = absl::StrCat(ns_path[0].empty() ? "" : " ",
|
||||
absl::StrJoin(ns_path, "::"));
|
||||
absl::StrAppend(&out_types, "namespace", nested_ns_name, " {\n");
|
||||
}
|
||||
absl::StrAppend(&out_types, PrintAstDecl(decl), ";");
|
||||
if (!ns_path.empty()) {
|
||||
absl::StrAppend(&out_types, "\n} // namespace", nested_ns_name);
|
||||
}
|
||||
absl::StrAppend(&out_types, "\n");
|
||||
added_types = true;
|
||||
}
|
||||
if (added_types) {
|
||||
absl::StrAppend(&out, out_types);
|
||||
}
|
||||
|
||||
// Optionally emit a default sandbox that instantiates an embedded sandboxee
|
||||
|
@ -329,11 +332,7 @@ absl::StatusOr<std::string> EmitHeader(
|
|||
// TODO(cblichmann): Make the "Api" suffix configurable or at least optional.
|
||||
absl::StrAppendFormat(&out, kClassHeaderTemplate,
|
||||
absl::StrCat(options.name, "Api"));
|
||||
std::string out_func;
|
||||
for (const clang::FunctionDecl* decl : functions) {
|
||||
SAPI_ASSIGN_OR_RETURN(out_func, EmitFunction(decl));
|
||||
absl::StrAppend(&out, out_func);
|
||||
}
|
||||
absl::StrAppend(&out, absl::StrJoin(functions, "\n"));
|
||||
absl::StrAppend(&out, kClassFooterTemplate);
|
||||
|
||||
// Close out the header: close namespace (if needed) and end include guard
|
||||
|
@ -344,4 +343,45 @@ absl::StatusOr<std::string> EmitHeader(
|
|||
return out;
|
||||
}
|
||||
|
||||
void Emitter::CollectType(clang::QualType qual) {
|
||||
clang::TypeDecl* decl = nullptr;
|
||||
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
||||
decl = typedef_type->getDecl();
|
||||
} else if (const auto* enum_type = qual->getAs<clang::EnumType>()) {
|
||||
decl = enum_type->getDecl();
|
||||
} else {
|
||||
decl = qual->getAsRecordDecl();
|
||||
}
|
||||
if (!decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<std::string> ns_path = GetNamespacePath(decl);
|
||||
std::string ns_name;
|
||||
if (!ns_path.empty()) {
|
||||
if (const auto& ns_root = ns_path.front();
|
||||
ns_root == "std" || ns_root == "sapi" || ns_root == "__gnu_cxx") {
|
||||
// Filter out any and all declarations from the C++ standard library,
|
||||
// from SAPI itself and from other well-known namespaces. This avoids
|
||||
// re-declaring things like standard integer types, for example.
|
||||
return;
|
||||
}
|
||||
ns_name = absl::StrCat(ns_path[0].empty() ? "" : " ",
|
||||
absl::StrJoin(ns_path, "::"));
|
||||
}
|
||||
|
||||
rendered_types_[ns_name].push_back(PrintAstDecl(decl));
|
||||
}
|
||||
|
||||
void Emitter::CollectFunction(clang::FunctionDecl* decl) {
|
||||
functions_.push_back(*EmitFunction(decl)); // Cannot currently fail
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> Emitter::EmitHeader(
|
||||
const GeneratorOptions& options) {
|
||||
SAPI_ASSIGN_OR_RETURN(const std::string header,
|
||||
::sapi::EmitHeader(functions_, rendered_types_, options));
|
||||
return internal::ReformatGoogleStyle(options.out_file, header);
|
||||
}
|
||||
|
||||
} // namespace sapi
|
||||
|
|
|
@ -16,16 +16,44 @@
|
|||
#define SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "sandboxed_api/tools/clang_generator/generator.h"
|
||||
#include "sandboxed_api/tools/clang_generator/types.h"
|
||||
|
||||
namespace sapi {
|
||||
namespace internal {
|
||||
|
||||
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
|
||||
const std::string& code);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class GeneratorOptions;
|
||||
|
||||
class Emitter {
|
||||
public:
|
||||
using RenderedTypesMap =
|
||||
absl::flat_hash_map<std::string, std::vector<std::string>>;
|
||||
|
||||
void CollectType(clang::QualType qual);
|
||||
void CollectFunction(clang::FunctionDecl* decl);
|
||||
|
||||
// Outputs a formatted header for a list of functions and their related types.
|
||||
absl::StatusOr<std::string> EmitHeader(const GeneratorOptions& options);
|
||||
|
||||
protected:
|
||||
// Maps namespace to a list of spellings for types
|
||||
RenderedTypesMap rendered_types_;
|
||||
|
||||
// Functions for sandboxed API, including their bodies
|
||||
std::vector<std::string> functions_;
|
||||
};
|
||||
|
||||
// Constructs an include guard name for the given filename. The name is of the
|
||||
// same form as the include guards in this project.
|
||||
|
@ -35,11 +63,6 @@ namespace sapi {
|
|||
// SANDBOXED_API_EXAMPLES_ZLIB_ZLIB_SAPI_SAPI_H_
|
||||
std::string GetIncludeGuard(absl::string_view filename);
|
||||
|
||||
// Outputs a formatted header for a list of functions and their related types.
|
||||
absl::StatusOr<std::string> EmitHeader(
|
||||
std::vector<clang::FunctionDecl*> functions, const QualTypeSet& types,
|
||||
const GeneratorOptions& options);
|
||||
|
||||
} // namespace sapi
|
||||
|
||||
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_
|
||||
|
|
|
@ -14,18 +14,48 @@
|
|||
|
||||
#include "sandboxed_api/tools/clang_generator/emitter.h"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sandboxed_api/sandbox2/testing.h"
|
||||
#include "sandboxed_api/tools/clang_generator/frontend_action_test_util.h"
|
||||
#include "sandboxed_api/tools/clang_generator/generator.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
namespace sapi {
|
||||
namespace {
|
||||
|
||||
using ::testing::MatchesRegex;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::StrEq;
|
||||
using ::testing::StrNe;
|
||||
|
||||
class EmitterForTesting : public Emitter {
|
||||
public:
|
||||
using Emitter::functions_;
|
||||
};
|
||||
|
||||
class EmitterTest : public FrontendActionTest {};
|
||||
|
||||
TEST_F(EmitterTest, BasicFunctionality) {
|
||||
GeneratorOptions options;
|
||||
options.out_file = "input.h";
|
||||
options.set_function_names<std::initializer_list<std::string>>(
|
||||
{"ExposedFunction"});
|
||||
|
||||
EmitterForTesting emitter;
|
||||
RunFrontendAction(R"(extern "C" void ExposedFunction() {})",
|
||||
absl::make_unique<GeneratorAction>(emitter, options));
|
||||
|
||||
EXPECT_THAT(emitter.functions_, SizeIs(1));
|
||||
|
||||
absl::StatusOr<std::string> header = emitter.EmitHeader(options);
|
||||
EXPECT_THAT(header, IsOk());
|
||||
}
|
||||
|
||||
TEST(IncludeGuard, CreatesRandomizedGuardForEmptyFilename) {
|
||||
// Copybara will transform the string. This is intentional.
|
||||
constexpr absl::string_view kGeneratedHeaderPrefix =
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2020 google llc
|
||||
//
|
||||
// licensed under the apache license, version 2.0 (the "license");
|
||||
// you may not use this file except in compliance with the license.
|
||||
// you may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/license-2.0
|
||||
//
|
||||
// unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the license is distributed on an "as is" basis,
|
||||
// without warranties or conditions of any kind, either express or implied.
|
||||
// see the license for the specific language governing permissions and
|
||||
// limitations under the license.
|
||||
|
||||
#include "sandboxed_api/tools/clang_generator/frontend_action_test_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/FileSystemOptions.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
namespace sapi {
|
||||
namespace internal {
|
||||
|
||||
absl::Status RunClangTool(
|
||||
const std::vector<std::string> command_line,
|
||||
const absl::flat_hash_map<std::string, std::string> file_contents,
|
||||
std::unique_ptr<clang::FrontendAction> action) {
|
||||
// Setup an in-memory virtual filesystem
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> fs(
|
||||
new llvm::vfs::InMemoryFileSystem());
|
||||
llvm::IntrusiveRefCntPtr<clang::FileManager> files =
|
||||
new clang::FileManager(clang::FileSystemOptions(), fs);
|
||||
|
||||
for (const auto& [filename, content] : file_contents) {
|
||||
if (!fs->addFile(filename, /*ModificationTime=*/0,
|
||||
llvm::MemoryBuffer::getMemBuffer(content))) {
|
||||
return absl::UnknownError(
|
||||
absl::StrCat("Couldn't add file to in-memory VFS: ", filename));
|
||||
}
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 10
|
||||
clang::tooling::ToolInvocation invocation(command_line, std::move(action),
|
||||
files.get());
|
||||
#else
|
||||
clang::tooling::ToolInvocation invocation(command_line, action.get(),
|
||||
files.get());
|
||||
#endif
|
||||
if (!invocation.run()) {
|
||||
return absl::UnknownError("Tool invocation failed");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
std::vector<std::string> FrontendActionTest::GetCommandLineFlagsForTesting(
|
||||
absl::string_view input_file) {
|
||||
return {"tool", "-fsyntax-only", "--std=c++17",
|
||||
"-I.", "-Wno-error", std::string(input_file)};
|
||||
}
|
||||
|
||||
} // namespace sapi
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2020 google llc
|
||||
//
|
||||
// licensed under the apache license, version 2.0 (the "license");
|
||||
// you may not use this file except in compliance with the license.
|
||||
// you may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/license-2.0
|
||||
//
|
||||
// unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the license is distributed on an "as is" basis,
|
||||
// without warranties or conditions of any kind, either express or implied.
|
||||
// see the license for the specific language governing permissions and
|
||||
// limitations under the license.
|
||||
|
||||
#ifndef SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
|
||||
#define SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
namespace sapi {
|
||||
namespace internal {
|
||||
|
||||
absl::Status RunClangTool(
|
||||
const std::vector<std::string> command_line,
|
||||
const absl::flat_hash_map<std::string, std::string> file_contents,
|
||||
std::unique_ptr<clang::FrontendAction> action);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class FrontendActionTest : public ::testing::Test {
|
||||
protected:
|
||||
// Adds code to a virtual filesystem with the given filename.
|
||||
void AddCode(const std::string& filename, absl::string_view code) {
|
||||
absl::StrAppend(&file_contents_[filename], code);
|
||||
}
|
||||
|
||||
// Changes the name of the virtual input file. Useful for special cases where
|
||||
// the filenames of compiled sources matter.
|
||||
void set_input_file(absl::string_view value) {
|
||||
input_file_ = std::string(value);
|
||||
}
|
||||
|
||||
virtual std::vector<std::string> GetCommandLineFlagsForTesting(
|
||||
absl::string_view input_file);
|
||||
|
||||
// Runs the specified frontend action on in-memory source code.
|
||||
void RunFrontendAction(absl::string_view code,
|
||||
std::unique_ptr<clang::FrontendAction> action) {
|
||||
std::vector<std::string> command_line =
|
||||
GetCommandLineFlagsForTesting(input_file_);
|
||||
AddCode(input_file_, code);
|
||||
ASSERT_THAT(
|
||||
internal::RunClangTool(command_line, file_contents_, std::move(action)),
|
||||
IsOk());
|
||||
}
|
||||
|
||||
// Runs the specified frontend action. Provided for compatibility with LLVM <
|
||||
// 10. Takes ownership.
|
||||
void RunFrontendAction(absl::string_view code,
|
||||
clang::FrontendAction* action) {
|
||||
RunFrontendAction(code, absl::WrapUnique(action));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string input_file_ = "input.cc";
|
||||
absl::flat_hash_map<std::string, std::string> file_contents_;
|
||||
};
|
||||
|
||||
} // namespace sapi
|
||||
|
||||
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/tools/clang_generator/diagnostics.h"
|
||||
|
@ -39,88 +40,46 @@ std::string ReplaceFileExtension(absl::string_view path,
|
|||
return absl::StrCat(path.substr(0, pos), new_extension);
|
||||
}
|
||||
|
||||
std::string GetOutputFilename(absl::string_view source_file) {
|
||||
return ReplaceFileExtension(source_file, ".sapi.h");
|
||||
}
|
||||
|
||||
inline absl::string_view ToStringView(llvm::StringRef ref) {
|
||||
return absl::string_view(ref.data(), ref.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string GetOutputFilename(absl::string_view source_file) {
|
||||
return ReplaceFileExtension(source_file, ".sapi.h");
|
||||
}
|
||||
|
||||
bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
|
||||
if (!decl->isCXXClassMember() && // Skip classes
|
||||
decl->isExternC() && // Skip non external functions
|
||||
!decl->isTemplated() && // Skip function templates
|
||||
// Process either all function or just the requested ones
|
||||
(options_->function_names.empty() ||
|
||||
options_->function_names.count(ToStringView(decl->getName())) > 0)) {
|
||||
(options_.function_names.empty() ||
|
||||
options_.function_names.count(ToStringView(decl->getName())) > 0)) {
|
||||
functions_.push_back(decl);
|
||||
GatherRelatedTypes(decl->getDeclaredReturnType(), &types_);
|
||||
|
||||
collector_.CollectRelatedTypes(decl->getDeclaredReturnType());
|
||||
for (const clang::ParmVarDecl* param : decl->parameters()) {
|
||||
GatherRelatedTypes(param->getType(), &types_);
|
||||
collector_.CollectRelatedTypes(param->getType());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
|
||||
const std::string& code) {
|
||||
// Configure code style based on Google style, but enforce pointer alignment
|
||||
clang::format::FormatStyle style =
|
||||
clang::format::getGoogleStyle(clang::format::FormatStyle::LK_Cpp);
|
||||
style.DerivePointerAlignment = false;
|
||||
style.PointerAlignment = clang::format::FormatStyle::PAS_Left;
|
||||
|
||||
clang::tooling::Replacements replacements = clang::format::reformat(
|
||||
style, code, llvm::makeArrayRef(clang::tooling::Range(0, code.size())),
|
||||
filename);
|
||||
|
||||
llvm::Expected<std::string> formatted_header =
|
||||
clang::tooling::applyAllReplacements(code, replacements);
|
||||
if (!formatted_header) {
|
||||
return absl::InternalError(llvm::toString(formatted_header.takeError()));
|
||||
}
|
||||
return *formatted_header;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
absl::Status GeneratorASTConsumer::GenerateAndSaveHeader() {
|
||||
const std::string out_file =
|
||||
options_->out_file.empty() ? GetOutputFilename(in_file_)
|
||||
: sandbox2::file_util::fileops::MakeAbsolute(
|
||||
options_->out_file, options_->work_dir);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(const std::string header,
|
||||
EmitHeader(visitor_.functions_, visitor_.types_, *options_));
|
||||
SAPI_ASSIGN_OR_RETURN(const std::string formatted_header,
|
||||
internal::ReformatGoogleStyle(in_file_, header));
|
||||
|
||||
std::ofstream os(out_file, std::ios::out | std::ios::trunc);
|
||||
os << formatted_header;
|
||||
if (!os) {
|
||||
return absl::UnknownError("I/O error");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
|
||||
absl::Status status;
|
||||
std::cout << "Processing " << in_file_ << "\n";
|
||||
if (!visitor_.TraverseDecl(context.getTranslationUnitDecl())) {
|
||||
status = absl::InternalError("AST traversal exited early");
|
||||
} else {
|
||||
status = GenerateAndSaveHeader();
|
||||
ReportFatalError(context.getDiagnostics(),
|
||||
context.getTranslationUnitDecl()->getBeginLoc(),
|
||||
"AST traversal exited early");
|
||||
}
|
||||
|
||||
if (!status.ok()) {
|
||||
ReportFatalError(context.getDiagnostics(),
|
||||
GetDiagnosticLocationFromStatus(status).value_or(
|
||||
context.getTranslationUnitDecl()->getBeginLoc()),
|
||||
status.message());
|
||||
for (clang::QualType qual : visitor_.collector_.collected()) {
|
||||
emitter_.CollectType(qual);
|
||||
}
|
||||
for (clang::FunctionDecl* func : visitor_.functions_) {
|
||||
emitter_.CollectFunction(func);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "sandboxed_api/tools/clang_generator/emitter.h"
|
||||
#include "sandboxed_api/tools/clang_generator/types.h"
|
||||
|
||||
namespace sapi {
|
||||
|
@ -46,85 +47,87 @@ struct GeneratorOptions {
|
|||
std::string work_dir;
|
||||
std::string name; // Name of the Sandboxed API
|
||||
std::string namespace_name; // Namespace to wrap the SAPI in
|
||||
std::string out_file; // Output path of the generated header
|
||||
std::string embed_dir; // Directory with embedded includes
|
||||
std::string embed_name; // Identifier of the embed object
|
||||
// Output path of the generated header. Used to build the header include
|
||||
// guard.
|
||||
std::string out_file;
|
||||
std::string embed_dir; // Directory with embedded includes
|
||||
std::string embed_name; // Identifier of the embed object
|
||||
};
|
||||
|
||||
class GeneratorASTVisitor
|
||||
: public clang::RecursiveASTVisitor<GeneratorASTVisitor> {
|
||||
public:
|
||||
explicit GeneratorASTVisitor(const GeneratorOptions& options)
|
||||
: options_(options) {}
|
||||
|
||||
bool VisitFunctionDecl(clang::FunctionDecl* decl);
|
||||
|
||||
private:
|
||||
friend class GeneratorASTConsumer;
|
||||
const GeneratorOptions* options_ = nullptr;
|
||||
|
||||
TypeCollector collector_;
|
||||
|
||||
std::vector<clang::FunctionDecl*> functions_;
|
||||
QualTypeSet types_;
|
||||
|
||||
const GeneratorOptions& options_;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
|
||||
const std::string& code);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class GeneratorASTConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
GeneratorASTConsumer(std::string in_file, const GeneratorOptions* options)
|
||||
: in_file_(std::move(in_file)), options_(options) {
|
||||
visitor_.options_ = options_;
|
||||
}
|
||||
GeneratorASTConsumer(std::string in_file, Emitter& emitter,
|
||||
const GeneratorOptions& options)
|
||||
: in_file_(std::move(in_file)), visitor_(options), emitter_(emitter) {}
|
||||
|
||||
private:
|
||||
void HandleTranslationUnit(clang::ASTContext& context) override;
|
||||
|
||||
absl::Status GenerateAndSaveHeader();
|
||||
|
||||
std::string in_file_;
|
||||
const GeneratorOptions* options_;
|
||||
|
||||
GeneratorASTVisitor visitor_;
|
||||
|
||||
Emitter& emitter_;
|
||||
};
|
||||
|
||||
class GeneratorAction : public clang::ASTFrontendAction {
|
||||
public:
|
||||
explicit GeneratorAction(const GeneratorOptions* options)
|
||||
: options_(options) {}
|
||||
GeneratorAction(Emitter& emitter, const GeneratorOptions& options)
|
||||
: emitter_(emitter), options_(options) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||
clang::CompilerInstance&, llvm::StringRef in_file) override {
|
||||
return absl::make_unique<GeneratorASTConsumer>(std::string(in_file),
|
||||
options_);
|
||||
emitter_, options_);
|
||||
}
|
||||
|
||||
bool hasCodeCompletionSupport() const override { return false; }
|
||||
|
||||
const GeneratorOptions* options_;
|
||||
Emitter& emitter_;
|
||||
const GeneratorOptions& options_;
|
||||
};
|
||||
|
||||
class GeneratorFactory : public clang::tooling::FrontendActionFactory {
|
||||
public:
|
||||
explicit GeneratorFactory(GeneratorOptions options = {})
|
||||
: options_(std::move(options)) {}
|
||||
// Does not take ownership
|
||||
GeneratorFactory(Emitter& emitter, const GeneratorOptions& options)
|
||||
: emitter_(emitter), options_(options) {}
|
||||
|
||||
private:
|
||||
#if LLVM_VERSION_MAJOR >= 10
|
||||
std::unique_ptr<clang::FrontendAction> create() override {
|
||||
return absl::make_unique<GeneratorAction>(&options_);
|
||||
return absl::make_unique<GeneratorAction>(emitter_, options_);
|
||||
}
|
||||
#else
|
||||
clang::FrontendAction* create() override {
|
||||
return new GeneratorAction(&options_);
|
||||
return new GeneratorAction(emitter_, options_);
|
||||
}
|
||||
#endif
|
||||
|
||||
GeneratorOptions options_;
|
||||
Emitter& emitter_;
|
||||
const GeneratorOptions& options_;
|
||||
};
|
||||
|
||||
std::string GetOutputFilename(absl::string_view source_file);
|
||||
|
||||
} // namespace sapi
|
||||
|
||||
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_
|
||||
|
|
|
@ -12,16 +12,23 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Tooling/ArgumentsAdjusters.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "sandboxed_api/sandbox2/util/file_helpers.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/tools/clang_generator/generator.h"
|
||||
#include "sandboxed_api/util/status_macros.h"
|
||||
|
||||
namespace sapi {
|
||||
namespace {
|
||||
|
@ -49,11 +56,11 @@ static auto* g_sapi_functions = new llvm::cl::list<std::string>(
|
|||
llvm::cl::cat(*g_tool_category));
|
||||
static auto* g_sapi_in = new llvm::cl::list<std::string>(
|
||||
"sapi_in", llvm::cl::CommaSeparated,
|
||||
llvm::cl::desc("List of input files to analyze. Deprecated, use positional "
|
||||
"arguments instead."),
|
||||
llvm::cl::desc("List of input files to analyze."),
|
||||
llvm::cl::cat(*g_tool_category));
|
||||
static auto* g_sapi_isystem = new llvm::cl::opt<std::string>(
|
||||
"sapi_isystem", llvm::cl::desc("Extra system include paths"),
|
||||
"sapi_isystem",
|
||||
llvm::cl::desc("Parameter file with extra system include paths"),
|
||||
llvm::cl::cat(*g_tool_category));
|
||||
static auto* g_sapi_limit_scan_depth = new llvm::cl::opt<bool>(
|
||||
"sapi_limit_scan_depth",
|
||||
|
@ -69,28 +76,28 @@ static auto* g_sapi_ns = new llvm::cl::opt<std::string>(
|
|||
static auto* g_sapi_out = new llvm::cl::opt<std::string>(
|
||||
"sapi_out",
|
||||
llvm::cl::desc(
|
||||
"Ouput path of the generated header. If empty, simply appends .sapi.h "
|
||||
"Output path of the generated header. If empty, simply appends .sapi.h "
|
||||
"to the basename of the first source file specified."),
|
||||
llvm::cl::cat(*g_tool_category));
|
||||
|
||||
} // namespace
|
||||
|
||||
GeneratorOptions GeneratorOptionsFromFlags() {
|
||||
GeneratorOptions GeneratorOptionsFromFlags(
|
||||
const std::vector<std::string>& sources) {
|
||||
GeneratorOptions options;
|
||||
options.function_names.insert(g_sapi_functions->begin(),
|
||||
g_sapi_functions->end());
|
||||
options.work_dir = sandbox2::file_util::fileops::GetCWD();
|
||||
options.name = *g_sapi_name;
|
||||
options.namespace_name = *g_sapi_ns;
|
||||
options.out_file = *g_sapi_out;
|
||||
options.out_file =
|
||||
!g_sapi_out->empty() ? *g_sapi_out : GetOutputFilename(sources.front());
|
||||
options.embed_dir = *g_sapi_embed_dir;
|
||||
options.embed_name = *g_sapi_embed_name;
|
||||
return options;
|
||||
}
|
||||
|
||||
} // namespace sapi
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
absl::Status GeneratorMain(int argc, const char** argv) {
|
||||
clang::tooling::CommonOptionsParser opt_parser(
|
||||
argc, argv, *sapi::g_tool_category, llvm::cl::ZeroOrMore,
|
||||
"Generates a Sandboxed API header for C/C++ translation units.");
|
||||
|
@ -98,9 +105,45 @@ int main(int argc, const char** argv) {
|
|||
for (const auto& sapi_in : *sapi::g_sapi_in) {
|
||||
sources.push_back(sapi_in);
|
||||
}
|
||||
if (sources.empty()) {
|
||||
return absl::InvalidArgumentError("error: no input files");
|
||||
}
|
||||
|
||||
auto options = sapi::GeneratorOptionsFromFlags(sources);
|
||||
sapi::Emitter emitter;
|
||||
|
||||
clang::tooling::ClangTool tool(opt_parser.getCompilations(), sources);
|
||||
return tool.run(absl::make_unique<sapi::GeneratorFactory>(
|
||||
sapi::GeneratorOptionsFromFlags())
|
||||
.get());
|
||||
if (!sapi::g_sapi_isystem->empty()) {
|
||||
std::string isystem_lines;
|
||||
SAPI_RETURN_IF_ERROR(sandbox2::file::GetContents(
|
||||
*sapi::g_sapi_isystem, &isystem_lines, sandbox2::file::Defaults()));
|
||||
std::vector<std::string> isystem =
|
||||
absl::StrSplit(isystem_lines, '\n', absl::SkipWhitespace());
|
||||
for (std::string& line : isystem) {
|
||||
line.insert(0, "-isystem");
|
||||
}
|
||||
tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster(
|
||||
isystem, clang::tooling::ArgumentInsertPosition::BEGIN));
|
||||
}
|
||||
if (int result = tool.run(
|
||||
absl::make_unique<sapi::GeneratorFactory>(emitter, options).get());
|
||||
result != 0) {
|
||||
return absl::UnknownError("header generation failed");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(std::string header, emitter.EmitHeader(options));
|
||||
|
||||
SAPI_RETURN_IF_ERROR(sandbox2::file::SetContents(options.out_file, header,
|
||||
sandbox2::file::Defaults()));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace sapi
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
if (absl::Status status = sapi::GeneratorMain(argc, argv); !status.ok()) {
|
||||
absl::FPrintF(stderr, "error: %s\n", status.message());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,15 @@ bool IsFunctionReferenceType(clang::QualType qual) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
||||
void TypeCollector::CollectRelatedTypes(clang::QualType qual) {
|
||||
if (seen_.contains(qual)) {
|
||||
return;
|
||||
}
|
||||
seen_.insert(qual);
|
||||
|
||||
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
||||
GatherRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types);
|
||||
types->insert(qual);
|
||||
CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType());
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -43,26 +48,26 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
|||
->getAs<clang::FunctionProtoType>()) {
|
||||
// Note: Do not add the function type itself, as this will always be a
|
||||
// pointer argument. We only need to collect all its related types.
|
||||
GatherRelatedTypes(function_type->getReturnType(), types);
|
||||
CollectRelatedTypes(function_type->getReturnType());
|
||||
for (const clang::QualType& param : function_type->getParamTypes()) {
|
||||
GatherRelatedTypes(param, types);
|
||||
CollectRelatedTypes(param);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPointerOrReference(qual)) {
|
||||
clang::QualType pointee = qual->getPointeeType();
|
||||
while (IsPointerOrReference(pointee)) {
|
||||
clang::QualType pointee = qual;
|
||||
do {
|
||||
pointee = pointee->getPointeeType();
|
||||
}
|
||||
GatherRelatedTypes(pointee, types);
|
||||
} while (IsPointerOrReference(pointee));
|
||||
CollectRelatedTypes(pointee);
|
||||
return;
|
||||
}
|
||||
|
||||
// C array with specified constant size (i.e. int a[42])?
|
||||
if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) {
|
||||
GatherRelatedTypes(array_type->getElementType(), types);
|
||||
CollectRelatedTypes(array_type->getElementType());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -71,19 +76,19 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
|||
// Collect the underlying integer type of enum classes as well, as it may
|
||||
// be a typedef.
|
||||
if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) {
|
||||
GatherRelatedTypes(decl->getIntegerType(), types);
|
||||
CollectRelatedTypes(decl->getIntegerType());
|
||||
}
|
||||
}
|
||||
types->insert(qual);
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto* record_type = qual->getAs<clang::RecordType>()) {
|
||||
const clang::RecordDecl* decl = record_type->getDecl();
|
||||
for (const clang::FieldDecl* field : decl->fields()) {
|
||||
GatherRelatedTypes(field->getType(), types);
|
||||
CollectRelatedTypes(field->getType());
|
||||
}
|
||||
types->insert(qual);
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,20 +41,29 @@ inline bool IsPointerOrReference(clang::QualType qual) {
|
|||
qual->isLValueReferenceType() || qual->isRValueReferenceType();
|
||||
}
|
||||
|
||||
// Computes the transitive closure of all types that a type depends on. Those
|
||||
// are types that need to be declared before a declaration of the type denoted
|
||||
// by the qual parameter is valid. For example, given
|
||||
// struct SubStruct { bool truth_value; };
|
||||
// struct AggregateStruct {
|
||||
// int int_member;
|
||||
// SubStruct struct_member;
|
||||
// };
|
||||
//
|
||||
// calling this function on the type "AggregateStruct" yields these types:
|
||||
// int
|
||||
// SubStruct
|
||||
// bool
|
||||
void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types);
|
||||
class TypeCollector {
|
||||
public:
|
||||
// Computes the transitive closure of all types that a type depends on. Those
|
||||
// are types that need to be declared before a declaration of the type denoted
|
||||
// by the qual parameter is valid. For example, given
|
||||
// struct SubStruct { bool truth_value; };
|
||||
// struct AggregateStruct {
|
||||
// int int_member;
|
||||
// SubStruct struct_member;
|
||||
// };
|
||||
//
|
||||
// calling this function on the type "AggregateStruct" yields these types:
|
||||
// int
|
||||
// SubStruct
|
||||
// bool
|
||||
void CollectRelatedTypes(clang::QualType qual);
|
||||
|
||||
QualTypeSet& collected() { return collected_; }
|
||||
|
||||
private:
|
||||
QualTypeSet collected_;
|
||||
QualTypeSet seen_;
|
||||
};
|
||||
|
||||
// Maps a qualified type to a fully qualified SAPI-compatible type name. This
|
||||
// is used for the generated code that invokes the actual function call RPC.
|
||||
|
|
|
@ -492,7 +492,6 @@ class Function(object):
|
|||
self._tu = tu
|
||||
self.cursor = cursor # type: cindex.Index
|
||||
self.name = cursor.spelling # type: Text
|
||||
self.mangled_name = cursor.mangled_name # type: Text
|
||||
self.result = ReturnType(self, cursor.result_type)
|
||||
self.original_definition = '{} {}'.format(
|
||||
cursor.result_type.spelling, self.cursor.displayname) # type: Text
|
||||
|
@ -542,7 +541,7 @@ class Function(object):
|
|||
|
||||
def is_mangled(self):
|
||||
# type: () -> bool
|
||||
return self.name != self.mangled_name
|
||||
return self.cursor.mangled_name != self.cursor.spelling
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
|
@ -550,7 +549,7 @@ class Function(object):
|
|||
|
||||
def __eq__(self, other):
|
||||
# type: (Function) -> bool
|
||||
return self.mangled_name == other.mangled_name
|
||||
return self.cursor.mangled_name == other.cursor.mangled_name
|
||||
|
||||
|
||||
class _TranslationUnit(object):
|
||||
|
@ -580,12 +579,11 @@ class _TranslationUnit(object):
|
|||
|
||||
for i, cursor in enumerate(self._walk_preorder()):
|
||||
# Workaround for issue#32
|
||||
# ignore all the cursors with kinds not implemented in python bindings
|
||||
try:
|
||||
cursor.kind
|
||||
except ValueError:
|
||||
if cursor._kind_id >= 440: # pylint: disable=protected-access
|
||||
continue
|
||||
raise
|
||||
continue
|
||||
# naive way to order types: they should be ordered when walking the tree
|
||||
if cursor.kind.is_declaration():
|
||||
self.order[cursor.hash] = i
|
||||
|
@ -911,7 +909,7 @@ class Generator(object):
|
|||
result.append('#include "sandboxed_api/sandbox.h"')
|
||||
result.append('#include "sandboxed_api/vars.h"')
|
||||
|
||||
if (embed_dir is not None) and (embed_name is not None):
|
||||
if embed_dir and embed_name:
|
||||
result.append(
|
||||
Generator.EMBED_INCLUDE.format(
|
||||
os.path.join(embed_dir, embed_name) + '_embed.h'))
|
||||
|
@ -928,7 +926,7 @@ class Generator(object):
|
|||
|
||||
result.append('')
|
||||
|
||||
if (embed_dir is not None) and (embed_name is not None):
|
||||
if embed_dir and embed_name:
|
||||
result.append(
|
||||
Generator.EMBED_CLASS.format(name, embed_name.replace('-', '_')))
|
||||
|
||||
|
|
|
@ -832,7 +832,7 @@ class CodeAnalysisTest(parameterized.TestCase):
|
|||
functions = tu.get_functions()
|
||||
self.assertLen(functions, 2)
|
||||
|
||||
mangled_names = [f.mangled_name for f in functions]
|
||||
mangled_names = [f.cursor.mangled_name for f in functions]
|
||||
self.assertSameElements(mangled_names, ['sum', '_Z3sumif'])
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ cc_library(
|
|||
name = "statusor",
|
||||
hdrs = ["statusor.h"],
|
||||
deprecation = "Migrate to `absl::StatusOr<T>`",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
|
|
Loading…
Reference in New Issue
Block a user