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