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 <stddef.h>
6
7 #include <algorithm>
8 #include <memory>
9 #include <set>
10 #include <sstream>
11
12 #include "base/command_line.h"
13 #include "base/json/json_writer.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "gn/commands.h"
17 #include "gn/config.h"
18 #include "gn/desc_builder.h"
19 #include "gn/rust_variables.h"
20 #include "gn/setup.h"
21 #include "gn/standard_out.h"
22 #include "gn/swift_variables.h"
23 #include "gn/switches.h"
24 #include "gn/target.h"
25 #include "gn/variables.h"
26
27 namespace commands {
28
29 namespace {
30
31 // Desc-specific command line switches.
32 const char kBlame[] = "blame";
33 const char kTree[] = "tree";
34 const char kAll[] = "all";
35
PrintDictValue(const base::Value * value,int indentLevel,bool use_first_indent)36 void PrintDictValue(const base::Value* value,
37 int indentLevel,
38 bool use_first_indent) {
39 std::string indent(indentLevel * 2, ' ');
40 const base::ListValue* list_value = nullptr;
41 const base::DictionaryValue* dict_value = nullptr;
42 std::string string_value;
43 bool bool_value = false;
44 int int_value = 0;
45 if (use_first_indent)
46 OutputString(indent);
47 if (value->GetAsList(&list_value)) {
48 OutputString("[\n");
49 bool first = true;
50 for (const auto& v : *list_value) {
51 if (!first)
52 OutputString(",\n");
53 PrintDictValue(&v, indentLevel + 1, true);
54 first = false;
55 }
56 OutputString("\n" + indent + "]");
57 } else if (value->GetAsString(&string_value)) {
58 OutputString("\"" + string_value + "\"");
59 } else if (value->GetAsBoolean(&bool_value)) {
60 OutputString(bool_value ? "true" : "false");
61 } else if (value->GetAsDictionary(&dict_value)) {
62 OutputString("{\n");
63 std::string indent_plus_one((indentLevel + 1) * 2, ' ');
64 base::DictionaryValue::Iterator iter(*dict_value);
65 bool first = true;
66 while (!iter.IsAtEnd()) {
67 if (!first)
68 OutputString(",\n");
69 OutputString(indent_plus_one + iter.key() + " = ");
70 PrintDictValue(&iter.value(), indentLevel + 1, false);
71 iter.Advance();
72 first = false;
73 }
74 OutputString("\n" + indent + "}");
75 } else if (value->GetAsInteger(&int_value)) {
76 OutputString(base::IntToString(int_value));
77 } else if (value->is_none()) {
78 OutputString("<null>");
79 }
80 }
81
82 // Prints value with specified indentation level
PrintValue(const base::Value * value,int indentLevel)83 void PrintValue(const base::Value* value, int indentLevel) {
84 std::string indent(indentLevel * 2, ' ');
85 const base::ListValue* list_value = nullptr;
86 const base::DictionaryValue* dict_value = nullptr;
87 std::string string_value;
88 bool bool_value = false;
89 int int_value = 0;
90 if (value->GetAsList(&list_value)) {
91 for (const auto& v : *list_value) {
92 PrintValue(&v, indentLevel);
93 }
94 } else if (value->GetAsString(&string_value)) {
95 OutputString(indent);
96 OutputString(string_value);
97 OutputString("\n");
98 } else if (value->GetAsBoolean(&bool_value)) {
99 OutputString(indent);
100 OutputString(bool_value ? "true" : "false");
101 OutputString("\n");
102 } else if (value->GetAsDictionary(&dict_value)) {
103 base::DictionaryValue::Iterator iter(*dict_value);
104 while (!iter.IsAtEnd()) {
105 OutputString(indent + iter.key() + "\n");
106 PrintValue(&iter.value(), indentLevel + 1);
107 iter.Advance();
108 }
109 } else if (value->GetAsInteger(&int_value)) {
110 OutputString(indent);
111 OutputString(base::IntToString(int_value));
112 OutputString("\n");
113 } else if (value->is_none()) {
114 OutputString(indent + "<null>\n");
115 }
116 }
117
118 // Default handler for property
DefaultHandler(const std::string & name,const base::Value * value,bool value_only)119 void DefaultHandler(const std::string& name,
120 const base::Value* value,
121 bool value_only) {
122 if (value_only) {
123 PrintValue(value, 0);
124 return;
125 }
126 OutputString("\n");
127 OutputString(name);
128 OutputString("\n");
129 PrintValue(value, 1);
130 }
131
132 // Specific handler for properties that need different treatment
133
134 // Prints the dict in GN scope-sytle.
MetadataHandler(const std::string & name,const base::Value * value,bool value_only)135 void MetadataHandler(const std::string& name,
136 const base::Value* value,
137 bool value_only) {
138 if (value_only) {
139 PrintDictValue(value, 0, true);
140 OutputString("\n");
141 return;
142 }
143 OutputString("\n");
144 OutputString(name);
145 OutputString("\n");
146 PrintDictValue(value, 1, true);
147 OutputString("\n");
148 }
149
150 // Prints label and property value on one line, capitalizing the label.
LabelHandler(const std::string & name,const base::Value * value,bool value_only)151 void LabelHandler(const std::string& name,
152 const base::Value* value,
153 bool value_only) {
154 if (value_only) {
155 PrintValue(value, 0);
156 return;
157 }
158 std::string label = name;
159 label[0] = base::ToUpperASCII(label[0]);
160 std::string string_value;
161 if (value->GetAsString(&string_value)) {
162 OutputString(name + ": ", DECORATION_YELLOW);
163 OutputString(string_value + "\n");
164 }
165 }
166
VisibilityHandler(const std::string & name,const base::Value * value,bool value_only)167 void VisibilityHandler(const std::string& name,
168 const base::Value* value,
169 bool value_only) {
170 if (value_only) {
171 PrintValue(value, 0);
172 return;
173 }
174 const base::ListValue* list;
175 if (value->GetAsList(&list)) {
176 if (list->empty()) {
177 base::Value str("(no visibility)");
178 DefaultHandler(name, &str, value_only);
179 } else {
180 DefaultHandler(name, value, value_only);
181 }
182 }
183 }
184
PublicHandler(const std::string & name,const base::Value * value,bool value_only)185 void PublicHandler(const std::string& name,
186 const base::Value* value,
187 bool value_only) {
188 if (value_only) {
189 PrintValue(value, 0);
190 return;
191 }
192 std::string p;
193 if (value->GetAsString(&p)) {
194 if (p == "*") {
195 base::Value str("[All headers listed in the sources are public.]");
196 DefaultHandler(name, &str, value_only);
197 return;
198 }
199 }
200 DefaultHandler(name, value, value_only);
201 }
202
ConfigsHandler(const std::string & name,const base::Value * value,bool value_only)203 void ConfigsHandler(const std::string& name,
204 const base::Value* value,
205 bool value_only) {
206 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
207 if (tree)
208 DefaultHandler(name + " tree (in order applying)", value, value_only);
209 else
210 DefaultHandler(name + " (in order applying, try also --tree)", value,
211 value_only);
212 }
213
DepsHandler(const std::string & name,const base::Value * value,bool value_only)214 void DepsHandler(const std::string& name,
215 const base::Value* value,
216 bool value_only) {
217 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
218 bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
219 if (tree) {
220 DefaultHandler("Dependency tree", value, value_only);
221 } else {
222 if (!all) {
223 DefaultHandler(
224 "Direct dependencies "
225 "(try also \"--all\", \"--tree\", or even \"--all --tree\")",
226 value, value_only);
227 } else {
228 DefaultHandler("All recursive dependencies", value, value_only);
229 }
230 }
231 }
232
233 // Outputs need special processing when output patterns are present.
ProcessOutputs(base::DictionaryValue * target,bool files_only)234 void ProcessOutputs(base::DictionaryValue* target, bool files_only) {
235 base::ListValue* patterns = nullptr;
236 base::ListValue* outputs = nullptr;
237 target->GetList("output_patterns", &patterns);
238 target->GetList(variables::kOutputs, &outputs);
239
240 int indent = 0;
241 if (outputs || patterns) {
242 if (!files_only) {
243 OutputString("\noutputs\n");
244 indent = 1;
245 }
246 if (patterns) {
247 if (!files_only) {
248 OutputString(" Output patterns\n");
249 indent = 2;
250 }
251 PrintValue(patterns, indent);
252 if (!files_only)
253 OutputString("\n Resolved output file list\n");
254 }
255 if (outputs)
256 PrintValue(outputs, indent);
257
258 target->Remove("output_patterns", nullptr);
259 target->Remove(variables::kOutputs, nullptr);
260 }
261 }
262
263 using DescHandlerFunc = void (*)(const std::string& name,
264 const base::Value* value,
265 bool value_only);
GetHandlers()266 std::map<std::string, DescHandlerFunc> GetHandlers() {
267 return {{"type", LabelHandler},
268 {"toolchain", LabelHandler},
269 {variables::kVisibility, VisibilityHandler},
270 {variables::kMetadata, MetadataHandler},
271 {variables::kTestonly, DefaultHandler},
272 {variables::kCheckIncludes, DefaultHandler},
273 {variables::kAllowCircularIncludesFrom, DefaultHandler},
274 {variables::kSources, DefaultHandler},
275 {variables::kPublic, PublicHandler},
276 {variables::kInputs, DefaultHandler},
277 {variables::kConfigs, ConfigsHandler},
278 {variables::kPublicConfigs, ConfigsHandler},
279 {variables::kAllDependentConfigs, ConfigsHandler},
280 {variables::kScript, DefaultHandler},
281 {variables::kArgs, DefaultHandler},
282 {variables::kDepfile, DefaultHandler},
283 {"bundle_data", DefaultHandler},
284 {variables::kArflags, DefaultHandler},
285 {variables::kAsmflags, DefaultHandler},
286 {variables::kCflags, DefaultHandler},
287 {variables::kCflagsC, DefaultHandler},
288 {variables::kCflagsCC, DefaultHandler},
289 {variables::kCflagsObjC, DefaultHandler},
290 {variables::kCflagsObjCC, DefaultHandler},
291 {variables::kDefines, DefaultHandler},
292 {variables::kFrameworkDirs, DefaultHandler},
293 {variables::kFrameworks, DefaultHandler},
294 {variables::kIncludeDirs, DefaultHandler},
295 {variables::kLdflags, DefaultHandler},
296 {variables::kPrecompiledHeader, DefaultHandler},
297 {variables::kPrecompiledSource, DefaultHandler},
298 {variables::kDeps, DepsHandler},
299 {variables::kGenDeps, DefaultHandler},
300 {variables::kLibs, DefaultHandler},
301 {variables::kLibDirs, DefaultHandler},
302 {variables::kDataKeys, DefaultHandler},
303 {variables::kRebase, DefaultHandler},
304 {variables::kWalkKeys, DefaultHandler},
305 {variables::kWeakFrameworks, DefaultHandler},
306 {variables::kWriteOutputConversion, DefaultHandler},
307 {variables::kRustCrateName, DefaultHandler},
308 {variables::kRustCrateRoot, DefaultHandler},
309 {variables::kSwiftModuleName, DefaultHandler},
310 {variables::kSwiftBridgeHeader, DefaultHandler},
311 {"runtime_deps", DefaultHandler}};
312 }
313
HandleProperty(const std::string & what,const std::map<std::string,DescHandlerFunc> & handler_map,std::unique_ptr<base::Value> & v,std::unique_ptr<base::DictionaryValue> & dict)314 void HandleProperty(const std::string& what,
315 const std::map<std::string, DescHandlerFunc>& handler_map,
316 std::unique_ptr<base::Value>& v,
317 std::unique_ptr<base::DictionaryValue>& dict) {
318 if (dict->Remove(what, &v)) {
319 auto pair = handler_map.find(what);
320 if (pair != handler_map.end())
321 pair->second(what, v.get(), false);
322 }
323 }
324
PrintTarget(const Target * target,const std::string & what,bool single_target,const std::map<std::string,DescHandlerFunc> & handler_map,bool all,bool tree,bool blame)325 bool PrintTarget(const Target* target,
326 const std::string& what,
327 bool single_target,
328 const std::map<std::string, DescHandlerFunc>& handler_map,
329 bool all,
330 bool tree,
331 bool blame) {
332 std::unique_ptr<base::DictionaryValue> dict =
333 DescBuilder::DescriptionForTarget(target, what, all, tree, blame);
334 if (!what.empty() && dict->empty()) {
335 OutputString("Don't know how to display \"" + what + "\" for \"" +
336 Target::GetStringForOutputType(target->output_type()) +
337 "\".\n");
338 return false;
339 }
340 // Print single value
341 if (!what.empty() && dict->size() == 1 && single_target) {
342 if (what == variables::kOutputs) {
343 ProcessOutputs(dict.get(), true);
344 return true;
345 }
346 base::DictionaryValue::Iterator iter(*dict);
347 auto pair = handler_map.find(what);
348 if (pair != handler_map.end())
349 pair->second(what, &iter.value(), true);
350 return true;
351 }
352
353 OutputString("Target ", DECORATION_YELLOW);
354 OutputString(target->label().GetUserVisibleName(false));
355 OutputString("\n");
356
357 std::unique_ptr<base::Value> v;
358 // Entries with DefaultHandler are present to enforce order
359 HandleProperty("type", handler_map, v, dict);
360 HandleProperty("toolchain", handler_map, v, dict);
361 HandleProperty(variables::kSwiftModuleName, handler_map, v, dict);
362 HandleProperty(variables::kRustCrateName, handler_map, v, dict);
363 HandleProperty(variables::kRustCrateRoot, handler_map, v, dict);
364 HandleProperty(variables::kVisibility, handler_map, v, dict);
365 HandleProperty(variables::kMetadata, handler_map, v, dict);
366 HandleProperty(variables::kTestonly, handler_map, v, dict);
367 HandleProperty(variables::kCheckIncludes, handler_map, v, dict);
368 HandleProperty(variables::kAllowCircularIncludesFrom, handler_map, v, dict);
369 HandleProperty(variables::kSources, handler_map, v, dict);
370 HandleProperty(variables::kSwiftBridgeHeader, handler_map, v, dict);
371 HandleProperty(variables::kPublic, handler_map, v, dict);
372 HandleProperty(variables::kInputs, handler_map, v, dict);
373 HandleProperty(variables::kConfigs, handler_map, v, dict);
374 HandleProperty(variables::kPublicConfigs, handler_map, v, dict);
375 HandleProperty(variables::kAllDependentConfigs, handler_map, v, dict);
376 HandleProperty(variables::kScript, handler_map, v, dict);
377 HandleProperty(variables::kArgs, handler_map, v, dict);
378 HandleProperty(variables::kDepfile, handler_map, v, dict);
379 ProcessOutputs(dict.get(), false);
380 HandleProperty("bundle_data", handler_map, v, dict);
381 HandleProperty(variables::kArflags, handler_map, v, dict);
382 HandleProperty(variables::kAsmflags, handler_map, v, dict);
383 HandleProperty(variables::kCflags, handler_map, v, dict);
384 HandleProperty(variables::kCflagsC, handler_map, v, dict);
385 HandleProperty(variables::kCflagsCC, handler_map, v, dict);
386 HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
387 HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
388 HandleProperty(variables::kSwiftflags, handler_map, v, dict);
389 HandleProperty(variables::kDefines, handler_map, v, dict);
390 HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
391 HandleProperty(variables::kFrameworks, handler_map, v, dict);
392 HandleProperty(variables::kIncludeDirs, handler_map, v, dict);
393 HandleProperty(variables::kLdflags, handler_map, v, dict);
394 HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict);
395 HandleProperty(variables::kPrecompiledSource, handler_map, v, dict);
396 HandleProperty(variables::kDeps, handler_map, v, dict);
397 HandleProperty(variables::kLibs, handler_map, v, dict);
398 HandleProperty(variables::kLibDirs, handler_map, v, dict);
399 HandleProperty(variables::kDataKeys, handler_map, v, dict);
400 HandleProperty(variables::kRebase, handler_map, v, dict);
401 HandleProperty(variables::kWalkKeys, handler_map, v, dict);
402 HandleProperty(variables::kWeakFrameworks, handler_map, v, dict);
403 HandleProperty(variables::kWriteOutputConversion, handler_map, v, dict);
404
405 #undef HandleProperty
406
407 // Process the rest (if any)
408 base::DictionaryValue::Iterator iter(*dict);
409 while (!iter.IsAtEnd()) {
410 DefaultHandler(iter.key(), &iter.value(), false);
411 iter.Advance();
412 }
413
414 return true;
415 }
416
PrintConfig(const Config * config,const std::string & what,bool single_config,const std::map<std::string,DescHandlerFunc> & handler_map)417 bool PrintConfig(const Config* config,
418 const std::string& what,
419 bool single_config,
420 const std::map<std::string, DescHandlerFunc>& handler_map) {
421 std::unique_ptr<base::DictionaryValue> dict =
422 DescBuilder::DescriptionForConfig(config, what);
423 if (!what.empty() && dict->empty()) {
424 OutputString("Don't know how to display \"" + what + "\" for a config.\n");
425 return false;
426 }
427 // Print single value
428 if (!what.empty() && dict->size() == 1 && single_config) {
429 base::DictionaryValue::Iterator iter(*dict);
430 auto pair = handler_map.find(what);
431 if (pair != handler_map.end())
432 pair->second(what, &iter.value(), true);
433 return true;
434 }
435
436 OutputString("Config: ", DECORATION_YELLOW);
437 OutputString(config->label().GetUserVisibleName(false));
438 OutputString("\n");
439
440 std::unique_ptr<base::Value> v;
441 HandleProperty("toolchain", handler_map, v, dict);
442 if (!config->configs().empty()) {
443 OutputString(
444 "(This is a composite config, the values below are after the\n"
445 "expansion of the child configs.)\n");
446 }
447 HandleProperty(variables::kArflags, handler_map, v, dict);
448 HandleProperty(variables::kAsmflags, handler_map, v, dict);
449 HandleProperty(variables::kCflags, handler_map, v, dict);
450 HandleProperty(variables::kCflagsC, handler_map, v, dict);
451 HandleProperty(variables::kCflagsCC, handler_map, v, dict);
452 HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
453 HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
454 HandleProperty(variables::kSwiftflags, handler_map, v, dict);
455 HandleProperty(variables::kDefines, handler_map, v, dict);
456 HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
457 HandleProperty(variables::kFrameworks, handler_map, v, dict);
458 HandleProperty(variables::kIncludeDirs, handler_map, v, dict);
459 HandleProperty(variables::kInputs, handler_map, v, dict);
460 HandleProperty(variables::kLdflags, handler_map, v, dict);
461 HandleProperty(variables::kLibs, handler_map, v, dict);
462 HandleProperty(variables::kLibDirs, handler_map, v, dict);
463 HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict);
464 HandleProperty(variables::kPrecompiledSource, handler_map, v, dict);
465 HandleProperty(variables::kWeakFrameworks, handler_map, v, dict);
466
467 #undef HandleProperty
468
469 return true;
470 }
471
472 } // namespace
473
474 // desc ------------------------------------------------------------------------
475
476 const char kDesc[] = "desc";
477 const char kDesc_HelpShort[] =
478 "desc: Show lots of insightful information about a target or config.";
479 const char kDesc_Help[] =
480 R"(gn desc
481
482 gn desc <out_dir> <label or pattern> [<what to show>] [--blame]
483 [--format=json]
484
485 Displays information about a given target or config. The build parameters
486 will be taken for the build in the given <out_dir>.
487
488 The <label or pattern> can be a target label, a config label, or a label
489 pattern (see "gn help label_pattern"). A label pattern will only match
490 targets.
491
492 Possibilities for <what to show>
493
494 (If unspecified an overall summary will be displayed.)
495
496 all_dependent_configs
497 allow_circular_includes_from
498 arflags [--blame]
499 args
500 cflags [--blame]
501 cflags_c [--blame]
502 cflags_cc [--blame]
503 check_includes
504 configs [--tree] (see below)
505 data_keys
506 defines [--blame]
507 depfile
508 deps [--all] [--tree] (see below)
509 framework_dirs
510 frameworks
511 include_dirs [--blame]
512 inputs
513 ldflags [--blame]
514 lib_dirs
515 libs
516 metadata
517 output_conversion
518 outputs
519 public_configs
520 public
521 rebase
522 script
523 sources
524 testonly
525 visibility
526 walk_keys
527 weak_frameworks
528
529 runtime_deps
530 Compute all runtime deps for the given target. This is a computed list
531 and does not correspond to any GN variable, unlike most other values
532 here.
533
534 The output is a list of file names relative to the build directory. See
535 "gn help runtime_deps" for how this is computed. This also works with
536 "--blame" to see the source of the dependency.
537
538 Shared flags
539
540 )"
541
542 DEFAULT_TOOLCHAIN_SWITCH_HELP
543
544 R"(
545 --format=json
546 Format the output as JSON instead of text.
547
548 Target flags
549
550 --blame
551 Used with any value specified on a config, this will name the config that
552 causes that target to get the flag. This doesn't currently work for libs,
553 lib_dirs, frameworks, weak_frameworks and framework_dirs because those are
554 inherited and are more complicated to figure out the blame (patches
555 welcome).
556
557 Configs
558
559 The "configs" section will list all configs that apply. For targets this will
560 include configs specified in the "configs" variable of the target, and also
561 configs pushed onto this target via public or "all dependent" configs.
562
563 Configs can have child configs. Specifying --tree will show the hierarchy.
564
565 Printing outputs
566
567 The "outputs" section will list all outputs that apply, including the outputs
568 computed from the tool definition (eg for "executable", "static_library", ...
569 targets).
570
571 Printing deps
572
573 Deps will include all public, private, and data deps (TODO this could be
574 clarified and enhanced) sorted in order applying. The following may be used:
575
576 --all
577 Collects all recursive dependencies and prints a sorted flat list. Also
578 usable with --tree (see below).
579
580 )"
581
582 TARGET_PRINTING_MODE_COMMAND_LINE_HELP
583 "\n" TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP
584
585 R"(
586 --tree
587 Print a dependency tree. By default, duplicates will be elided with "..."
588 but when --all and -tree are used together, no eliding will be performed.
589
590 The "deps", "public_deps", and "data_deps" will all be included in the
591 tree.
592
593 Tree output can not be used with the filtering or output flags: --as,
594 --type, --testonly.
595
596 )"
597
598 TARGET_TYPE_FILTER_COMMAND_LINE_HELP
599
600 R"(
601 Note
602
603 This command will show the full name of directories and source files, but
604 when directories and source paths are written to the build file, they will be
605 adjusted to be relative to the build directory. So the values for paths
606 displayed by this command won't match (but should mean the same thing).
607
608 Examples
609
610 gn desc out/Debug //base:base
611 Summarizes the given target.
612
613 gn desc out/Foo :base_unittests deps --tree
614 Shows a dependency tree of the "base_unittests" project in
615 the current directory.
616
617 gn desc out/Debug //base defines --blame
618 Shows defines set for the //base:base target, annotated by where
619 each one was set from.
620 )";
621
RunDesc(const std::vector<std::string> & args)622 int RunDesc(const std::vector<std::string>& args) {
623 if (args.size() != 2 && args.size() != 3) {
624 Err(Location(), "Unknown command format. See \"gn help desc\"",
625 "Usage: \"gn desc <out_dir> <target_name> [<what to display>]\"")
626 .PrintToStdout();
627 return 1;
628 }
629 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
630
631 // Deliberately leaked to avoid expensive process teardown.
632 Setup* setup = new Setup;
633 if (!setup->DoSetup(args[0], false))
634 return 1;
635 if (!setup->Run())
636 return 1;
637
638 // Resolve target(s) and config from inputs.
639 UniqueVector<const Target*> target_matches;
640 UniqueVector<const Config*> config_matches;
641 UniqueVector<const Toolchain*> toolchain_matches;
642 UniqueVector<SourceFile> file_matches;
643
644 std::vector<std::string> target_list;
645 target_list.push_back(args[1]);
646
647 if (!ResolveFromCommandLineInput(
648 setup, target_list, cmdline->HasSwitch(switches::kDefaultToolchain),
649 &target_matches, &config_matches, &toolchain_matches, &file_matches))
650 return 1;
651
652 std::string what_to_print;
653 if (args.size() == 3)
654 what_to_print = args[2];
655
656 bool json = cmdline->GetSwitchValueASCII("format") == "json";
657
658 if (target_matches.empty() && config_matches.empty()) {
659 OutputString(
660 "The input " + args[1] + " matches no targets, configs or files.\n",
661 DECORATION_YELLOW);
662 return 1;
663 }
664
665 if (json) {
666 // Convert all targets/configs to JSON, serialize and print them
667 auto res = std::make_unique<base::DictionaryValue>();
668 if (!target_matches.empty()) {
669 for (const auto* target : target_matches) {
670 res->SetWithoutPathExpansion(
671 target->label().GetUserVisibleName(
672 target->settings()->default_toolchain_label()),
673 DescBuilder::DescriptionForTarget(
674 target, what_to_print, cmdline->HasSwitch(kAll),
675 cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
676 }
677 } else if (!config_matches.empty()) {
678 for (const auto* config : config_matches) {
679 res->SetWithoutPathExpansion(
680 config->label().GetUserVisibleName(false),
681 DescBuilder::DescriptionForConfig(config, what_to_print));
682 }
683 }
684 std::string s;
685 base::JSONWriter::WriteWithOptions(
686 *res.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
687 OutputString(s);
688 } else {
689 // Regular (non-json) formatted output
690 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
691 std::map<std::string, DescHandlerFunc> handlers = GetHandlers();
692
693 bool printed_output = false;
694 for (const Target* target : target_matches) {
695 if (printed_output)
696 OutputString("\n\n");
697 printed_output = true;
698
699 if (!PrintTarget(target, what_to_print, !multiple_outputs, handlers,
700 cmdline->HasSwitch(kAll), cmdline->HasSwitch(kTree),
701 cmdline->HasSwitch(kBlame)))
702 return 1;
703 }
704 for (const Config* config : config_matches) {
705 if (printed_output)
706 OutputString("\n\n");
707 printed_output = true;
708
709 if (!PrintConfig(config, what_to_print, !multiple_outputs, handlers))
710 return 1;
711 }
712 }
713
714 return 0;
715 }
716
717 } // namespace commands
718