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 |