Skip to content

Commit 8f374a7

Browse files
committed
Allow reformatting of multiple files
When using -i or --test. See google#210.
1 parent 12d0d1f commit 8f374a7

File tree

1 file changed

+115
-65
lines changed

1 file changed

+115
-65
lines changed

cmd/jsonnet.cpp

Lines changed: 115 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void usage(std::ostream &o)
9191
o << "Available options for specifying values of 'external' variables:\n";
9292
o << "Provide the value as a string:\n";
9393
o << " -V / --ext-str <var>[=<val>] If <val> is omitted, get from environment var <var>\n";
94-
o << " --ext-str-file <var>=<file> Read the string from the file\n";
94+
o << " --ext-str-file <var>=<file> Read the string from the file(s)\n";
9595
o << "Provide a value as Jsonnet code:\n";
9696
o << " --ext-code <var>[=<code>] If <code> is omitted, get from environment var <var>\n";
9797
o << " --ext-code-file <var>=<file> Read the code from the file\n";
@@ -110,7 +110,7 @@ void usage(std::ostream &o)
110110
o << " -h / --help This message\n";
111111
o << " -e / --exec Treat filename as code\n";
112112
o << " -o / --output-file <file> Write to the output file rather than stdout\n";
113-
o << " -i / --in-place Update the Jsonnet file in place. Same as -o <filename>\n";
113+
o << " -i / --in-place Update the Jsonnet file(s) in place. Same as -o <filename>\n";
114114
o << " --test Exit with failure if reformatting changed the file.\n";
115115
o << " -n / --indent <n> Number of spaces to indent by (default 0, means no change)\n";
116116
o << " --max-blank-lines <n> Max vertical spacing, 0 means no change (default 2)\n";
@@ -121,6 +121,7 @@ void usage(std::ostream &o)
121121
o << " --[no-]pad-objects { x: 1, x: 2 } instead of {x: 1, y: 2} (on by default)\n";
122122
o << " --debug-desugaring Unparse the desugared AST without executing it\n";
123123
o << " --version Print version\n";
124+
o << "Note: Multiple filenames can be provided at once when using -i or --test options.\n";
124125
o << "\n";
125126
o << "In all cases:\n";
126127
o << "<filename> can be - (stdin)\n";
@@ -152,7 +153,7 @@ enum Command {
152153
/** Class for representing configuration read from command line flags. */
153154
struct JsonnetConfig {
154155
Command cmd;
155-
std::string inputFile;
156+
std::vector<std::string> inputFiles;
156157
std::string outputFile;
157158
bool filenameIsCode;
158159

@@ -455,44 +456,53 @@ static bool process_args(int argc,
455456
return false;
456457
}
457458

458-
std::string filename = remaining_args[0];
459-
if (remaining_args.size() > 1) {
460-
std::cerr << "ERROR: Already specified " << want
461-
<< " as \"" << filename << "\"\n"
462-
<< std::endl;
463-
usage(std::cerr);
459+
bool multiple_files_allowed = config->cmd == FMT &&
460+
(config->fmtTest || config->fmtInPlace);
461+
if (!multiple_files_allowed) {
462+
std::string filename = remaining_args[0];
463+
if (remaining_args.size() > 1) {
464+
std::cerr << "ERROR: Already specified " << want
465+
<< " as \"" << filename << "\"\n"
466+
<< std::endl;
467+
usage(std::cerr);
468+
return false;
469+
}
470+
}
471+
config->inputFiles = remaining_args;
472+
return true;
473+
}
474+
475+
static bool read_input_contents(std::string filename, std::string *input) {
476+
std::ifstream f;
477+
f.open(filename);
478+
if (!f.good()) {
479+
std::string msg = "Opening input file: " + filename;
480+
perror(msg.c_str());
481+
return false;
482+
}
483+
input->assign(std::istreambuf_iterator<char>(f),
484+
std::istreambuf_iterator<char>());
485+
if (!f.good()) {
486+
std::string msg = "Reading input file: " + filename;
487+
perror(msg.c_str());
464488
return false;
465489
}
466-
config->inputFile = filename;
467490
return true;
468491
}
469492

470493
/** Reads Jsonnet code from the input file or stdin into the input buffer. */
471-
static bool read_input(JsonnetConfig* config, std::string* input) {
494+
static bool read_input(JsonnetConfig* config, int index, std::string* input) {
472495
if (config->filenameIsCode) {
473-
*input = config->inputFile;
474-
config->inputFile = "<cmdline>";
496+
*input = config->inputFiles[index];
497+
config->inputFiles[index] = "<cmdline>"; // side effect!
475498
} else {
476-
// Input file "-" tell Jsonnet to read stdin.
477-
if (config->inputFile == "-") {
478-
config->inputFile = "<stdin>";
499+
// Input file "-" tells Jsonnet to read stdin.
500+
if (config->inputFiles[index] == "-") {
501+
config->inputFiles[index] = "<stdin>"; // side effect!
479502
input->assign(std::istreambuf_iterator<char>(std::cin),
480503
std::istreambuf_iterator<char>());
481504
} else {
482-
std::ifstream f;
483-
f.open(config->inputFile.c_str());
484-
if (!f.good()) {
485-
std::string msg = "Opening input file: " + config->inputFile;
486-
perror(msg.c_str());
487-
return false;
488-
}
489-
input->assign(std::istreambuf_iterator<char>(f),
490-
std::istreambuf_iterator<char>());
491-
if (!f.good()) {
492-
std::string msg = "Reading input file: " + config->inputFile;
493-
perror(msg.c_str());
494-
return false;
495-
}
505+
return read_input_contents(config->inputFiles[index], input);
496506
}
497507
}
498508
return true;
@@ -618,27 +628,29 @@ int main(int argc, const char **argv)
618628
return EXIT_FAILURE;
619629
}
620630

621-
// Read input files.
622-
std::string input;
623-
if (!read_input(&config, &input)) {
624-
jsonnet_destroy(vm);
625-
return EXIT_FAILURE;
626-
}
627-
628631
// Evaluate input Jsonnet and handle any errors from Jsonnet VM.
629632
int error;
630633
char *output;
631634
switch (config.cmd) {
632635
case EVAL: {
636+
assert(config.inputFiles.size() == 1);
637+
638+
// Read input file.
639+
std::string input;
640+
if (!read_input(&config, 0, &input)) {
641+
jsonnet_destroy(vm);
642+
return EXIT_FAILURE;
643+
}
644+
633645
if (config.evalMulti) {
634646
output = jsonnet_evaluate_snippet_multi(
635-
vm, config.inputFile.c_str(), input.c_str(), &error);
647+
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
636648
} else if (config.evalStream) {
637649
output = jsonnet_evaluate_snippet_stream(
638-
vm, config.inputFile.c_str(), input.c_str(), &error);
650+
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
639651
} else {
640652
output = jsonnet_evaluate_snippet(
641-
vm, config.inputFile.c_str(), input.c_str(), &error);
653+
vm, config.inputFiles[0].c_str(), input.c_str(), &error);
642654
}
643655

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

674686
case FMT: {
675687
std::string output_file = config.outputFile;
676-
if (config.fmtInPlace) {
677-
if (config.inputFile == "-") {
678-
std::cerr << "ERROR: Cannot use --in-place with stdin" << std::endl;
679-
jsonnet_destroy(vm);
680-
return EXIT_FAILURE;
688+
689+
if (config.fmtInPlace || config.fmtTest) {
690+
assert(config.inputFiles.size() >= 1);
691+
for (std::string inputFile: config.inputFiles) {
692+
if (config.fmtInPlace) {
693+
output_file = inputFile;
694+
695+
if (inputFile == "-") {
696+
std::cerr << "ERROR: Cannot use --in-place with stdin" << std::endl;
697+
jsonnet_destroy(vm);
698+
return EXIT_FAILURE;
699+
}
700+
if (config.filenameIsCode) {
701+
std::cerr << "ERROR: Cannot use --in-place with --exec" << std::endl;
702+
jsonnet_destroy(vm);
703+
return EXIT_FAILURE;
704+
}
705+
}
706+
707+
std::string input;
708+
if (!read_input_contents(inputFile, &input)) {
709+
jsonnet_destroy(vm);
710+
return EXIT_FAILURE;
711+
}
712+
713+
output = jsonnet_fmt_snippet(vm, inputFile.c_str(), input.c_str(), &error);
714+
715+
if (error) {
716+
std::cerr << output;
717+
std::cerr.flush();
718+
jsonnet_realloc(vm, output, 0);
719+
jsonnet_destroy(vm);
720+
return EXIT_FAILURE;
721+
}
722+
723+
if (config.fmtTest) {
724+
// Check the output matches the input.
725+
bool ok = output == input;
726+
jsonnet_realloc(vm, output, 0);
727+
jsonnet_destroy(vm);
728+
return ok ? EXIT_SUCCESS : 2;
729+
} else {
730+
// Write output Jsonnet.
731+
bool successful = write_output_file(output, output_file);
732+
jsonnet_realloc(vm, output, 0);
733+
if (!successful) {
734+
jsonnet_destroy(vm);
735+
return EXIT_FAILURE;
736+
}
737+
}
681738
}
682-
if (config.filenameIsCode) {
683-
std::cerr << "ERROR: Cannot use --in-place with --exec" << std::endl;
739+
} else {
740+
assert(config.inputFiles.size() == 1);
741+
// Read input file.
742+
std::string input;
743+
if (!read_input(&config, 0, &input)) {
684744
jsonnet_destroy(vm);
685745
return EXIT_FAILURE;
686746
}
687-
output_file = config.inputFile;
688-
}
689747

690-
output = jsonnet_fmt_snippet(vm, config.inputFile.c_str(), input.c_str(), &error);
748+
output = jsonnet_fmt_snippet(vm, config.inputFiles[0].c_str(), input.c_str(), &error);
691749

692-
if (error) {
693-
std::cerr << output;
694-
std::cerr.flush();
695-
jsonnet_realloc(vm, output, 0);
696-
jsonnet_destroy(vm);
697-
return EXIT_FAILURE;
698-
}
699-
700-
if (config.fmtTest) {
701-
// Check the output matches the input.
702-
bool ok = output == input;
703-
jsonnet_realloc(vm, output, 0);
704-
jsonnet_destroy(vm);
705-
return ok ? EXIT_SUCCESS : 2;
750+
if (error) {
751+
std::cerr << output;
752+
std::cerr.flush();
753+
jsonnet_realloc(vm, output, 0);
754+
jsonnet_destroy(vm);
755+
return EXIT_FAILURE;
756+
}
706757

707-
} else {
708758
// Write output Jsonnet.
709759
bool successful = write_output_file(output, output_file);
710760
jsonnet_realloc(vm, output, 0);

0 commit comments

Comments
 (0)