OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "base/command_line.h" | |
6 #include "base/strings/stringprintf.h" | |
7 #include "tools/gn/commands.h" | |
8 #include "tools/gn/setup.h" | |
9 #include "tools/gn/standard_out.h" | |
10 | |
11 namespace commands { | |
12 | |
13 namespace { | |
14 | |
15 enum DepType { | |
16 DEP_NONE, | |
17 DEP_PUBLIC, | |
18 DEP_PRIVATE, | |
19 DEP_DATA | |
20 }; | |
21 | |
22 // As we do a depth-first search, this vector will store the current path | |
23 // the current target for printing when a match is found. | |
24 using TargetDep = std::pair<const Target*, DepType>; | |
25 using DepStack = std::vector<TargetDep>; | |
26 | |
27 void PrintDepStack(const DepStack& stack) { | |
28 // Don't print toolchains unless they differ from the first target. | |
29 const Label& default_toolchain = stack[0].first->label().GetToolchainLabel(); | |
30 | |
31 for (const auto& pair : stack) { | |
32 OutputString(pair.first->label().GetUserVisibleName(default_toolchain)); | |
33 switch (pair.second) { | |
34 case DEP_NONE: | |
35 break; | |
36 case DEP_PUBLIC: | |
37 OutputString(" --[public]-->", DECORATION_DIM); | |
38 break; | |
39 case DEP_PRIVATE: | |
40 OutputString(" --[private]-->", DECORATION_DIM); | |
41 break; | |
42 case DEP_DATA: | |
43 OutputString(" --[data]-->", DECORATION_DIM); | |
44 break; | |
45 } | |
46 OutputString("\n"); | |
47 } | |
48 OutputString("\n"); | |
49 } | |
50 | |
51 // Increments *found_count to reflect how many results are found. If print_all | |
52 // is not set, only the first result will be printed. | |
53 void RecursiveFindPath(const Target* current, | |
54 const Target* desired, | |
55 DepStack* stack, | |
56 int* found_count, | |
57 bool print_all) { | |
58 if (current == desired) { | |
59 (*found_count)++; | |
Dirk Pranke
2015/05/19 19:43:29
If I'm reading this correctly, this routine will s
brettw
2015/05/19 21:09:54
Correct. I want to find the number of items which
| |
60 if (print_all || *found_count == 1) { | |
61 stack->push_back(TargetDep(current, DEP_NONE)); | |
62 PrintDepStack(*stack); | |
63 stack->pop_back(); | |
64 } | |
65 return; | |
66 } | |
67 | |
68 stack->push_back(TargetDep(current, DEP_PUBLIC)); | |
69 for (const auto& pair : current->public_deps()) | |
70 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | |
71 | |
72 stack->back().second = DEP_PRIVATE; | |
73 for (const auto& pair : current->private_deps()) | |
74 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | |
75 | |
76 stack->back().second = DEP_DATA; | |
77 for (const auto& pair : current->data_deps()) | |
78 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | |
79 stack->pop_back(); | |
80 } | |
81 | |
82 } // namespace | |
83 | |
84 const char kPath[] = "path"; | |
85 const char kPath_HelpShort[] = | |
86 "path: Find paths between two targets."; | |
87 const char kPath_Help[] = | |
88 "gn path <out_dir> <target_one> <target_two>\n" | |
89 "\n" | |
90 " Finds paths of dependencies between two targets. Each unique path\n" | |
91 " will be printed in one group, and groups will be separate by newlines.\n" | |
92 " The two targets can appear in either order: paths will be found going\n" | |
93 " in either direction.\n" | |
94 "\n" | |
95 " Each dependency will be annotated with its type. By default, only the\n" | |
96 " first path encountered will be printed, which is not necessarily the\n" | |
97 " shortest path.\n" | |
98 "\n" | |
99 "Options\n" | |
100 "\n" | |
101 " --all\n" | |
102 " Prints all paths found rather than just the first one.\n" | |
103 "\n" | |
104 "Example\n" | |
105 "\n" | |
106 " gn path out/Default //base //tools/gn\n"; | |
107 | |
108 int RunPath(const std::vector<std::string>& args) { | |
109 if (args.size() != 3) { | |
110 Err(Location(), "You're holding it wrong.", | |
111 "Usage: \"gn path <out_dir> <target_one> <target_two>\"") | |
112 .PrintToStdout(); | |
113 return 1; | |
114 } | |
115 | |
116 Setup* setup = new Setup; | |
117 if (!setup->DoSetup(args[0], false)) | |
118 return 1; | |
119 if (!setup->Run()) | |
120 return 1; | |
121 | |
122 const Target* target1 = ResolveTargetFromCommandLineString(setup, args[1]); | |
123 if (!target1) | |
124 return 1; | |
125 const Target* target2 = ResolveTargetFromCommandLineString(setup, args[2]); | |
126 if (!target2) | |
127 return 1; | |
128 | |
129 bool print_all = base::CommandLine::ForCurrentProcess()->HasSwitch("all"); | |
130 | |
131 // If we don't find a path going "forwards", try the reverse direction. Deps | |
132 // can only go in one direction without having a cycle, which will have | |
133 // caused a run failure above. | |
134 DepStack stack; | |
135 int found = 0; | |
136 RecursiveFindPath(target1, target2, &stack, &found, print_all); | |
137 if (found == 0) | |
138 RecursiveFindPath(target2, target1, &stack, &found, print_all); | |
139 | |
140 if (found == 0) { | |
141 OutputString("No paths found between these two targets.\n", | |
142 DECORATION_YELLOW); | |
143 } else if (found == 1) { | |
144 OutputString("1 path found.\n", DECORATION_YELLOW); | |
145 } else { | |
146 if (print_all) { | |
147 OutputString(base::StringPrintf("%d unique paths found.\n", found), | |
148 DECORATION_YELLOW); | |
149 } else { | |
150 OutputString( | |
151 base::StringPrintf("Showing the first of %d unique paths. ", found), | |
152 DECORATION_YELLOW); | |
153 OutputString("Use --all to print all paths.\n"); | |
154 } | |
155 } | |
156 return 0; | |
157 } | |
158 | |
159 } // namespace commands | |
OLD | NEW |