Hide the "Add new services" menu from Files app when running as dialog.
[chromium-blink-merge.git] / tools / gn / commands.cc
blob3c7ea20ee7b0546daf8b8c1ebb7e19dff3cce876
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 "tools/gn/commands.h"
7 #include "base/command_line.h"
8 #include "tools/gn/builder.h"
9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/item.h"
11 #include "tools/gn/label.h"
12 #include "tools/gn/label_pattern.h"
13 #include "tools/gn/setup.h"
14 #include "tools/gn/standard_out.h"
15 #include "tools/gn/target.h"
17 namespace commands {
19 namespace {
21 // Like above but the input string can be a pattern that matches multiple
22 // targets. If the input does not parse as a pattern, prints and error and
23 // returns false. If the pattern is valid, fills the vector (which might be
24 // empty if there are no matches) and returns true.
26 // If all_toolchains is false, a pattern with an unspecified toolchain will
27 // match the default toolchain only. If true, all toolchains will be matched.
28 bool ResolveTargetsFromCommandLinePattern(
29 Setup* setup,
30 const std::string& label_pattern,
31 bool all_toolchains,
32 std::vector<const Target*>* matches) {
33 Value pattern_value(nullptr, label_pattern);
35 Err err;
36 LabelPattern pattern = LabelPattern::GetPattern(
37 SourceDirForCurrentDirectory(setup->build_settings().root_path()),
38 pattern_value,
39 &err);
40 if (err.has_error()) {
41 err.PrintToStdout();
42 return false;
45 if (!all_toolchains) {
46 // By default a pattern with an empty toolchain will match all toolchains.
47 // If the caller wants to default to the main toolchain only, set it
48 // explicitly.
49 if (pattern.toolchain().is_null()) {
50 // No explicit toolchain set.
51 pattern.set_toolchain(setup->loader()->default_toolchain_label());
55 std::vector<LabelPattern> pattern_vector;
56 pattern_vector.push_back(pattern);
57 FilterTargetsByPatterns(setup->builder()->GetAllResolvedTargets(),
58 pattern_vector, matches);
59 return true;
63 // If there's an error, it will be printed and false will be returned.
64 bool ResolveStringFromCommandLineInput(
65 Setup* setup,
66 const SourceDir& current_dir,
67 const std::string& input,
68 bool all_toolchains,
69 UniqueVector<const Target*>* target_matches,
70 UniqueVector<const Config*>* config_matches,
71 UniqueVector<const Toolchain*>* toolchain_matches,
72 UniqueVector<SourceFile>* file_matches) {
73 if (LabelPattern::HasWildcard(input)) {
74 // For now, only match patterns against targets. It might be nice in the
75 // future to allow the user to specify which types of things they want to
76 // match, but it should probably only match targets by default.
77 std::vector<const Target*> target_match_vector;
78 if (!ResolveTargetsFromCommandLinePattern(setup, input, all_toolchains,
79 &target_match_vector))
80 return false;
81 for (const Target* target : target_match_vector)
82 target_matches->push_back(target);
83 return true;
86 // Try to figure out what this thing is.
87 Err err;
88 Label label = Label::Resolve(current_dir,
89 setup->loader()->default_toolchain_label(),
90 Value(nullptr, input), &err);
91 if (err.has_error()) {
92 // Not a valid label, assume this must be a file.
93 file_matches->push_back(current_dir.ResolveRelativeFile(
94 input, setup->build_settings().root_path_utf8()));
95 return true;
98 const Item* item = setup->builder()->GetItem(label);
99 if (item) {
100 if (const Config* as_config = item->AsConfig())
101 config_matches->push_back(as_config);
102 else if (const Target* as_target = item->AsTarget())
103 target_matches->push_back(as_target);
104 else if (const Toolchain* as_toolchain = item->AsToolchain())
105 toolchain_matches->push_back(as_toolchain);
106 } else {
107 // Not an item, assume this must be a file.
108 file_matches->push_back(current_dir.ResolveRelativeFile(
109 input, setup->build_settings().root_path_utf8()));
112 return true;
115 enum TargetPrintingMode {
116 TARGET_PRINT_BUILDFILE,
117 TARGET_PRINT_LABEL,
118 TARGET_PRINT_OUTPUT,
121 // Retrieves the target printing mode based on the command line flags for the
122 // current process. Returns true on success. On error, prints a message to the
123 // console and returns false.
124 bool GetTargetPrintingMode(TargetPrintingMode* mode) {
125 std::string switch_key = "as";
126 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
128 if (!cmdline->HasSwitch(switch_key)) {
129 // Default to labels.
130 *mode = TARGET_PRINT_LABEL;
131 return true;
134 std::string value = cmdline->GetSwitchValueASCII(switch_key);
135 if (value == "buildfile") {
136 *mode = TARGET_PRINT_BUILDFILE;
137 return true;
139 if (value == "label") {
140 *mode = TARGET_PRINT_LABEL;
141 return true;
143 if (value == "output") {
144 *mode = TARGET_PRINT_OUTPUT;
145 return true;
148 Err(Location(), "Invalid value for \"--as\".",
149 "I was expecting \"buildfile\", \"label\", or \"output\" but you\n"
150 "said \"" + value + "\".").PrintToStdout();
151 return false;
154 // Returns the target type filter based on the command line flags for the
155 // current process. Returns true on success. On error, prints a message to the
156 // console and returns false.
158 // Target::UNKNOWN will be set if there is no filter. Target::ACTION_FOREACH
159 // will never be returned. Code applying the filters should apply Target::ACTION
160 // to both ACTION and ACTION_FOREACH.
161 bool GetTargetTypeFilter(Target::OutputType* type) {
162 std::string switch_key = "type";
163 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
165 if (!cmdline->HasSwitch(switch_key)) {
166 // Default to unknown -> no filtering.
167 *type = Target::UNKNOWN;
168 return true;
171 std::string value = cmdline->GetSwitchValueASCII(switch_key);
172 if (value == "group") {
173 *type = Target::GROUP;
174 return true;
176 if (value == "executable") {
177 *type = Target::EXECUTABLE;
178 return true;
180 if (value == "shared_library") {
181 *type = Target::SHARED_LIBRARY;
182 return true;
184 if (value == "static_library") {
185 *type = Target::STATIC_LIBRARY;
186 return true;
188 if (value == "source_set") {
189 *type = Target::SOURCE_SET;
190 return true;
192 if (value == "copy") {
193 *type = Target::COPY_FILES;
194 return true;
196 if (value == "action") {
197 *type = Target::ACTION;
198 return true;
201 Err(Location(), "Invalid value for \"--type\".").PrintToStdout();
202 return false;
206 // Applies any testonly filtering specified on the command line to the given
207 // target set. On failure, prints an error and returns false.
208 bool ApplyTestonlyFilter(std::vector<const Target*>* targets) {
209 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
210 std::string testonly_key = "testonly";
212 if (targets->empty() || !cmdline->HasSwitch(testonly_key))
213 return true;
215 std::string testonly_value = cmdline->GetSwitchValueASCII(testonly_key);
216 bool testonly = false;
217 if (testonly_value == "true") {
218 testonly = true;
219 } else if (testonly_value != "false") {
220 Err(Location(), "Bad value for --testonly.",
221 "I was expecting --testonly=true or --testonly=false.")
222 .PrintToStdout();
223 return false;
226 // Filter into a copy of the vector, then swap to output.
227 std::vector<const Target*> result;
228 result.reserve(targets->size());
230 for (const Target* target : *targets) {
231 if (target->testonly() == testonly)
232 result.push_back(target);
235 targets->swap(result);
236 return true;
239 // Applies any target type filtering specified on the command line to the given
240 // target set. On failure, prints an error and returns false.
241 bool ApplyTypeFilter(std::vector<const Target*>* targets) {
242 Target::OutputType type = Target::UNKNOWN;
243 if (!GetTargetTypeFilter(&type))
244 return false;
245 if (targets->empty() || type == Target::UNKNOWN)
246 return true; // Nothing to filter out.
248 // Filter into a copy of the vector, then swap to output.
249 std::vector<const Target*> result;
250 result.reserve(targets->size());
252 for (const Target* target : *targets) {
253 // Make "action" also apply to ACTION_FOREACH.
254 if (target->output_type() == type ||
255 (type == Target::ACTION &&
256 target->output_type() == Target::ACTION_FOREACH))
257 result.push_back(target);
260 targets->swap(result);
261 return true;
264 // Returns the file path generating this item.
265 base::FilePath BuildFileForItem(const Item* item) {
266 return item->defined_from()->GetRange().begin().file()->physical_name();
269 void PrintTargetsAsBuildfiles(bool indent,
270 const std::vector<const Target*>& targets) {
271 // Output the set of unique source files.
272 std::set<std::string> unique_files;
273 for (const Target* target : targets)
274 unique_files.insert(FilePathToUTF8(BuildFileForItem(target)));
276 for (const std::string& file : unique_files) {
277 if (indent)
278 OutputString(" ");
279 OutputString(file + "\n");
283 void PrintTargetsAsLabels(bool indent,
284 const std::vector<const Target*>& targets) {
285 // Putting the labels into a set automatically sorts them for us.
286 std::set<Label> unique_labels;
287 for (const auto& target : targets)
288 unique_labels.insert(target->label());
290 // Grab the label of the default toolchain from the first target.
291 Label default_tc_label =
292 targets[0]->settings()->default_toolchain_label();
294 for (const Label& label : unique_labels) {
295 // Print toolchain only for ones not in the default toolchain.
296 if (indent)
297 OutputString(" ");
298 OutputString(label.GetUserVisibleName(
299 label.GetToolchainLabel() != default_tc_label));
300 OutputString("\n");
304 void PrintTargetsAsOutputs(bool indent,
305 const std::vector<const Target*>& targets) {
306 if (targets.empty())
307 return;
309 // Grab the build settings from a random target.
310 const BuildSettings* build_settings =
311 targets[0]->settings()->build_settings();
313 SourceDir current_dir = SourceDirForCurrentDirectory(
314 build_settings->root_path());
315 for (const Target* target : targets) {
316 // Use the link output file if there is one, otherwise fall back to the
317 // dependency output file (for actions, for example).
318 OutputFile output_file = target->link_output_file();
319 if (output_file.value().empty())
320 output_file = target->dependency_output_file();
322 SourceFile output_as_source =
323 output_file.AsSourceFile(build_settings);
324 std::string result = RebasePath(output_as_source.value(), current_dir,
325 build_settings->root_path_utf8());
326 if (indent)
327 OutputString(" ");
328 OutputString(result);
329 OutputString("\n");
333 } // namespace
335 CommandInfo::CommandInfo()
336 : help_short(nullptr),
337 help(nullptr),
338 runner(nullptr) {
341 CommandInfo::CommandInfo(const char* in_help_short,
342 const char* in_help,
343 CommandRunner in_runner)
344 : help_short(in_help_short),
345 help(in_help),
346 runner(in_runner) {
349 const CommandInfoMap& GetCommands() {
350 static CommandInfoMap info_map;
351 if (info_map.empty()) {
352 #define INSERT_COMMAND(cmd) \
353 info_map[k##cmd] = CommandInfo(k##cmd##_HelpShort, \
354 k##cmd##_Help, \
355 &Run##cmd);
357 INSERT_COMMAND(Args)
358 INSERT_COMMAND(Check)
359 INSERT_COMMAND(Clean)
360 INSERT_COMMAND(Desc)
361 INSERT_COMMAND(Gen)
362 INSERT_COMMAND(Format)
363 INSERT_COMMAND(Help)
364 INSERT_COMMAND(Ls)
365 INSERT_COMMAND(Refs)
367 #undef INSERT_COMMAND
369 return info_map;
372 const Target* ResolveTargetFromCommandLineString(
373 Setup* setup,
374 const std::string& label_string) {
375 // Need to resolve the label after we know the default toolchain.
376 Label default_toolchain = setup->loader()->default_toolchain_label();
377 Value arg_value(nullptr, label_string);
378 Err err;
379 Label label = Label::Resolve(SourceDirForCurrentDirectory(
380 setup->build_settings().root_path()),
381 default_toolchain, arg_value, &err);
382 if (err.has_error()) {
383 err.PrintToStdout();
384 return nullptr;
387 const Item* item = setup->builder()->GetItem(label);
388 if (!item) {
389 Err(Location(), "Label not found.",
390 label.GetUserVisibleName(false) + " not found.").PrintToStdout();
391 return nullptr;
394 const Target* target = item->AsTarget();
395 if (!target) {
396 Err(Location(), "Not a target.",
397 "The \"" + label.GetUserVisibleName(false) + "\" thing\n"
398 "is not a target. Somebody should probably implement this command for "
399 "other\nitem types.");
400 return nullptr;
403 return target;
406 bool ResolveFromCommandLineInput(
407 Setup* setup,
408 const std::vector<std::string>& input,
409 bool all_toolchains,
410 UniqueVector<const Target*>* target_matches,
411 UniqueVector<const Config*>* config_matches,
412 UniqueVector<const Toolchain*>* toolchain_matches,
413 UniqueVector<SourceFile>* file_matches) {
414 if (input.empty()) {
415 Err(Location(), "You need to specify a label, file, or pattern.")
416 .PrintToStdout();
417 return false;
420 SourceDir cur_dir =
421 SourceDirForCurrentDirectory(setup->build_settings().root_path());
422 for (const auto& cur : input) {
423 if (!ResolveStringFromCommandLineInput(setup, cur_dir, cur,
424 all_toolchains, target_matches,
425 config_matches, toolchain_matches,
426 file_matches))
427 return false;
429 return true;
432 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
433 const std::vector<LabelPattern>& filter,
434 std::vector<const Target*>* output) {
435 for (const auto& target : input) {
436 for (const auto& pattern : filter) {
437 if (pattern.Matches(target->label())) {
438 output->push_back(target);
439 break;
445 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
446 const std::vector<LabelPattern>& filter,
447 UniqueVector<const Target*>* output) {
448 for (const auto& target : input) {
449 for (const auto& pattern : filter) {
450 if (pattern.Matches(target->label())) {
451 output->push_back(target);
452 break;
458 void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets) {
459 if (targets->empty())
460 return;
462 if (!ApplyTestonlyFilter(targets))
463 return;
464 if (!ApplyTypeFilter(targets))
465 return;
467 TargetPrintingMode printing_mode = TARGET_PRINT_LABEL;
468 if (targets->empty() || !GetTargetPrintingMode(&printing_mode))
469 return;
470 switch (printing_mode) {
471 case TARGET_PRINT_BUILDFILE:
472 PrintTargetsAsBuildfiles(indent, *targets);
473 break;
474 case TARGET_PRINT_LABEL:
475 PrintTargetsAsLabels(indent, *targets);
476 break;
477 case TARGET_PRINT_OUTPUT:
478 PrintTargetsAsOutputs(indent, *targets);
479 break;
483 void FilterAndPrintTargetSet(bool indent,
484 const std::set<const Target*>& targets) {
485 std::vector<const Target*> target_vector(targets.begin(), targets.end());
486 FilterAndPrintTargets(indent, &target_vector);
489 } // namespace commands