Esempio n. 1
0
int main(int argc, const char **argv)
{
    try {
        JsonnetVm *vm = jsonnet_make();
        JsonnetConfig config;
        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;
        switch (config.cmd) {
            case EVAL: {
                assert(config.inputFiles.size() == 1);

                // Read input file.
                std::string input;
                if (!read_input(&config, &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;
                    }
                }
            } break;

            case FMT: {
                std::string output_file = config.outputFile;

                if (config.fmtInPlace || config.fmtTest) {
                    assert(config.inputFiles.size() >= 1);
                    for (std::string &inputFile : config.inputFiles) {
                        if (config.fmtInPlace) {
                            output_file = inputFile;

                            if (inputFile == "-") {
                                std::cerr << "ERROR: Cannot use --in-place with stdin" << std::endl;
                                jsonnet_destroy(vm);
                                return EXIT_FAILURE;
                            }
                            if (config.filenameIsCode) {
                                std::cerr << "ERROR: Cannot use --in-place with --exec"
                                          << std::endl;
                                jsonnet_destroy(vm);
                                return EXIT_FAILURE;
                            }
                        }

                        std::string input;
                        if (!read_input(&config, &inputFile, &input)) {
                            jsonnet_destroy(vm);
                            return EXIT_FAILURE;
                        }

                        output = jsonnet_fmt_snippet(vm, inputFile.c_str(), input.c_str(), &error);

                        if (error) {
                            std::cerr << output;
                            jsonnet_realloc(vm, output, 0);
                            jsonnet_destroy(vm);
                            return EXIT_FAILURE;
                        }

                        if (config.fmtTest) {
                            // Check the output matches the input.
                            bool ok = output == input;
                            jsonnet_realloc(vm, output, 0);
                            if (!ok) {
                                jsonnet_destroy(vm);
                                return 2;
                            }
                        } else {
                            // Write output Jsonnet.
                            bool successful = write_output_file(output, output_file);
                            jsonnet_realloc(vm, output, 0);
                            if (!successful) {
                                jsonnet_destroy(vm);
                                return EXIT_FAILURE;
                            }
                        }
                    }
                } else {
                    assert(config.inputFiles.size() == 1);
                    // Read input file.
                    std::string input;
                    if (!read_input(&config, &config.inputFiles[0], &input)) {
                        jsonnet_destroy(vm);
                        return EXIT_FAILURE;
                    }

                    output = jsonnet_fmt_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 Jsonnet.
                    bool successful = write_output_file(output, output_file);
                    jsonnet_realloc(vm, output, 0);
                    if (!successful) {
                        jsonnet_destroy(vm);
                        return EXIT_FAILURE;
                    }
                }
            } break;
        }

        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;
}
Esempio n. 2
0
int main(int argc, const char **argv)
{
    try {
        JsonnetVm *vm = jsonnet_make();
        JsonnetConfig config;
        if (!process_args(argc, argv, &config, vm)) {
            return EXIT_FAILURE;
        }

        // Read input files.
        std::string input;
        if (!read_input(&config, &input)) {
            return EXIT_FAILURE;
        }

        // Evaluate input Jsonnet and handle any errors from Jsonnet VM.
        int error;
        char *output;
        if (config.multi()) {
            output = jsonnet_evaluate_snippet_multi(
                vm, config.input_file().c_str(), input.c_str(), &error);
        } else {
            output = jsonnet_evaluate_snippet(
                vm, config.input_file().c_str(), input.c_str(), &error);
        }

        if (error) {
            std::cerr << output;
            std::cerr.flush();
            jsonnet_realloc(vm, output, 0);
            jsonnet_destroy(vm);
            return EXIT_FAILURE;
        }

        // Write output JSON.
        if (config.multi()) {
            if (!write_multi_output_files(vm, output, config.output_dir())) {
                return EXIT_FAILURE;
            }
        } else {
            bool successful =  write_output_file(output, config.output_file());
            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;
}
Esempio n. 3
0
int main(int argc, const char **argv)
{
				JsonnetVM *vm = jsonnet_make();
				std::string filename = "-";
				bool filename_is_code = false;
				bool multi = false;

				auto args = simplify_args(argc, argv);
				std::vector<std::string> remaining_args;

				for (unsigned i = 0; i<args.size(); ++i) {
								const std::string &arg = args[i];
								if (arg == "-h" || arg == "--help") {
												usage(std::cout);
												exit(EXIT_SUCCESS);
								}
								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 << "\n" << std::endl;
																usage(std::cerr);
																exit(EXIT_FAILURE);
												}
												jsonnet_max_stack(vm, l);
								}
								else if (arg == "-E" || arg == "--env") {
												const std::string var = next_arg(i, args);
												const char *val = ::getenv(var.c_str());
												if (val == nullptr) {
																std::cerr << "ERROR: Environment variable " << var
																				<< " was undefined." << std::endl;
																exit(EXIT_FAILURE);
												}
												jsonnet_ext_var(vm, var.c_str(), val);
								}
								else if (arg == "-V" || arg == "--var") {
												const std::string var_val = next_arg(i, args);
												size_t eq_pos = var_val.find_first_of('=', 0);
												if (eq_pos == std::string::npos) {
																std::cerr << "ERROR: argument not in form <var>=<val> \""
																				<< var_val << "\"." << std::endl;
																exit(EXIT_FAILURE);
												}
												const std::string var = var_val.substr(0, eq_pos);
												const std::string val = var_val.substr(eq_pos + 1, std::string::npos);
												jsonnet_ext_var(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;
																usage(std::cerr);
																exit(EXIT_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;
																usage(std::cerr);
																exit(EXIT_FAILURE);
												}
												jsonnet_max_trace(vm, l);
								}
								else if (arg == "--gc-growth-trigger") {
												const char *arg = next_arg(i, args).c_str();
												char *ep;
												double v = std::strtod(arg, &ep);
												if (*ep != '\0' || *arg == '\0') {
																std::cerr << "ERROR: Invalid number \"" << arg << "\"" << std::endl;
																usage(std::cerr);
																exit(EXIT_FAILURE);
												}
												if (v < 0) {
																std::cerr << "ERROR: Invalid --gc-growth-trigger \"" << arg << "\"\n" << std::endl;
																usage(std::cerr);
																exit(EXIT_FAILURE);
												}
												jsonnet_gc_growth_trigger(vm, v);
								}
								else if (arg == "-e" || arg == "--exec") {
												filename_is_code = true;
								}
								else if (arg == "-m" || arg == "--multi") {
												multi = true;
								}
								else if (arg == "--debug-ast") {
												jsonnet_debug_ast(vm, true);
								}
								else if (arg == "--") {
												// All subsequent args are not options.
												while ((++i) < args.size())
																remaining_args.push_back(args[i]);
												break;
								}
								else {
												remaining_args.push_back(args[i]);
								}
				}

				if (remaining_args.size() > 0)
								filename = remaining_args[0];

				if (remaining_args.size() > 1) {
								std::cerr << "ERROR: Filename already specified as \"" << filename << "\"\n"
												<< std::endl;
								usage(std::cerr);
								exit(EXIT_FAILURE);
				}

				if (filename_is_code && remaining_args.size() == 0) {
								std::cerr << "ERROR: Must give filename when using -e, --exec\n" << std::endl;
								usage(std::cerr);
								exit(EXIT_FAILURE);
				}

				std::string input;
				if (filename_is_code) {
								input = filename;
								filename = "<cmdline>";
				}
				else {
								if (filename == "-") {
												filename = "<stdin>";
												input.assign(std::istreambuf_iterator<char>(std::cin),
																std::istreambuf_iterator<char>());
								}
								else {
												std::ifstream f;
												f.open(filename.c_str());
												if (!f.good()) {
																std::string msg = "Opening input file: " + filename;
																perror(msg.c_str());
																return EXIT_FAILURE;
												}
												input.assign(std::istreambuf_iterator<char>(f),
																std::istreambuf_iterator<char>());
												if (!f.good()) {
																std::string msg = "Reading input file: " + filename;
																perror(msg.c_str());
																return EXIT_FAILURE;
												}
								}
				}

				int error;
				const char *output;
				if (multi) {
								output = jsonnet_evaluate_snippet_multi(vm, filename.c_str(), input.c_str(), &error);
				}
				else {
								output = jsonnet_evaluate_snippet(vm, filename.c_str(), input.c_str(), &error);
				}

				if (error) {
								std::cerr << output;
								std::cerr.flush();
								jsonnet_cleanup_string(vm, output);
								jsonnet_destroy(vm);
								return EXIT_FAILURE;
				}

				if (multi) {
								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_cleanup_string(vm, output);
								for (const auto &pair : r) {
												const std::string &new_content = pair.second;
												const std::string &filename = pair.first;
												std::cout << 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());
																jsonnet_destroy(vm);
																return EXIT_FAILURE;
												}
												f << new_content;
												f.close();
												if (!f.good()) {
																std::string msg = "Writing to output file: " + filename;
																perror(msg.c_str());
																jsonnet_destroy(vm);
																return EXIT_FAILURE;
												}
								}
								std::cout.flush();
				}
				else {
								std::cout << output;
								std::cout.flush();
								jsonnet_cleanup_string(vm, output);
				}
				jsonnet_destroy(vm);
				return EXIT_SUCCESS;
}