Correct blacklist entry message
[chromium-blink-merge.git] / tools / gn / command_args.cc
blobc6b7cfb3eb8b3cb451be9efda04f45b446b312eb
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
3 // found in the LICENSE file.
5 #include <map>
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "tools/gn/commands.h"
10 #include "tools/gn/input_file.h"
11 #include "tools/gn/parse_tree.h"
12 #include "tools/gn/setup.h"
13 #include "tools/gn/standard_out.h"
14 #include "tools/gn/tokenizer.h"
16 namespace commands {
18 namespace {
20 bool DoesLineBeginWithComment(const base::StringPiece& line) {
21 // Skip whitespace.
22 size_t i = 0;
23 while (i < line.size() && IsAsciiWhitespace(line[i]))
24 i++;
26 return i < line.size() && line[i] == '#';
29 // Returns the offset of the beginning of the line identified by |offset|.
30 size_t BackUpToLineBegin(const std::string& data, size_t offset) {
31 // Degenerate case of an empty line. Below we'll try to return the
32 // character after the newline, but that will be incorrect in this case.
33 if (offset == 0 || Tokenizer::IsNewline(data, offset))
34 return offset;
36 size_t cur = offset;
37 do {
38 cur --;
39 if (Tokenizer::IsNewline(data, cur))
40 return cur + 1; // Want the first character *after* the newline.
41 } while (cur > 0);
42 return 0;
45 // Assumes DoesLineBeginWithComment().
46 std::string StripCommentFromLine(const base::StringPiece& line) {
47 std::string ret = line.as_string();
48 for (size_t i = 0; i < ret.size(); i++) {
49 if (ret[i] == '#') {
50 ret[i] = ' ';
51 break;
54 return ret;
57 // Tries to find the comment before the setting of the given value.
58 void GetContextForValue(const Value& value,
59 std::string* location_str,
60 std::string* comment) {
61 Location location = value.origin()->GetRange().begin();
62 const InputFile* file = location.file();
63 if (!file)
64 return;
66 *location_str = file->name().value() + ":" +
67 base::IntToString(location.line_number());
69 const std::string& data = file->contents();
70 size_t line_off =
71 Tokenizer::ByteOffsetOfNthLine(data, location.line_number());
73 while (line_off > 1) {
74 line_off -= 2; // Back up to end of previous line.
75 size_t previous_line_offset = BackUpToLineBegin(data, line_off);
77 base::StringPiece line(&data[previous_line_offset],
78 line_off - previous_line_offset + 1);
79 if (!DoesLineBeginWithComment(line))
80 break;
82 comment->insert(0, StripCommentFromLine(line) + "\n");
83 line_off = previous_line_offset;
87 void PrintArgHelp(const base::StringPiece& name, const Value& value) {
88 OutputString(name.as_string(), DECORATION_YELLOW);
89 OutputString(" Default = " + value.ToString(true) + "\n");
91 if (value.origin()) {
92 std::string location, comment;
93 GetContextForValue(value, &location, &comment);
94 OutputString(" " + location + "\n" + comment);
95 } else {
96 OutputString(" (Internally set)\n");
100 } // namespace
102 extern const char kArgs[] = "args";
103 extern const char kArgs_HelpShort[] =
104 "args: Display configurable arguments declared by the build.";
105 extern const char kArgs_Help[] =
106 "gn args [arg name]\n"
107 " Displays all arguments declared by buildfiles along with their\n"
108 " description. Build arguments are anything in a declare_args() block\n"
109 " in any buildfile. The comment preceeding the declaration will be\n"
110 " displayed here (so comment well!).\n"
111 "\n"
112 " These arguments can be overriden on the command-line:\n"
113 " --args=\"doom_melon_setting=5 component_build=1\"\n"
114 " or in a toolchain definition (see \"gn help buildargs\" for more on\n"
115 " how this all works).\n"
116 "\n"
117 " If \"arg name\" is specified, only the information for that argument\n"
118 " will be displayed. Otherwise all arguments will be displayed.\n";
120 int RunArgs(const std::vector<std::string>& args) {
121 Setup* setup = new Setup;
122 setup->set_check_for_bad_items(false);
123 if (!setup->DoSetup() || !setup->Run())
124 return 1;
126 const Scope::KeyValueMap& build_args =
127 setup->build_settings().build_args().declared_arguments();
129 if (args.size() == 1) {
130 // Get help on a specific command.
131 Scope::KeyValueMap::const_iterator found_arg = build_args.find(args[0]);
132 if (found_arg == build_args.end()) {
133 Err(Location(), "Unknown build arg.",
134 "You asked for \"" + args[0] + "\" which I didn't find in any "
135 "buildfile\nassociated with this build.");
136 return 1;
138 PrintArgHelp(args[0], found_arg->second);
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;
147 // List all arguments. First put them in a regular map so they're sorted.
148 std::map<base::StringPiece, Value> sorted_args;
149 for (Scope::KeyValueMap::const_iterator i = build_args.begin();
150 i != build_args.end(); ++i)
151 sorted_args.insert(*i);
153 for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
154 i != sorted_args.end(); ++i) {
155 PrintArgHelp(i->first, i->second);
156 OutputString("\n");
159 return 0;
162 } // namespace commands