| Index: tools/gn/command_args.cc
|
| diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc
|
| index 72a623f219cacf52d28fd2b06c23887275b31e16..0c72408e3fb5a80c313b5e06b7824f5742ead3d4 100644
|
| --- a/tools/gn/command_args.cc
|
| +++ b/tools/gn/command_args.cc
|
| @@ -2,21 +2,38 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +
|
| #include <map>
|
|
|
| +#include "base/command_line.h"
|
| +#include "base/environment.h"
|
| +#include "base/file_util.h"
|
| +#include "base/process/launch.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "tools/gn/commands.h"
|
| +#include "tools/gn/filesystem_utils.h"
|
| #include "tools/gn/input_file.h"
|
| #include "tools/gn/parse_tree.h"
|
| #include "tools/gn/setup.h"
|
| #include "tools/gn/standard_out.h"
|
| #include "tools/gn/tokenizer.h"
|
| +#include "tools/gn/trace.h"
|
| +
|
| +#if defined(OS_WIN)
|
| +#include <windows.h>
|
| +#include <shellapi.h>
|
| +#endif
|
|
|
| namespace commands {
|
|
|
| namespace {
|
|
|
| +const char kSwitchList[] = "list";
|
| +const char kSwitchShort[] = "short";
|
| +
|
| bool DoesLineBeginWithComment(const base::StringPiece& line) {
|
| // Skip whitespace.
|
| size_t i = 0;
|
| @@ -95,67 +112,50 @@ void PrintArgHelp(const base::StringPiece& name, const Value& value) {
|
| }
|
| }
|
|
|
| -} // namespace
|
| -
|
| -extern const char kArgs[] = "args";
|
| -extern const char kArgs_HelpShort[] =
|
| - "args: Display configurable arguments declared by the build.";
|
| -extern const char kArgs_Help[] =
|
| - "gn args [arg name]\n"
|
| - " Displays all arguments declared by buildfiles along with their\n"
|
| - " description. Build arguments are anything in a declare_args() block\n"
|
| - " in any buildfile. The comment preceding the declaration will be\n"
|
| - " displayed here (so comment well!).\n"
|
| - "\n"
|
| - " These arguments can be overridden on the command-line:\n"
|
| - " --args=\"doom_melon_setting=5 component_build=1\"\n"
|
| - " or in a toolchain definition (see \"gn help buildargs\" for more on\n"
|
| - " how this all works).\n"
|
| - "\n"
|
| - " If \"arg name\" is specified, only the information for that argument\n"
|
| - " will be displayed. Otherwise all arguments will be displayed.\n";
|
| -
|
| -int RunArgs(const std::vector<std::string>& args) {
|
| +int ListArgs(const std::string& build_dir) {
|
| Setup* setup = new Setup;
|
| setup->set_check_for_bad_items(false);
|
| - // TODO(brettw) bug 343726: Use a temporary directory instead of this
|
| - // default one to avoid messing up any build that's in there.
|
| - if (!setup->DoSetup("//out/Default/") || !setup->Run())
|
| + if (!setup->DoSetup(build_dir) || !setup->Run())
|
| return 1;
|
|
|
| Scope::KeyValueMap build_args;
|
| setup->build_settings().build_args().MergeDeclaredArguments(&build_args);
|
|
|
| - if (args.size() == 1) {
|
| - // Get help on a specific command.
|
| - Scope::KeyValueMap::const_iterator found_arg = build_args.find(args[0]);
|
| + // Find all of the arguments we care about. Use a regular map so they're
|
| + // sorted nicely when we write them out.
|
| + std::map<base::StringPiece, Value> sorted_args;
|
| + std::string list_value =
|
| + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kSwitchList);
|
| + if (list_value.empty()) {
|
| + // List all values.
|
| + for (Scope::KeyValueMap::const_iterator i = build_args.begin();
|
| + i != build_args.end(); ++i)
|
| + sorted_args.insert(*i);
|
| + } else {
|
| + // List just the one specified as the parameter to --list.
|
| + Scope::KeyValueMap::const_iterator found_arg = build_args.find(list_value);
|
| if (found_arg == build_args.end()) {
|
| Err(Location(), "Unknown build argument.",
|
| - "You asked for \"" + args[0] + "\" which I didn't find in any "
|
| - "buildfile\nassociated with this build.");
|
| + "You asked for \"" + list_value + "\" which I didn't find in any "
|
| + "build file\nassociated with this build.").PrintToStdout();
|
| return 1;
|
| }
|
| - PrintArgHelp(args[0], found_arg->second);
|
| - return 0;
|
| - } else if (args.size() > 1) {
|
| - // Too many arguments.
|
| - Err(Location(), "You're holding it wrong.",
|
| - "Usage: \"gn args [arg name]\"").PrintToStdout();
|
| - return 1;
|
| + sorted_args.insert(*found_arg);
|
| }
|
|
|
| - // List all arguments. First put them in a regular map so they're sorted.
|
| - std::map<base::StringPiece, Value> sorted_args;
|
| - for (Scope::KeyValueMap::const_iterator i = build_args.begin();
|
| - i != build_args.end(); ++i)
|
| - sorted_args.insert(*i);
|
| -
|
| - OutputString(
|
| - "Available build arguments. Note that the which arguments are declared\n"
|
| - "and their default values may depend on other arguments or the current\n"
|
| - "platform and architecture. So setting some values may add, remove, or\n"
|
| - "change the default value of other values.\n\n");
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort)) {
|
| + // Short key=value output.
|
| + for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
|
| + i != sorted_args.end(); ++i) {
|
| + OutputString(i->first.as_string());
|
| + OutputString(" = ");
|
| + OutputString(i->second.ToString(true));
|
| + OutputString("\n");
|
| + }
|
| + return 0;
|
| + }
|
|
|
| + // Long output.
|
| for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
|
| i != sorted_args.end(); ++i) {
|
| PrintArgHelp(i->first, i->second);
|
| @@ -165,4 +165,177 @@ int RunArgs(const std::vector<std::string>& args) {
|
| return 0;
|
| }
|
|
|
| +#if defined(OS_WIN)
|
| +
|
| +void RunEditor(const base::FilePath& file_to_edit) {
|
| + SHELLEXECUTEINFO info;
|
| + memset(&info, 0, sizeof(info));
|
| + info.cbSize = sizeof(info);
|
| + info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_CLASSNAME;
|
| + info.lpFile = file_to_edit.value().c_str();
|
| + info.nShow = SW_SHOW;
|
| + info.lpClass = L".txt";
|
| + if (!::ShellExecuteEx(&info)) {
|
| + Err(Location(), "Couldn't run editor.",
|
| + "Just edit \"" + FilePathToUTF8(file_to_edit) +
|
| + "\" manually instead.").PrintToStdout();
|
| + return;
|
| + }
|
| +
|
| + if (!info.hProcess) {
|
| + // Windows re-used an existing process.
|
| + OutputString(
|
| + "File opened in editor, save it and press <Enter> when done.\n");
|
| + getchar();
|
| + } else {
|
| + OutputString("Waiting for editor...\n");
|
| + ::WaitForSingleObject(info.hProcess, INFINITE);
|
| + ::CloseHandle(info.hProcess);
|
| + }
|
| +}
|
| +
|
| +#else // POSIX
|
| +
|
| +void RunEditor(const base::FilePath& file_to_edit) {
|
| + // Prefer $VISUAL, then $EDITOR, then vi.
|
| + const char* editor_ptr = getenv("VISUAL");
|
| + if (!editor_ptr)
|
| + editor_ptr = getenv("EDITOR");
|
| + if (!editor_ptr)
|
| + editor_ptr = "vi";
|
| +
|
| + std::string cmd(editor_ptr);
|
| + cmd.append(" \"");
|
| +
|
| + // Its impossible to do this properly since we don't know the user's shell,
|
| + // but quoting and escaping internal quotes should handle 99.999% of all
|
| + // cases.
|
| + std::string escaped_name = file_to_edit.value();
|
| + ReplaceSubstringsAfterOffset(&escaped_name, 0, "\"", "\\\"");
|
| + cmd.append(escaped_name);
|
| + cmd.push_back('"');
|
| +
|
| + system(cmd.c_str());
|
| +}
|
| +
|
| +#endif
|
| +
|
| +int EditArgsFile(const std::string& build_dir) {
|
| + {
|
| + // Scope the setup. We only use it for some basic state. We'll do the
|
| + // "real" build below in the gen command.
|
| + Setup setup;
|
| + setup.set_check_for_bad_items(false);
|
| + // Don't fill build arguments. We're about to edit the file which supplies
|
| + // these in the first place.
|
| + setup.set_fill_arguments(false);
|
| + if (!setup.DoSetup(build_dir))
|
| + return 1;
|
| +
|
| + // Ensure the file exists. Need to normalize path separators since on
|
| + // Windows they can come out as forward slashes here, and that conuses some
|
| + // of the commands.
|
| + base::FilePath arg_file =
|
| + setup.build_settings().GetFullPath(setup.GetBuildArgFile())
|
| + .NormalizePathSeparators();
|
| + if (!base::PathExists(arg_file)) {
|
| + std::string argfile_default_contents =
|
| + "# Build arguments go here. Examples:\n"
|
| + "# is_debug = false\n"
|
| + "# crazy_something = \"absolutely\"\n\n";
|
| +#if defined(OS_WIN)
|
| + // Use Windows lineendings for this file since it will often open in
|
| + // Notepad which can't handle Unix ones.
|
| + ReplaceSubstringsAfterOffset(&argfile_default_contents, 0, "\n", "\r\n");
|
| +#endif
|
| + base::WriteFile(arg_file, argfile_default_contents.c_str(),
|
| + argfile_default_contents.size());
|
| + }
|
| +
|
| + ScopedTrace editor_trace(TraceItem::TRACE_SETUP, "Waiting for editor");
|
| + RunEditor(arg_file);
|
| + }
|
| +
|
| + // Now do a normal "gen" command.
|
| + OutputString("Generating files...\n");
|
| + std::vector<std::string> gen_commands;
|
| + gen_commands.push_back(build_dir);
|
| + return RunGen(gen_commands);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +extern const char kArgs[] = "args";
|
| +extern const char kArgs_HelpShort[] =
|
| + "args: Display or configure arguments declared by the build.";
|
| +extern const char kArgs_Help[] =
|
| + "gn args [arg name]\n"
|
| + "\n"
|
| + " See also \"gn help buildargs\" for a more high-level overview of how\n"
|
| + " build arguments work.\n"
|
| + "\n"
|
| + "Usage\n"
|
| + " gn args <dir_name>\n"
|
| + " Open the arguments for the given build directory in an editor\n"
|
| + " (as specified by the EDITOR environment variable). If the given\n"
|
| + " build directory doesn't exist, it will be created and an empty\n"
|
| + " args file will be opened in the editor. You would type something\n"
|
| + " like this into that file:\n"
|
| + " enable_doom_melon=false\n"
|
| + " os=\"android\"\n"
|
| + "\n"
|
| + " Note: you can edit the build args manually by editing the file\n"
|
| + " \"gn.args\" in the build directory and then running\n"
|
| + " \"gn gen <build_dir>\".\n"
|
| + "\n"
|
| + " gn args <dir_name> --list[=<exact_arg>] [--short]\n"
|
| + " Lists all build arguments available in the current configuration,\n"
|
| + " or, if an exact_arg is specified for the list flag, just that one\n"
|
| + " build argument.\n"
|
| + "\n"
|
| + " The output will list the declaration location, default value, and\n"
|
| + " comment preceeding the declaration. If --short is specified,\n"
|
| + " only the names and values will be printed.\n"
|
| + "\n"
|
| + " If the dir_name is specified, the build configuration will be\n"
|
| + " taken from that build directory. The reason this is needed is that\n"
|
| + " the definition of some arguments is dependent on the build\n"
|
| + " configuration, so setting some values might add, remove, or change\n"
|
| + " the default values for other arguments. Specifying your exact\n"
|
| + " configuration allows the proper arguments to be displayed.\n"
|
| + "\n"
|
| + " Instead of specifying the dir_name, you can also use the\n"
|
| + " command-line flag to specify the build configuration:\n"
|
| + " --args=<exact list of args to use>\n"
|
| + "\n"
|
| + "Examples\n"
|
| + " gn args out/Debug\n"
|
| + " Opens an editor with the args for out/Debug.\n"
|
| + "\n"
|
| + " gn args out/Debug --list --short\n"
|
| + " Prints all arguments with their default values for the out/Debug\n"
|
| + " build.\n"
|
| + "\n"
|
| + " gn args out/Debug --list=cpu_arch\n"
|
| + " Prints information about the \"cpu_arch\" argument for the out/Debug\n"
|
| + " build.\n"
|
| + "\n"
|
| + " gn args --list --args=\"os=\\\"android\\\" enable_doom_melon=true\"\n"
|
| + " Prints all arguments with the default values for a build with the\n"
|
| + " given arguments set (which may affect the values of other\n"
|
| + " arguments).\n";
|
| +
|
| +int RunArgs(const std::vector<std::string>& args) {
|
| + if (args.size() != 1) {
|
| + Err(Location(), "Exactly one build dir needed.",
|
| + "Usage: \"gn args <build_dir>\"\n"
|
| + "Or see \"gn help args\" for more variants.").PrintToStdout();
|
| + return 1;
|
| + }
|
| +
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchList))
|
| + return ListArgs(args[0]);
|
| + return EditArgsFile(args[0]);
|
| +}
|
| +
|
| } // namespace commands
|
|
|