Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: tools/gn/command_args.cc

Issue 265693003: Redo GN "args" command (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: windows Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 <stdio.h>
6 #include <stdlib.h>
7
5 #include <map> 8 #include <map>
6 9
10 #include "base/command_line.h"
11 #include "base/environment.h"
12 #include "base/file_util.h"
13 #include "base/process/launch.h"
7 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
9 #include "tools/gn/commands.h" 16 #include "tools/gn/commands.h"
17 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/input_file.h" 18 #include "tools/gn/input_file.h"
11 #include "tools/gn/parse_tree.h" 19 #include "tools/gn/parse_tree.h"
12 #include "tools/gn/setup.h" 20 #include "tools/gn/setup.h"
13 #include "tools/gn/standard_out.h" 21 #include "tools/gn/standard_out.h"
14 #include "tools/gn/tokenizer.h" 22 #include "tools/gn/tokenizer.h"
23 #include "tools/gn/trace.h"
24
25 #if defined(OS_WIN)
26 #include <windows.h>
27 #include <shellapi.h>
28 #endif
15 29
16 namespace commands { 30 namespace commands {
17 31
18 namespace { 32 namespace {
19 33
34 const char kSwitchList[] = "list";
35 const char kSwitchShort[] = "short";
36
20 bool DoesLineBeginWithComment(const base::StringPiece& line) { 37 bool DoesLineBeginWithComment(const base::StringPiece& line) {
21 // Skip whitespace. 38 // Skip whitespace.
22 size_t i = 0; 39 size_t i = 0;
23 while (i < line.size() && IsAsciiWhitespace(line[i])) 40 while (i < line.size() && IsAsciiWhitespace(line[i]))
24 i++; 41 i++;
25 42
26 return i < line.size() && line[i] == '#'; 43 return i < line.size() && line[i] == '#';
27 } 44 }
28 45
29 // Returns the offset of the beginning of the line identified by |offset|. 46 // Returns the offset of the beginning of the line identified by |offset|.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 105
89 if (value.origin()) { 106 if (value.origin()) {
90 std::string location, comment; 107 std::string location, comment;
91 GetContextForValue(value, &location, &comment); 108 GetContextForValue(value, &location, &comment);
92 OutputString(" " + location + "\n" + comment); 109 OutputString(" " + location + "\n" + comment);
93 } else { 110 } else {
94 OutputString(" (Internally set)\n"); 111 OutputString(" (Internally set)\n");
95 } 112 }
96 } 113 }
97 114
98 } // namespace 115 int ListArgs(const std::string& build_dir) {
99
100 extern const char kArgs[] = "args";
101 extern const char kArgs_HelpShort[] =
102 "args: Display configurable arguments declared by the build.";
103 extern const char kArgs_Help[] =
104 "gn args [arg name]\n"
105 " Displays all arguments declared by buildfiles along with their\n"
106 " description. Build arguments are anything in a declare_args() block\n"
107 " in any buildfile. The comment preceding the declaration will be\n"
108 " displayed here (so comment well!).\n"
109 "\n"
110 " These arguments can be overridden on the command-line:\n"
111 " --args=\"doom_melon_setting=5 component_build=1\"\n"
112 " or in a toolchain definition (see \"gn help buildargs\" for more on\n"
113 " how this all works).\n"
114 "\n"
115 " If \"arg name\" is specified, only the information for that argument\n"
116 " will be displayed. Otherwise all arguments will be displayed.\n";
117
118 int RunArgs(const std::vector<std::string>& args) {
119 Setup* setup = new Setup; 116 Setup* setup = new Setup;
120 setup->set_check_for_bad_items(false); 117 setup->set_check_for_bad_items(false);
121 // TODO(brettw) bug 343726: Use a temporary directory instead of this 118 if (!setup->DoSetup(build_dir) || !setup->Run())
122 // default one to avoid messing up any build that's in there.
123 if (!setup->DoSetup("//out/Default/") || !setup->Run())
124 return 1; 119 return 1;
125 120
126 Scope::KeyValueMap build_args; 121 Scope::KeyValueMap build_args;
127 setup->build_settings().build_args().MergeDeclaredArguments(&build_args); 122 setup->build_settings().build_args().MergeDeclaredArguments(&build_args);
128 123
129 if (args.size() == 1) { 124 // Find all of the arguments we care about. Use a regular map so they're
130 // Get help on a specific command. 125 // sorted nicely when we write them out.
131 Scope::KeyValueMap::const_iterator found_arg = build_args.find(args[0]); 126 std::map<base::StringPiece, Value> sorted_args;
127 std::string list_value =
128 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kSwitchList);
129 if (list_value.empty()) {
130 // List all values.
131 for (Scope::KeyValueMap::const_iterator i = build_args.begin();
132 i != build_args.end(); ++i)
133 sorted_args.insert(*i);
134 } else {
135 // List just the one specified as the parameter to --list.
136 Scope::KeyValueMap::const_iterator found_arg = build_args.find(list_value);
132 if (found_arg == build_args.end()) { 137 if (found_arg == build_args.end()) {
133 Err(Location(), "Unknown build argument.", 138 Err(Location(), "Unknown build argument.",
134 "You asked for \"" + args[0] + "\" which I didn't find in any " 139 "You asked for \"" + list_value + "\" which I didn't find in any "
135 "buildfile\nassociated with this build."); 140 "build file\nassociated with this build.").PrintToStdout();
136 return 1; 141 return 1;
137 } 142 }
138 PrintArgHelp(args[0], found_arg->second); 143 sorted_args.insert(*found_arg);
139 return 0;
140 } else if (args.size() > 1) {
141 // Too many arguments.
142 Err(Location(), "You're holding it wrong.",
143 "Usage: \"gn args [arg name]\"").PrintToStdout();
144 return 1;
145 } 144 }
146 145
147 // List all arguments. First put them in a regular map so they're sorted. 146 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort)) {
148 std::map<base::StringPiece, Value> sorted_args; 147 // Short key=value output.
149 for (Scope::KeyValueMap::const_iterator i = build_args.begin(); 148 for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
150 i != build_args.end(); ++i) 149 i != sorted_args.end(); ++i) {
151 sorted_args.insert(*i); 150 OutputString(i->first.as_string());
151 OutputString(" = ");
152 OutputString(i->second.ToString(true));
153 OutputString("\n");
154 }
155 return 0;
156 }
152 157
153 OutputString( 158 // Long output.
154 "Available build arguments. Note that the which arguments are declared\n"
155 "and their default values may depend on other arguments or the current\n"
156 "platform and architecture. So setting some values may add, remove, or\n"
157 "change the default value of other values.\n\n");
158
159 for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin(); 159 for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
160 i != sorted_args.end(); ++i) { 160 i != sorted_args.end(); ++i) {
161 PrintArgHelp(i->first, i->second); 161 PrintArgHelp(i->first, i->second);
162 OutputString("\n"); 162 OutputString("\n");
163 } 163 }
164 164
165 return 0; 165 return 0;
166 } 166 }
167 167
168 #if defined(OS_WIN)
169
170 void RunEditor(const base::FilePath& file_to_edit) {
171 SHELLEXECUTEINFO info;
172 memset(&info, 0, sizeof(info));
173 info.cbSize = sizeof(info);
174 info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_CLASSNAME;
175 info.lpFile = file_to_edit.value().c_str();
176 info.nShow = SW_SHOW;
177 info.lpClass = L".txt";
178 if (!::ShellExecuteEx(&info)) {
179 Err(Location(), "Couldn't run editor.",
180 "Just edit \"" + FilePathToUTF8(file_to_edit) +
181 "\" manually instead.").PrintToStdout();
182 return;
183 }
184
185 if (!info.hProcess) {
186 // Windows re-used an existing process.
187 OutputString(
188 "File opened in editor, save it and press <Enter> when done.\n");
189 getchar();
190 } else {
191 OutputString("Waiting for editor...\n");
192 ::WaitForSingleObject(info.hProcess, INFINITE);
193 ::CloseHandle(info.hProcess);
194 }
195 }
196
197 #else // POSIX
198
199 void RunEditor(const base::FilePath& file_to_edit) {
200 // Prefer $VISUAL, then $EDITOR, then vi.
201 const char* editor_ptr = getenv("VISUAL");
202 if (!editor_ptr)
203 editor_ptr = getenv("EDITOR");
204 if (!editor_ptr)
205 editor_ptr = "vi";
206
207 std::string cmd(editor_ptr);
208 cmd.append(" \"");
209
210 // Its impossible to do this properly since we don't know the user's shell,
211 // but quoting and escaping internal quotes should handle 99.999% of all
212 // cases.
213 std::string escaped_name = file_to_edit.value();
214 ReplaceSubstringsAfterOffset(&escaped_name, 0, "\"", "\\\"");
215 cmd.append(escaped_name);
216 cmd.push_back('"');
217
218 system(cmd.c_str());
219 }
220
221 #endif
222
223 int EditArgsFile(const std::string& build_dir) {
224 {
225 // Scope the setup. We only use it for some basic state. We'll do the
226 // "real" build below in the gen command.
227 Setup setup;
228 setup.set_check_for_bad_items(false);
229 // Don't fill build arguments. We're about to edit the file which supplies
230 // these in the first place.
231 setup.set_fill_arguments(false);
232 if (!setup.DoSetup(build_dir))
233 return 1;
234
235 // Ensure the file exists. Need to normalize path separators since on
236 // Windows they can come out as forward slashes here, and that conuses some
237 // of the commands.
238 base::FilePath arg_file =
239 setup.build_settings().GetFullPath(setup.GetBuildArgFile())
240 .NormalizePathSeparators();
241 if (!base::PathExists(arg_file)) {
242 std::string argfile_default_contents =
243 "# Build arguments go here. Examples:\n"
244 "# is_debug = false\n"
245 "# crazy_something = \"absolutely\"\n\n";
246 #if defined(OS_WIN)
247 // Use Windows lineendings for this file since it will often open in
248 // Notepad which can't handle Unix ones.
249 ReplaceSubstringsAfterOffset(&argfile_default_contents, 0, "\n", "\r\n");
250 #endif
251 base::WriteFile(arg_file, argfile_default_contents.c_str(),
252 argfile_default_contents.size());
253 }
254
255 ScopedTrace editor_trace(TraceItem::TRACE_SETUP, "Waiting for editor");
256 RunEditor(arg_file);
257 }
258
259 // Now do a normal "gen" command.
260 OutputString("Generating files...\n");
261 std::vector<std::string> gen_commands;
262 gen_commands.push_back(build_dir);
263 return RunGen(gen_commands);
264 }
265
266 } // namespace
267
268 extern const char kArgs[] = "args";
269 extern const char kArgs_HelpShort[] =
270 "args: Display or configure arguments declared by the build.";
271 extern const char kArgs_Help[] =
272 "gn args [arg name]\n"
273 "\n"
274 " See also \"gn help buildargs\" for a more high-level overview of how\n"
275 " build arguments work.\n"
276 "\n"
277 "Usage\n"
278 " gn args <dir_name>\n"
279 " Open the arguments for the given build directory in an editor\n"
280 " (as specified by the EDITOR environment variable). If the given\n"
281 " build directory doesn't exist, it will be created and an empty\n"
282 " args file will be opened in the editor. You would type something\n"
283 " like this into that file:\n"
284 " enable_doom_melon=false\n"
285 " os=\"android\"\n"
286 "\n"
287 " Note: you can edit the build args manually by editing the file\n"
288 " \"gn.args\" in the build directory and then running\n"
289 " \"gn gen <build_dir>\".\n"
290 "\n"
291 " gn args <dir_name> --list[=<exact_arg>] [--short]\n"
292 " Lists all build arguments available in the current configuration,\n"
293 " or, if an exact_arg is specified for the list flag, just that one\n"
294 " build argument.\n"
295 "\n"
296 " The output will list the declaration location, default value, and\n"
297 " comment preceeding the declaration. If --short is specified,\n"
298 " only the names and values will be printed.\n"
299 "\n"
300 " If the dir_name is specified, the build configuration will be\n"
301 " taken from that build directory. The reason this is needed is that\n"
302 " the definition of some arguments is dependent on the build\n"
303 " configuration, so setting some values might add, remove, or change\n"
304 " the default values for other arguments. Specifying your exact\n"
305 " configuration allows the proper arguments to be displayed.\n"
306 "\n"
307 " Instead of specifying the dir_name, you can also use the\n"
308 " command-line flag to specify the build configuration:\n"
309 " --args=<exact list of args to use>\n"
310 "\n"
311 "Examples\n"
312 " gn args out/Debug\n"
313 " Opens an editor with the args for out/Debug.\n"
314 "\n"
315 " gn args out/Debug --list --short\n"
316 " Prints all arguments with their default values for the out/Debug\n"
317 " build.\n"
318 "\n"
319 " gn args out/Debug --list=cpu_arch\n"
320 " Prints information about the \"cpu_arch\" argument for the out/Debug\n"
321 " build.\n"
322 "\n"
323 " gn args --list --args=\"os=\\\"android\\\" enable_doom_melon=true\"\n"
324 " Prints all arguments with the default values for a build with the\n"
325 " given arguments set (which may affect the values of other\n"
326 " arguments).\n";
327
328 int RunArgs(const std::vector<std::string>& args) {
329 if (args.size() != 1) {
330 Err(Location(), "Exactly one build dir needed.",
331 "Usage: \"gn args <build_dir>\"\n"
332 "Or see \"gn help args\" for more variants.").PrintToStdout();
333 return 1;
334 }
335
336 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchList))
337 return ListArgs(args[0]);
338 return EditArgsFile(args[0]);
339 }
340
168 } // namespace commands 341 } // namespace commands
OLDNEW
« tools/gn/args.cc ('K') | « tools/gn/args.cc ('k') | tools/gn/gn.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698