mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Merge pull request #54 from Manwi23:jsonnet
PiperOrigin-RevId: 335017461 Change-Id: I583444057bb4d8c8c33694fbba4d3717bb22101a
This commit is contained in:
commit
569c7d84b0
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,6 +1,9 @@
|
||||||
[submodule "oss-internship-2020/sapi_lodepng/lodepng"]
|
[submodule "oss-internship-2020/sapi_lodepng/lodepng"]
|
||||||
path = oss-internship-2020/lodepng/lodepng
|
path = oss-internship-2020/lodepng/lodepng
|
||||||
url = https://github.com/lvandeve/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"]
|
[submodule "oss-internship-2020/openjpeg/openjpeg"]
|
||||||
path = oss-internship-2020/openjpeg/openjpeg
|
path = oss-internship-2020/openjpeg/openjpeg
|
||||||
url = https://github.com/uclouvain/openjpeg.git
|
url = https://github.com/uclouvain/openjpeg.git
|
||||||
|
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user