| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "tools/gn/commands.h" | 14 #include "tools/gn/commands.h" |
| 15 #include "tools/gn/filesystem_utils.h" | 15 #include "tools/gn/filesystem_utils.h" |
| 16 #include "tools/gn/input_file.h" | 16 #include "tools/gn/input_file.h" |
| 17 #include "tools/gn/parser.h" | 17 #include "tools/gn/parser.h" |
| 18 #include "tools/gn/scheduler.h" | 18 #include "tools/gn/scheduler.h" |
| 19 #include "tools/gn/setup.h" | 19 #include "tools/gn/setup.h" |
| 20 #include "tools/gn/source_file.h" | 20 #include "tools/gn/source_file.h" |
| 21 #include "tools/gn/tokenizer.h" | 21 #include "tools/gn/tokenizer.h" |
| 22 | 22 |
| 23 namespace commands { | 23 namespace commands { |
| 24 | 24 |
| 25 const char kSwitchDryRun[] = "dry-run"; | 25 const char kSwitchDryRun[] = "dry-run"; |
| 26 const char kSwitchDumpTree[] = "dump-tree"; | 26 const char kSwitchDumpTree[] = "dump-tree"; |
| 27 const char kSwitchInPlace[] = "in-place"; | |
| 28 const char kSwitchStdin[] = "stdin"; | 27 const char kSwitchStdin[] = "stdin"; |
| 29 | 28 |
| 30 const char kFormat[] = "format"; | 29 const char kFormat[] = "format"; |
| 31 const char kFormat_HelpShort[] = | 30 const char kFormat_HelpShort[] = |
| 32 "format: Format .gn file."; | 31 "format: Format .gn file."; |
| 33 const char kFormat_Help[] = | 32 const char kFormat_Help[] = |
| 34 "gn format [--dump-tree] [--in-place] [--stdin] BUILD.gn\n" | 33 "gn format [--dump-tree] (--stdin | <build_file>)\n" |
| 35 "\n" | 34 "\n" |
| 36 " Formats .gn file to a standard format.\n" | 35 " Formats .gn file to a standard format.\n" |
| 37 "\n" | 36 "\n" |
| 38 " The contents of some lists ('sources', 'deps', etc.) will be sorted to\n" | 37 " The contents of some lists ('sources', 'deps', etc.) will be sorted to\n" |
| 39 " a canonical order. To suppress this, you can add a comment of the form\n" | 38 " a canonical order. To suppress this, you can add a comment of the form\n" |
| 40 " \"# NOSORT\" immediately preceeding the assignment. e.g.\n" | 39 " \"# NOSORT\" immediately preceeding the assignment. e.g.\n" |
| 41 "\n" | 40 "\n" |
| 42 " # NOSORT\n" | 41 " # NOSORT\n" |
| 43 " sources = [\n" | 42 " sources = [\n" |
| 44 " \"z.cc\",\n" | 43 " \"z.cc\",\n" |
| 45 " \"a.cc\",\n" | 44 " \"a.cc\",\n" |
| 46 " ]\n" | 45 " ]\n" |
| 47 "\n" | 46 "\n" |
| 48 "Arguments\n" | 47 "Arguments\n" |
| 48 "\n" |
| 49 " --dry-run\n" | 49 " --dry-run\n" |
| 50 " Does not change or output anything, but sets the process exit code\n" | 50 " Does not change or output anything, but sets the process exit code\n" |
| 51 " based on whether output would be different than what's on disk.\n" | 51 " based on whether output would be different than what's on disk.\n" |
| 52 " This is useful for presubmit/lint-type checks.\n" | 52 " This is useful for presubmit/lint-type checks.\n" |
| 53 " - Exit code 0: successful format, matches on disk.\n" | 53 " - Exit code 0: successful format, matches on disk.\n" |
| 54 " - Exit code 1: general failure (parse error, etc.)\n" | 54 " - Exit code 1: general failure (parse error, etc.)\n" |
| 55 " - Exit code 2: successful format, but differs from on disk.\n" | 55 " - Exit code 2: successful format, but differs from on disk.\n" |
| 56 "\n" | 56 "\n" |
| 57 " --dump-tree\n" | 57 " --dump-tree\n" |
| 58 " For debugging only, dumps the parse tree.\n" | 58 " For debugging, dumps the parse tree to stdout and does not update\n" |
| 59 "\n" | 59 " the file or print formatted output.\n" |
| 60 " --in-place\n" | |
| 61 " Instead of writing the formatted file to stdout, replace the input\n" | |
| 62 " file with the formatted output. If no reformatting is required,\n" | |
| 63 " the input file will not be touched, and nothing printed.\n" | |
| 64 "\n" | 60 "\n" |
| 65 " --stdin\n" | 61 " --stdin\n" |
| 66 " Read input from stdin (and write to stdout). Not compatible with\n" | 62 " Read input from stdin and write to stdout rather than update\n" |
| 67 " --in-place of course.\n" | 63 " a file in-place.\n" |
| 68 "\n" | 64 "\n" |
| 69 "Examples\n" | 65 "Examples\n" |
| 70 " gn format //some/BUILD.gn\n" | 66 " gn format //some/BUILD.gn\n" |
| 71 " gn format some\\BUILD.gn\n" | 67 " gn format some\\BUILD.gn\n" |
| 72 " gn format /abspath/some/BUILD.gn\n" | 68 " gn format /abspath/some/BUILD.gn\n" |
| 73 " gn format --stdin\n"; | 69 " gn format --stdin\n"; |
| 74 | 70 |
| 75 namespace { | 71 namespace { |
| 76 | 72 |
| 77 const int kIndentSize = 2; | 73 const int kIndentSize = 2; |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 return true; | 913 return true; |
| 918 } | 914 } |
| 919 | 915 |
| 920 return false; | 916 return false; |
| 921 } | 917 } |
| 922 | 918 |
| 923 void DoFormat(const ParseNode* root, bool dump_tree, std::string* output) { | 919 void DoFormat(const ParseNode* root, bool dump_tree, std::string* output) { |
| 924 if (dump_tree) { | 920 if (dump_tree) { |
| 925 std::ostringstream os; | 921 std::ostringstream os; |
| 926 root->Print(os, 0); | 922 root->Print(os, 0); |
| 927 printf("----------------------\n"); | |
| 928 printf("-- PARSE TREE --------\n"); | |
| 929 printf("----------------------\n"); | |
| 930 printf("%s", os.str().c_str()); | 923 printf("%s", os.str().c_str()); |
| 931 printf("----------------------\n"); | |
| 932 } | 924 } |
| 933 Printer pr; | 925 Printer pr; |
| 934 pr.Block(root); | 926 pr.Block(root); |
| 935 *output = pr.String(); | 927 *output = pr.String(); |
| 936 } | 928 } |
| 937 | 929 |
| 938 std::string ReadStdin() { | 930 std::string ReadStdin() { |
| 939 static const int kBufferSize = 256; | 931 static const int kBufferSize = 256; |
| 940 char buffer[kBufferSize]; | 932 char buffer[kBufferSize]; |
| 941 std::string result; | 933 std::string result; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 return true; | 987 return true; |
| 996 } | 988 } |
| 997 | 989 |
| 998 int RunFormat(const std::vector<std::string>& args) { | 990 int RunFormat(const std::vector<std::string>& args) { |
| 999 bool dry_run = | 991 bool dry_run = |
| 1000 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDryRun); | 992 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDryRun); |
| 1001 bool dump_tree = | 993 bool dump_tree = |
| 1002 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDumpTree); | 994 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDumpTree); |
| 1003 bool from_stdin = | 995 bool from_stdin = |
| 1004 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchStdin); | 996 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchStdin); |
| 1005 bool in_place = | |
| 1006 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchInPlace); | |
| 1007 | 997 |
| 1008 if (dry_run) { | 998 if (dry_run) { |
| 1009 // --dry-run only works with an actual file to compare to. | 999 // --dry-run only works with an actual file to compare to. |
| 1010 from_stdin = false; | 1000 from_stdin = false; |
| 1011 in_place = true; | |
| 1012 } | 1001 } |
| 1013 | 1002 |
| 1014 if (from_stdin) { | 1003 if (from_stdin) { |
| 1015 if (args.size() != 0) { | 1004 if (args.size() != 0) { |
| 1016 Err(Location(), "Expecting no arguments when reading from stdin.\n") | 1005 Err(Location(), "Expecting no arguments when reading from stdin.\n") |
| 1017 .PrintToStdout(); | 1006 .PrintToStdout(); |
| 1018 return 1; | 1007 return 1; |
| 1019 } | 1008 } |
| 1020 std::string input = ReadStdin(); | 1009 std::string input = ReadStdin(); |
| 1021 std::string output; | 1010 std::string output; |
| 1022 if (!FormatStringToString(input, dump_tree, &output)) | 1011 if (!FormatStringToString(input, dump_tree, &output)) |
| 1023 return 1; | 1012 return 1; |
| 1024 printf("%s", output.c_str()); | 1013 if (!dump_tree) |
| 1014 printf("%s", output.c_str()); |
| 1025 return 0; | 1015 return 0; |
| 1026 } | 1016 } |
| 1027 | 1017 |
| 1028 // TODO(scottmg): Eventually, this should be a list/spec of files, and they | 1018 // TODO(scottmg): Eventually, this should be a list/spec of files, and they |
| 1029 // should all be done in parallel. | 1019 // should all be done in parallel. |
| 1030 if (args.size() != 1) { | 1020 if (args.size() != 1) { |
| 1031 Err(Location(), "Expecting exactly one argument, see `gn help format`.\n") | 1021 Err(Location(), "Expecting exactly one argument, see `gn help format`.\n") |
| 1032 .PrintToStdout(); | 1022 .PrintToStdout(); |
| 1033 return 1; | 1023 return 1; |
| 1034 } | 1024 } |
| 1035 | 1025 |
| 1036 Setup setup; | 1026 Setup setup; |
| 1037 SourceDir source_dir = | 1027 SourceDir source_dir = |
| 1038 SourceDirForCurrentDirectory(setup.build_settings().root_path()); | 1028 SourceDirForCurrentDirectory(setup.build_settings().root_path()); |
| 1039 | 1029 |
| 1040 Err err; | 1030 Err err; |
| 1041 SourceFile file = source_dir.ResolveRelativeFile(Value(nullptr, args[0]), | 1031 SourceFile file = source_dir.ResolveRelativeFile(Value(nullptr, args[0]), |
| 1042 &err); | 1032 &err); |
| 1043 if (err.has_error()) { | 1033 if (err.has_error()) { |
| 1044 err.PrintToStdout(); | 1034 err.PrintToStdout(); |
| 1045 return 1; | 1035 return 1; |
| 1046 } | 1036 } |
| 1047 | 1037 |
| 1048 std::string output_string; | 1038 std::string output_string; |
| 1049 if (FormatFileToString(&setup, file, dump_tree, &output_string)) { | 1039 if (FormatFileToString(&setup, file, dump_tree, &output_string)) { |
| 1050 if (in_place) { | 1040 if (!dump_tree) { |
| 1041 // Update the file in-place. |
| 1051 base::FilePath to_write = setup.build_settings().GetFullPath(file); | 1042 base::FilePath to_write = setup.build_settings().GetFullPath(file); |
| 1052 std::string original_contents; | 1043 std::string original_contents; |
| 1053 if (!base::ReadFileToString(to_write, &original_contents)) { | 1044 if (!base::ReadFileToString(to_write, &original_contents)) { |
| 1054 Err(Location(), std::string("Couldn't read \"") + | 1045 Err(Location(), std::string("Couldn't read \"") + |
| 1055 to_write.AsUTF8Unsafe() + | 1046 to_write.AsUTF8Unsafe() + |
| 1056 std::string("\" for comparison.")).PrintToStdout(); | 1047 std::string("\" for comparison.")).PrintToStdout(); |
| 1057 return 1; | 1048 return 1; |
| 1058 } | 1049 } |
| 1059 if (dry_run) | 1050 if (dry_run) |
| 1060 return original_contents == output_string ? 0 : 2; | 1051 return original_contents == output_string ? 0 : 2; |
| 1061 if (original_contents != output_string) { | 1052 if (original_contents != output_string) { |
| 1062 if (base::WriteFile(to_write, | 1053 if (base::WriteFile(to_write, |
| 1063 output_string.data(), | 1054 output_string.data(), |
| 1064 static_cast<int>(output_string.size())) == -1) { | 1055 static_cast<int>(output_string.size())) == -1) { |
| 1065 Err(Location(), | 1056 Err(Location(), |
| 1066 std::string("Failed to write formatted output back to \"") + | 1057 std::string("Failed to write formatted output back to \"") + |
| 1067 to_write.AsUTF8Unsafe() + std::string("\".")).PrintToStdout(); | 1058 to_write.AsUTF8Unsafe() + std::string("\".")).PrintToStdout(); |
| 1068 return 1; | 1059 return 1; |
| 1069 } | 1060 } |
| 1070 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); | 1061 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); |
| 1071 } | 1062 } |
| 1072 } else { | |
| 1073 printf("%s", output_string.c_str()); | |
| 1074 } | 1063 } |
| 1075 } | 1064 } |
| 1076 | 1065 |
| 1077 return 0; | 1066 return 0; |
| 1078 } | 1067 } |
| 1079 | 1068 |
| 1080 } // namespace commands | 1069 } // namespace commands |
| OLD | NEW |