Skip to content

Commit

Permalink
Allow reformatting of multiple files
Browse files Browse the repository at this point in the history
When using -i or --test.

See google#210.
  • Loading branch information
sbarzowski committed Jul 13, 2017
1 parent 12d0d1f commit 8f374a7
Showing 1 changed file with 115 additions and 65 deletions.
180 changes: 115 additions & 65 deletions cmd/jsonnet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void usage(std::ostream &o)
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 << " --ext-str-file <var>=<file> Read the string from the file(s)\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";
Expand All @@ -110,7 +110,7 @@ void usage(std::ostream &o)
o << " -h / --help This message\n";
o << " -e / --exec Treat filename as code\n";
o << " -o / --output-file <file> Write to the output file rather than stdout\n";
o << " -i / --in-place Update the Jsonnet file in place. Same as -o <filename>\n";
o << " -i / --in-place Update the Jsonnet file(s) in place. Same as -o <filename>\n";
o << " --test Exit with failure if reformatting changed the file.\n";
o << " -n / --indent <n> Number of spaces to indent by (default 0, means no change)\n";
o << " --max-blank-lines <n> Max vertical spacing, 0 means no change (default 2)\n";
Expand All @@ -121,6 +121,7 @@ void usage(std::ostream &o)
o << " --[no-]pad-objects { x: 1, x: 2 } instead of {x: 1, y: 2} (on by default)\n";
o << " --debug-desugaring Unparse the desugared AST without executing it\n";
o << " --version Print version\n";
o << "Note: Multiple filenames can be provided at once when using -i or --test options.\n";
o << "\n";
o << "In all cases:\n";
o << "<filename> can be - (stdin)\n";
Expand Down Expand Up @@ -152,7 +153,7 @@ enum Command {
/** Class for representing configuration read from command line flags. */
struct JsonnetConfig {
Command cmd;
std::string inputFile;
std::vector<std::string> inputFiles;
std::string outputFile;
bool filenameIsCode;

Expand Down Expand Up @@ -455,44 +456,53 @@ static bool process_args(int argc,
return false;
}

std::string filename = remaining_args[0];
if (remaining_args.size() > 1) {
std::cerr << "ERROR: Already specified " << want
<< " as \"" << filename << "\"\n"
<< std::endl;
usage(std::cerr);
bool multiple_files_allowed = config->cmd == FMT &&
(config->fmtTest || config->fmtInPlace);
if (!multiple_files_allowed) {
std::string filename = remaining_args[0];
if (remaining_args.size() > 1) {
std::cerr << "ERROR: Already specified " << want
<< " as \"" << filename << "\"\n"
<< std::endl;
usage(std::cerr);
return false;
}
}
config->inputFiles = remaining_args;
return true;
}

static bool read_input_contents(std::string filename, std::string *input) {
std::ifstream f;
f.open(filename);
if (!f.good()) {
std::string msg = "Opening input file: " + filename;
perror(msg.c_str());
return false;
}
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 false;
}
config->inputFile = filename;
return true;
}

/** Reads Jsonnet code from the input file or stdin into the input buffer. */
static bool read_input(JsonnetConfig* config, std::string* input) {
static bool read_input(JsonnetConfig* config, int index, std::string* input) {
if (config->filenameIsCode) {
*input = config->inputFile;
config->inputFile = "<cmdline>";
*input = config->inputFiles[index];
config->inputFiles[index] = "<cmdline>"; // side effect!
} else {
// Input file "-" tell Jsonnet to read stdin.
if (config->inputFile == "-") {
config->inputFile = "<stdin>";
// Input file "-" tells Jsonnet to read stdin.
if (config->inputFiles[index] == "-") {
config->inputFiles[index] = "<stdin>"; // side effect!
input->assign(std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>());
} else {
std::ifstream f;
f.open(config->inputFile.c_str());
if (!f.good()) {
std::string msg = "Opening input file: " + config->inputFile;
perror(msg.c_str());
return false;
}
input->assign(std::istreambuf_iterator<char>(f),
std::istreambuf_iterator<char>());
if (!f.good()) {
std::string msg = "Reading input file: " + config->inputFile;
perror(msg.c_str());
return false;
}
return read_input_contents(config->inputFiles[index], input);
}
}
return true;
Expand Down Expand Up @@ -618,27 +628,29 @@ int main(int argc, const char **argv)
return EXIT_FAILURE;
}

// Read input files.
std::string input;
if (!read_input(&config, &input)) {
jsonnet_destroy(vm);
return 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, 0, &input)) {
jsonnet_destroy(vm);
return EXIT_FAILURE;
}

if (config.evalMulti) {
output = jsonnet_evaluate_snippet_multi(
vm, config.inputFile.c_str(), input.c_str(), &error);
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
} else if (config.evalStream) {
output = jsonnet_evaluate_snippet_stream(
vm, config.inputFile.c_str(), input.c_str(), &error);
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
} else {
output = jsonnet_evaluate_snippet(
vm, config.inputFile.c_str(), input.c_str(), &error);
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
}

if (error) {
Expand Down Expand Up @@ -673,38 +685,76 @@ int main(int argc, const char **argv)

case FMT: {
std::string output_file = config.outputFile;
if (config.fmtInPlace) {
if (config.inputFile == "-") {
std::cerr << "ERROR: Cannot use --in-place with stdin" << std::endl;
jsonnet_destroy(vm);
return EXIT_FAILURE;

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_contents(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;
std::cerr.flush();
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);
jsonnet_destroy(vm);
return ok ? EXIT_SUCCESS : 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;
}
}
}
if (config.filenameIsCode) {
std::cerr << "ERROR: Cannot use --in-place with --exec" << std::endl;
} else {
assert(config.inputFiles.size() == 1);
// Read input file.
std::string input;
if (!read_input(&config, 0, &input)) {
jsonnet_destroy(vm);
return EXIT_FAILURE;
}
output_file = config.inputFile;
}

output = jsonnet_fmt_snippet(vm, config.inputFile.c_str(), input.c_str(), &error);
output = jsonnet_fmt_snippet(vm, config.inputFiles[0].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;
}

if (config.fmtTest) {
// Check the output matches the input.
bool ok = output == input;
jsonnet_realloc(vm, output, 0);
jsonnet_destroy(vm);
return ok ? EXIT_SUCCESS : 2;
if (error) {
std::cerr << output;
std::cerr.flush();
jsonnet_realloc(vm, output, 0);
jsonnet_destroy(vm);
return EXIT_FAILURE;
}

} else {
// Write output Jsonnet.
bool successful = write_output_file(output, output_file);
jsonnet_realloc(vm, output, 0);
Expand Down

0 comments on commit 8f374a7

Please sign in to comment.