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.
7 #include "base/command_line.h"
8 #include "tools/gn/commands.h"
9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/input_file.h"
11 #include "tools/gn/item.h"
12 #include "tools/gn/item_node.h"
13 #include "tools/gn/pattern.h"
14 #include "tools/gn/setup.h"
15 #include "tools/gn/standard_out.h"
16 #include "tools/gn/target.h"
22 // Returns the file path generating this item node.
23 base::FilePath
FilePathForItemNode(const ItemNode
& node
) {
24 const InputFile
* file
= node
.generated_from_here().begin().file();
26 return base::FilePath(FILE_PATH_LITERAL("=UNRESOLVED DEPENDENCY="));
27 return file
->physical_name();
32 const char kRefs
[] = "refs";
33 const char kRefs_HelpShort
[] =
34 "refs: Find stuff referencing a target, directory, or config.";
35 const char kRefs_Help
[] =
36 "gn refs <label_pattern> [--files]\n"
37 " Finds code referencing a given label. The label can be a\n"
38 " target or config name. Unlike most other commands, unresolved\n"
39 " dependencies will be tolerated. This allows you to use this command\n"
40 " to find references to targets you're in the process of moving.\n"
42 " By default, the mapping from source item to dest item (where the\n"
43 " pattern matches the dest item). See \"gn help pattern\" for\n"
44 " information on pattern-matching rules.\n"
48 " Output unique filenames referencing a matched target or config.\n"
51 " gn refs \"//tools/gn/*\"\n"
52 " Find all targets depending on any target or config in the\n"
53 " \"tools/gn\" directory.\n"
55 " gn refs //tools/gn:gn\n"
56 " Find all targets depending on the given exact target name.\n"
58 " gn refs \"*gtk*\" --files\n"
59 " Find all unique buildfiles with a dependency on a target that has\n"
60 " the substring \"gtk\" in the name.\n";
62 int RunRefs(const std::vector
<std::string
>& args
) {
63 if (args
.size() != 1 && args
.size() != 2) {
64 Err(Location(), "You're holding it wrong.",
65 "Usage: \"gn refs <label_pattern>\"").PrintToStdout();
69 // Check for common errors on input.
70 if (args
[0].find('*') == std::string::npos
) {
71 // We need to begin with a "//" and have a colon if there's no "*" or it
72 // will be impossible to match anything.
73 if (args
[0].size() < 2 ||
74 (args
[0][0] != '/' && args
[0][1] != '/') ||
75 args
[0].find(':') == std::string::npos
) {
76 Err(Location(), "Patterns match the entire label. Since your pattern "
77 "has no wildcard, it\nshould start with a \"//\" and have a colon "
78 "or it can never match anything.\nTo match a substring, use "
79 "\"*foo*\".").PrintToStdout();
84 Pattern
pattern(args
[0]);
86 Setup
* setup
= new Setup
;
87 setup
->set_check_for_bad_items(false);
88 if (!setup
->DoSetup() || !setup
->Run())
91 const ItemTree
& item_tree
= setup
->build_settings().item_tree();
92 base::AutoLock
lock(item_tree
.lock());
94 std::vector
<const ItemNode
*> nodes
;
95 item_tree
.GetAllItemNodesLocked(&nodes
);
97 const CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
99 bool file_output
= cmdline
->HasSwitch("files");
100 std::set
<std::string
> unique_output
;
102 for (size_t node_index
= 0; node_index
< nodes
.size(); node_index
++) {
103 const ItemNode
& node
= *nodes
[node_index
];
104 const ItemNode::ItemNodeMap
& deps
= node
.direct_dependencies();
105 for (ItemNode::ItemNodeMap::const_iterator d
= deps
.begin();
106 d
!= deps
.end(); ++d
) {
107 std::string label
= d
->first
->item()->label().GetUserVisibleName(false);
108 if (pattern
.MatchesString(label
)) {
111 unique_output
.insert(FilePathToUTF8(FilePathForItemNode(node
)));
112 break; // Found a match for this target's file, don't need more.
114 // We can get dupes when there are differnet toolchains involved,
115 // so we want to send all output through the de-duper.
116 unique_output
.insert(
117 node
.item()->label().GetUserVisibleName(false) + " -> " + label
);
123 for (std::set
<std::string
>::iterator i
= unique_output
.begin();
124 i
!= unique_output
.end(); ++i
)
125 OutputString(*i
+ "\n");
130 } // namespace commands