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