Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / tools / gn / command_refs.cc
blobd75ca505136f3d7451530eb688250be404883864
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 <map>
6 #include <set>
8 #include "base/command_line.h"
9 #include "tools/gn/commands.h"
10 #include "tools/gn/deps_iterator.h"
11 #include "tools/gn/filesystem_utils.h"
12 #include "tools/gn/input_file.h"
13 #include "tools/gn/item.h"
14 #include "tools/gn/setup.h"
15 #include "tools/gn/standard_out.h"
16 #include "tools/gn/target.h"
18 namespace commands {
20 namespace {
22 typedef std::set<const Target*> TargetSet;
23 typedef std::vector<const Target*> TargetVector;
25 // Maps targets to the list of targets that depend on them.
26 typedef std::multimap<const Target*, const Target*> DepMap;
28 // Populates the reverse dependency map for the targets in the Setup.
29 void FillDepMap(Setup* setup, DepMap* dep_map) {
30 for (const auto& target : setup->builder()->GetAllResolvedTargets()) {
31 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL))
32 dep_map->insert(std::make_pair(dep_pair.ptr, target));
36 // Returns the file path generating this item.
37 base::FilePath FilePathForItem(const Item* item) {
38 return item->defined_from()->GetRange().begin().file()->physical_name();
41 // Prints the targets which are the result of a query. This list is sorted
42 // and, if as_files is set, the unique filenames matching those targets will
43 // be used.
44 void OutputResultSet(const TargetSet& results, bool as_files) {
45 if (results.empty())
46 return;
48 if (as_files) {
49 // Output the set of unique source files.
50 std::set<std::string> unique_files;
51 for (const auto& cur : results)
52 unique_files.insert(FilePathToUTF8(FilePathForItem(cur)));
54 for (const auto& cur : unique_files)
55 OutputString(cur + "\n");
56 } else {
57 // Output sorted and uniquified list of labels. The set will sort the
58 // labels.
59 std::set<Label> unique_labels;
60 for (const auto& cur : results)
61 unique_labels.insert(cur->label());
63 // Grab the label of the default toolchain from a random target.
64 Label default_tc_label =
65 (*results.begin())->settings()->default_toolchain_label();
67 for (const auto& cur : unique_labels) {
68 // Print toolchain only for ones not in the default toolchain.
69 OutputString(cur.GetUserVisibleName(
70 cur.GetToolchainLabel() != default_tc_label));
71 OutputString("\n");
76 // Forward declatation for function below.
77 void RecursivePrintTargetDeps(const DepMap& dep_map,
78 const Target* target,
79 TargetSet* seen_targets,
80 int indent_level);
82 // Prints the target and its dependencies in tree form. If the set is non-null,
83 // new targets encountered will be added to the set, and if a ref is in the set
84 // already, it will not be recused into. When the set is null, all refs will be
85 // printed.
86 void RecursivePrintTarget(const DepMap& dep_map,
87 const Target* target,
88 TargetSet* seen_targets,
89 int indent_level) {
90 std::string indent(indent_level * 2, ' ');
92 // Only print the toolchain for non-default-toolchain targets.
93 OutputString(indent + target->label().GetUserVisibleName(
94 !target->settings()->is_default()));
96 bool print_children = true;
97 if (seen_targets) {
98 if (seen_targets->find(target) == seen_targets->end()) {
99 // New target, mark it visited.
100 seen_targets->insert(target);
101 } else {
102 // Already seen.
103 print_children = false;
104 // Only print "..." if something is actually elided, which means that
105 // the current target has children.
106 if (dep_map.lower_bound(target) != dep_map.upper_bound(target))
107 OutputString("...");
111 OutputString("\n");
112 if (print_children)
113 RecursivePrintTargetDeps(dep_map, target, seen_targets, indent_level + 1);
116 // Prints refs of the given target (not the target itself). See
117 // RecursivePrintTarget.
118 void RecursivePrintTargetDeps(const DepMap& dep_map,
119 const Target* target,
120 TargetSet* seen_targets,
121 int indent_level) {
122 DepMap::const_iterator dep_begin = dep_map.lower_bound(target);
123 DepMap::const_iterator dep_end = dep_map.upper_bound(target);
124 for (DepMap::const_iterator cur_dep = dep_begin;
125 cur_dep != dep_end; cur_dep++) {
126 RecursivePrintTarget(dep_map, cur_dep->second, seen_targets, indent_level);
130 void RecursiveCollectChildRefs(const DepMap& dep_map,
131 const Target* target,
132 TargetSet* results);
134 // Recursively finds all targets that reference the given one, and additionally
135 // adds the current one to the list.
136 void RecursiveCollectRefs(const DepMap& dep_map,
137 const Target* target,
138 TargetSet* results) {
139 if (results->find(target) != results->end())
140 return; // Already found this target.
141 results->insert(target);
142 RecursiveCollectChildRefs(dep_map, target, results);
145 // Recursively finds all targets that reference the given one.
146 void RecursiveCollectChildRefs(const DepMap& dep_map,
147 const Target* target,
148 TargetSet* results) {
149 DepMap::const_iterator dep_begin = dep_map.lower_bound(target);
150 DepMap::const_iterator dep_end = dep_map.upper_bound(target);
151 for (DepMap::const_iterator cur_dep = dep_begin;
152 cur_dep != dep_end; cur_dep++)
153 RecursiveCollectRefs(dep_map, cur_dep->second, results);
156 bool TargetContainsFile(const Target* target, const SourceFile& file) {
157 for (const auto& cur_file : target->sources()) {
158 if (cur_file == file)
159 return true;
161 for (const auto& cur_file : target->public_headers()) {
162 if (cur_file == file)
163 return true;
165 for (const auto& cur_file : target->inputs()) {
166 if (cur_file == file)
167 return true;
169 for (const auto& cur_file : target->data()) {
170 if (cur_file == file)
171 return true;
173 return false;
176 void GetTargetsContainingFile(Setup* setup,
177 const std::string& input,
178 bool all_toolchains,
179 std::vector<const Target*>* matches) {
180 SourceDir cur_dir =
181 SourceDirForCurrentDirectory(setup->build_settings().root_path());
182 SourceFile file = cur_dir.ResolveRelativeFile(
183 input, setup->build_settings().root_path_utf8());
185 Label default_toolchain = setup->loader()->default_toolchain_label();
187 std::vector<const Target*> all_targets =
188 setup->builder()->GetAllResolvedTargets();
190 for (const auto& target : all_targets) {
191 if (!all_toolchains) {
192 // Only check targets in the default toolchain.
193 if (target->label().GetToolchainLabel() != default_toolchain)
194 continue;
196 if (TargetContainsFile(target, file))
197 matches->push_back(target);
201 } // namespace
203 const char kRefs[] = "refs";
204 const char kRefs_HelpShort[] =
205 "refs: Find stuff referencing a target or file.";
206 const char kRefs_Help[] =
207 "gn refs <out_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n"
208 " [--all-toolchains]\n"
209 "\n"
210 " Finds reverse dependencies (which targets reference something). The\n"
211 " input is either a target label, a target label pattern, or a file\n"
212 " name.\n"
213 "\n"
214 " The <label_pattern> can take exact labels or patterns that match more\n"
215 " than one (although not general regular expressions).\n"
216 " See \"gn help label_pattern\" for details.\n"
217 "\n"
218 " If the input is a file name, the output will be the target(s)\n"
219 " referencing that file (potentially recursively if used with --tree\n"
220 " or --all). By default, only targets from the default toolchain that\n"
221 " reference the file will be listed.\n"
222 "\n"
223 " --all\n"
224 " When used without --tree, will recurse and display all unique\n"
225 " dependencies of the given targets. When used with --tree, turns\n"
226 " off eliding to show a complete tree.\n"
227 "\n"
228 " --all-toolchains\n"
229 " For target patterns, make the label pattern match all toolchains.\n"
230 " If the label pattern does not specify an explicit toolchain,\n"
231 " labels from all toolchains will be matched (normally only the\n"
232 " default toolchain is matched when no toolchain is specified).\n"
233 "\n"
234 " For filename inputs, lists targets from all toolchains that\n"
235 " include the file.\n"
236 "\n"
237 " --files\n"
238 " Output unique filenames referencing a matched target or config.\n"
239 " These will be relative to the source root directory such that they\n"
240 " are suitable for piping to other commands.\n"
241 "\n"
242 " --tree\n"
243 " Outputs a reverse dependency tree from the given target.\n"
244 " Duplicates will be elided. Combine with --all to see a full\n"
245 " dependency tree.\n"
246 "\n"
247 "Examples (target input)\n"
248 "\n"
249 " gn refs out/Debug //tools/gn:gn\n"
250 " Find all targets depending on the given exact target name.\n"
251 "\n"
252 " gn refs out/Debug //base:i18n --files | xargs gvim\n"
253 " Edit all files containing references to //base:i18n\n"
254 "\n"
255 " gn refs out/Debug //base --all\n"
256 " List all targets depending directly or indirectly on //base:base.\n"
257 "\n"
258 " gn refs out/Debug \"//base/*\"\n"
259 " List all targets depending directly on any target in //base or\n"
260 " its subdirectories.\n"
261 "\n"
262 " gn refs out/Debug \"//base:*\"\n"
263 " List all targets depending directly on any target in\n"
264 " //base/BUILD.gn.\n"
265 "\n"
266 " gn refs out/Debug //base --tree\n"
267 " Print a reverse dependency tree of //base:base\n"
268 "\n"
269 "Examples (file input)\n"
270 "\n"
271 " gn refs out/Debug //base/macros.h\n"
272 " Print targets listing //base/macros.h as a source.\n"
273 "\n"
274 " gn refs out/Debug //base/macros.h --tree\n"
275 " Display a reverse dependency tree to get to the given file. This\n"
276 " will show how dependencies will reference that file.\n"
277 "\n"
278 " gn refs out/Debug //base/macros.h --all\n"
279 " Display all unique targets with some dependency path to a target\n"
280 " containing the given file as a source.\n";
282 int RunRefs(const std::vector<std::string>& args) {
283 if (args.size() != 2) {
284 Err(Location(), "You're holding it wrong.",
285 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"")
286 .PrintToStdout();
287 return 1;
290 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
291 bool tree = cmdline->HasSwitch("tree");
292 bool all = cmdline->HasSwitch("all");
293 bool all_toolchains = cmdline->HasSwitch("all-toolchains");
294 bool files = cmdline->HasSwitch("files");
296 Setup* setup = new Setup;
297 setup->set_check_for_bad_items(false);
298 if (!setup->DoSetup(args[0], false) || !setup->Run())
299 return 1;
301 // Figure out the target or targets that the user is querying.
302 bool is_file_input = false;
303 std::vector<const Target*> query;
304 if (!ResolveTargetsFromCommandLinePattern(setup, args[1], all_toolchains,
305 &query))
306 return 1;
307 if (query.empty()) {
308 // If it doesn't match any targets, assume input is file.
309 GetTargetsContainingFile(setup, args[1], all_toolchains, &query);
310 if (query.empty()) {
311 OutputString("\"" + args[1] + "\" matches no targets.\n");
312 return 0;
314 is_file_input = true;
317 // Construct the reverse dependency tree.
318 DepMap dep_map;
319 FillDepMap(setup, &dep_map);
321 // When the input is a file, we want to print the targets in |query|, which
322 // are the things that directly reference the file, but when the input is a
323 // target, we skip that since the user is asking for what reference those.
324 if (tree) {
325 // Output dependency tree.
326 if (files) {
327 Err(nullptr, "--files option can't be used with --tree option.")
328 .PrintToStdout();
329 return 1;
331 if (query.size() != 1) {
332 Err(nullptr, "Query matches more than one target.",
333 "--tree only supports a single target as input.").PrintToStdout();
334 return 1;
336 if (all) {
337 // Recursively print all targets.
338 for (const auto& cur_query : query) {
339 if (is_file_input)
340 RecursivePrintTarget(dep_map, cur_query, nullptr, 0);
341 else
342 RecursivePrintTargetDeps(dep_map, cur_query, nullptr, 0);
344 } else {
345 // Recursively print unique targets.
346 TargetSet seen_targets;
347 for (const auto& cur_query : query) {
348 if (is_file_input)
349 RecursivePrintTarget(dep_map, cur_query, &seen_targets, 0);
350 else
351 RecursivePrintTargetDeps(dep_map, cur_query, &seen_targets, 0);
354 } else if (all) {
355 // Output recursive dependencies, uniquified and flattened.
356 TargetSet results;
357 for (const auto& cur_query : query) {
358 // File inputs also include the top level targets we found.
359 if (is_file_input)
360 results.insert(cur_query);
361 RecursiveCollectChildRefs(dep_map, cur_query, &results);
363 OutputResultSet(results, files);
364 } else {
365 TargetSet results;
366 for (const auto& cur_query : query) {
367 if (is_file_input) {
368 // When querying for a file, output the resolved list of targets only
369 // (don't need to track back any target dependencies).
370 results.insert(cur_query);
371 } else {
372 // When querying for a target, output direct references of everything
373 // in the query.
374 DepMap::const_iterator dep_begin = dep_map.lower_bound(cur_query);
375 DepMap::const_iterator dep_end = dep_map.upper_bound(cur_query);
376 for (DepMap::const_iterator cur_dep = dep_begin;
377 cur_dep != dep_end; cur_dep++)
378 results.insert(cur_dep->second);
381 OutputResultSet(results, files);
384 return 0;
387 } // namespace commands