Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / tools / gn / command_args.cc
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.
4
5 #include <map>
6
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"
15
16 namespace commands {
17
18 namespace {
19
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++;
25
26   return i < line.size() && line[i] == '#';
27 }
28
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;
35
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;
43 }
44
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;
52     }
53   }
54   return ret;
55 }
56
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;
65
66   *location_str = file->name().value() + ":" +
67       base::IntToString(location.line_number());
68
69   const std::string& data = file->contents();
70   size_t line_off =
71       Tokenizer::ByteOffsetOfNthLine(data, location.line_number());
72
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);
76
77     base::StringPiece line(&data[previous_line_offset],
78                            line_off - previous_line_offset + 1);
79     if (!DoesLineBeginWithComment(line))
80       break;
81
82     comment->insert(0, StripCommentFromLine(line) + "\n");
83     line_off = previous_line_offset;
84   }
85 }
86
87 void PrintArgHelp(const base::StringPiece& name, const Value& value) {
88   OutputString(name.as_string(), DECORATION_YELLOW);
89   OutputString("  Default = " + value.ToString(true) + "\n");
90
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");
97   }
98 }
99
100 }  // namespace
101
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 preceding the declaration will be\n"
110     "  displayed here (so comment well!).\n"
111     "\n"
112     "  These arguments can be overridden 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";
119
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;
125
126   const Scope::KeyValueMap& build_args =
127       setup->build_settings().build_args().declared_arguments();
128
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 argument.",
134           "You asked for \"" + args[0] + "\" which I didn't find in any "
135           "buildfile\nassociated with this build.");
136       return 1;
137     }
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;
145   }
146
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);
152
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");
157   }
158
159   return 0;
160 }
161
162 }  // namespace commands