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.
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"
20 bool DoesLineBeginWithComment(const base::StringPiece
& line
) {
23 while (i
< line
.size() && IsAsciiWhitespace(line
[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
))
39 if (Tokenizer::IsNewline(data
, cur
))
40 return cur
+ 1; // Want the first character *after* the newline.
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
++) {
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();
66 *location_str
= file
->name().value() + ":" +
67 base::IntToString(location
.line_number());
69 const std::string
& data
= file
->contents();
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
))
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");
92 std::string location
, comment
;
93 GetContextForValue(value
, &location
, &comment
);
94 OutputString(" " + location
+ "\n" + comment
);
96 OutputString(" (Internally set)\n");
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"
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"
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())
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.");
138 PrintArgHelp(args
[0], found_arg
->second
);
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();
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
);
162 } // namespace commands