• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 <algorithm>
6 #include <set>
7 
8 #include "base/command_line.h"
9 #include "base/strings/string_split.h"
10 #include "gn/commands.h"
11 #include "gn/metadata_walk.h"
12 #include "gn/setup.h"
13 #include "gn/standard_out.h"
14 #include "gn/switches.h"
15 #include "gn/target.h"
16 
17 namespace commands {
18 
19 const char kMeta[] = "meta";
20 const char kMeta_HelpShort[] = "meta: List target metadata collection results.";
21 const char kMeta_Help[] =
22     R"(gn meta
23 
24   gn meta <out_dir> <target>* --data=<key>[,<key>*]* [--walk=<key>[,<key>*]*]
25           [--rebase=<dest dir>]
26 
27   Lists collected metaresults of all given targets for the given data key(s),
28   collecting metadata dependencies as specified by the given walk key(s).
29 
30   See `gn help generated_file` for more information on the walk.
31 
32 Arguments
33 
34   <target(s)>
35     A list of target labels from which to initiate the walk.
36 
37   --data
38     A comma-separated list of keys from which to extract data. In each target
39     walked, its metadata scope is checked for the presence of these keys. If
40     present, the contents of those variable in the scope are appended to the
41     results list.
42 
43   --walk (optional)
44     A comma-separated list of keys from which to control the walk. In each
45     target walked, its metadata scope is checked for the presence of any of
46     these keys. If present, the contents of those variables is checked to ensure
47     that it is a label of a valid dependency of the target and then added to the
48     set of targets to walk. If the empty string ("") is present in any of these
49     keys, all deps and data_deps are added to the walk set.
50 
51   --rebase (optional)
52     A destination directory onto which to rebase any paths found. If set, all
53     collected metadata will be rebased onto this path. This option will throw errors
54     if collected metadata is not a list of strings.
55 
56 Examples
57 
58   gn meta out/Debug "//base/foo" --data=files
59       Lists collected metaresults for the `files` key in the //base/foo:foo
60       target and all of its dependency tree.
61 
62   gn meta out/Debug "//base/foo" --data=files,other
63       Lists collected metaresults for the `files` and `other` keys in the
64       //base/foo:foo target and all of its dependency tree.
65 
66   gn meta out/Debug "//base/foo" --data=files --walk=stop
67       Lists collected metaresults for the `files` key in the //base/foo:foo
68       target and all of the dependencies listed in the `stop` key (and so on).
69 
70   gn meta out/Debug "//base/foo" --data=files --rebase="/"
71       Lists collected metaresults for the `files` key in the //base/foo:foo
72       target and all of its dependency tree, rebasing the strings in the `files`
73       key onto the source directory of the target's declaration relative to "/".
74 )";
75 
RunMeta(const std::vector<std::string> & args)76 int RunMeta(const std::vector<std::string>& args) {
77   if (args.size() == 0) {
78     Err(Location(), "Unknown command format. See \"gn help meta\"",
79         "Usage: \"gn meta <out_dir> <target>* --data=<key>[,<key>*] "
80         "[--walk=<key>[,<key>*]*] [--rebase=<dest dir>]\"")
81         .PrintToStdout();
82     return 1;
83   }
84 
85   Setup* setup = new Setup;
86   if (!setup->DoSetup(args[0], false) || !setup->Run())
87     return 1;
88 
89   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
90   std::string rebase_dir = cmdline->GetSwitchValueASCII("rebase");
91   std::string data_keys_str = cmdline->GetSwitchValueASCII("data");
92   std::string walk_keys_str = cmdline->GetSwitchValueASCII("walk");
93 
94   std::vector<std::string> inputs(args.begin() + 1, args.end());
95 
96   UniqueVector<const Target*> targets;
97   for (const auto& input : inputs) {
98     const Target* target = ResolveTargetFromCommandLineString(setup, input);
99     if (!target) {
100       Err(Location(), "Unknown target " + input).PrintToStdout();
101       return 1;
102     }
103     targets.push_back(target);
104   }
105 
106   std::vector<std::string> data_keys = base::SplitString(
107       data_keys_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
108   if (data_keys.empty()) {
109     return 1;
110   }
111   std::vector<std::string> walk_keys = base::SplitString(
112       walk_keys_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
113   Err err;
114   TargetSet targets_walked;
115   SourceDir rebase_source_dir(rebase_dir);
116   // When SourceDir constructor is supplied with an empty string,
117   // a trailing slash will be added. This prevent SourceDir::is_null()
118   // from returning true. Explicitly remove this traling slash here.
119   if (rebase_dir.empty()) {
120     rebase_source_dir = SourceDir();
121   }
122   std::vector<Value> result =
123       WalkMetadata(targets, data_keys, walk_keys, rebase_source_dir,
124                    &targets_walked, &err);
125   if (err.has_error()) {
126     err.PrintToStdout();
127     return 1;
128   }
129 
130   OutputString("Metadata values\n", DECORATION_DIM);
131   for (const auto& value : result)
132     OutputString("\n" + value.ToString(false) + "\n");
133 
134   // TODO(juliehockett): We should have better dep tracing and error support for
135   // this. Also possibly data about where different values came from.
136   OutputString("\nExtracted from:\n", DECORATION_DIM);
137   bool first = true;
138   for (const auto* target : targets_walked) {
139     if (!first) {
140       first = false;
141       OutputString(", ", DECORATION_DIM);
142     }
143     OutputString(target->label().GetUserVisibleName(true) + "\n");
144   }
145   OutputString("\nusing data keys:\n", DECORATION_DIM);
146   first = true;
147   for (const auto& key : data_keys) {
148     if (!first) {
149       first = false;
150       OutputString(", ");
151     }
152     OutputString(key + "\n");
153   }
154   if (!walk_keys.empty()) {
155     OutputString("\nand using walk keys:\n", DECORATION_DIM);
156     first = true;
157     for (const auto& key : walk_keys) {
158       if (!first) {
159         first = false;
160         OutputString(", ");
161       }
162       OutputString(key + "\n");
163     }
164   }
165   return 0;
166 }
167 
168 }  // namespace commands
169