OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "base/containers/hash_tables.h" |
6 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
7 #include "tools/gn/commands.h" | 8 #include "tools/gn/commands.h" |
8 #include "tools/gn/setup.h" | 9 #include "tools/gn/setup.h" |
9 #include "tools/gn/standard_out.h" | 10 #include "tools/gn/standard_out.h" |
10 | 11 |
11 namespace commands { | 12 namespace commands { |
12 | 13 |
13 namespace { | 14 namespace { |
14 | 15 |
15 enum DepType { | 16 enum DepType { |
16 DEP_NONE, | 17 DEP_NONE, |
17 DEP_PUBLIC, | 18 DEP_PUBLIC, |
18 DEP_PRIVATE, | 19 DEP_PRIVATE, |
19 DEP_DATA | 20 DEP_DATA |
20 }; | 21 }; |
21 | 22 |
22 // As we do a depth-first search, this vector will store the current path | 23 // 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 // the current target for printing when a match is found. |
24 using TargetDep = std::pair<const Target*, DepType>; | 25 using TargetDep = std::pair<const Target*, DepType>; |
25 using DepStack = std::vector<TargetDep>; | 26 using DepStack = std::vector<TargetDep>; |
26 | 27 |
| 28 using DepSet = base::hash_set<const Target*>; |
| 29 |
27 void PrintDepStack(const DepStack& stack) { | 30 void PrintDepStack(const DepStack& stack) { |
28 // Don't print toolchains unless they differ from the first target. | 31 // Don't print toolchains unless they differ from the first target. |
29 const Label& default_toolchain = stack[0].first->label().GetToolchainLabel(); | 32 const Label& default_toolchain = stack[0].first->label().GetToolchainLabel(); |
30 | 33 |
31 for (const auto& pair : stack) { | 34 for (const auto& pair : stack) { |
32 OutputString(pair.first->label().GetUserVisibleName(default_toolchain)); | 35 OutputString(pair.first->label().GetUserVisibleName(default_toolchain)); |
33 switch (pair.second) { | 36 switch (pair.second) { |
34 case DEP_NONE: | 37 case DEP_NONE: |
35 break; | 38 break; |
36 case DEP_PUBLIC: | 39 case DEP_PUBLIC: |
37 OutputString(" --[public]-->", DECORATION_DIM); | 40 OutputString(" --[public]-->", DECORATION_DIM); |
38 break; | 41 break; |
39 case DEP_PRIVATE: | 42 case DEP_PRIVATE: |
40 OutputString(" --[private]-->", DECORATION_DIM); | 43 OutputString(" --[private]-->", DECORATION_DIM); |
41 break; | 44 break; |
42 case DEP_DATA: | 45 case DEP_DATA: |
43 OutputString(" --[data]-->", DECORATION_DIM); | 46 OutputString(" --[data]-->", DECORATION_DIM); |
44 break; | 47 break; |
45 } | 48 } |
46 OutputString("\n"); | 49 OutputString("\n"); |
47 } | 50 } |
48 OutputString("\n"); | 51 OutputString("\n"); |
49 } | 52 } |
50 | 53 |
51 // Increments *found_count to reflect how many results are found. If print_all | 54 // Increments *found_count to reflect how many results are found. If print_all |
52 // is not set, only the first result will be printed. | 55 // is not set, only the first result will be printed. |
| 56 // |
| 57 // As an optimization, targets that do not have any paths are added to |
| 58 // *reject so this function doesn't waste time revisiting them. |
53 void RecursiveFindPath(const Target* current, | 59 void RecursiveFindPath(const Target* current, |
54 const Target* desired, | 60 const Target* desired, |
55 DepStack* stack, | 61 DepStack* stack, |
| 62 DepSet* reject, |
56 int* found_count, | 63 int* found_count, |
57 bool print_all) { | 64 bool print_all) { |
| 65 if (reject->find(current) != reject->end()) |
| 66 return; |
| 67 int initial_found_count = *found_count; |
| 68 |
58 if (current == desired) { | 69 if (current == desired) { |
59 (*found_count)++; | 70 (*found_count)++; |
60 if (print_all || *found_count == 1) { | 71 if (print_all || *found_count == 1) { |
61 stack->push_back(TargetDep(current, DEP_NONE)); | 72 stack->push_back(TargetDep(current, DEP_NONE)); |
62 PrintDepStack(*stack); | 73 PrintDepStack(*stack); |
63 stack->pop_back(); | 74 stack->pop_back(); |
64 } | 75 } |
65 return; | 76 return; |
66 } | 77 } |
67 | 78 |
68 stack->push_back(TargetDep(current, DEP_PUBLIC)); | 79 stack->push_back(TargetDep(current, DEP_PUBLIC)); |
69 for (const auto& pair : current->public_deps()) | 80 for (const auto& pair : current->public_deps()) |
70 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | 81 RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all); |
71 | 82 |
72 stack->back().second = DEP_PRIVATE; | 83 stack->back().second = DEP_PRIVATE; |
73 for (const auto& pair : current->private_deps()) | 84 for (const auto& pair : current->private_deps()) |
74 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | 85 RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all); |
75 | 86 |
76 stack->back().second = DEP_DATA; | 87 stack->back().second = DEP_DATA; |
77 for (const auto& pair : current->data_deps()) | 88 for (const auto& pair : current->data_deps()) |
78 RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); | 89 RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all); |
79 stack->pop_back(); | 90 stack->pop_back(); |
| 91 |
| 92 if (*found_count == initial_found_count) |
| 93 reject->insert(current); // Eliminated this target. |
80 } | 94 } |
81 | 95 |
82 } // namespace | 96 } // namespace |
83 | 97 |
84 const char kPath[] = "path"; | 98 const char kPath[] = "path"; |
85 const char kPath_HelpShort[] = | 99 const char kPath_HelpShort[] = |
86 "path: Find paths between two targets."; | 100 "path: Find paths between two targets."; |
87 const char kPath_Help[] = | 101 const char kPath_Help[] = |
88 "gn path <out_dir> <target_one> <target_two>\n" | 102 "gn path <out_dir> <target_one> <target_two>\n" |
89 "\n" | 103 "\n" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 const Target* target2 = ResolveTargetFromCommandLineString(setup, args[2]); | 139 const Target* target2 = ResolveTargetFromCommandLineString(setup, args[2]); |
126 if (!target2) | 140 if (!target2) |
127 return 1; | 141 return 1; |
128 | 142 |
129 bool print_all = base::CommandLine::ForCurrentProcess()->HasSwitch("all"); | 143 bool print_all = base::CommandLine::ForCurrentProcess()->HasSwitch("all"); |
130 | 144 |
131 // If we don't find a path going "forwards", try the reverse direction. Deps | 145 // 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 | 146 // can only go in one direction without having a cycle, which will have |
133 // caused a run failure above. | 147 // caused a run failure above. |
134 DepStack stack; | 148 DepStack stack; |
| 149 DepSet rejected; |
135 int found = 0; | 150 int found = 0; |
136 RecursiveFindPath(target1, target2, &stack, &found, print_all); | 151 RecursiveFindPath(target1, target2, &stack, &rejected, &found, print_all); |
137 if (found == 0) | 152 if (found == 0) { |
138 RecursiveFindPath(target2, target1, &stack, &found, print_all); | 153 // Need to reset the rejected set for a new invocation since the reverse |
| 154 // search will revisit the same targets looking for something else. |
| 155 rejected.clear(); |
| 156 RecursiveFindPath(target2, target1, &stack, &rejected, &found, print_all); |
| 157 } |
139 | 158 |
140 if (found == 0) { | 159 if (found == 0) { |
141 OutputString("No paths found between these two targets.\n", | 160 OutputString("No paths found between these two targets.\n", |
142 DECORATION_YELLOW); | 161 DECORATION_YELLOW); |
143 } else if (found == 1) { | 162 } else if (found == 1) { |
144 OutputString("1 path found.\n", DECORATION_YELLOW); | 163 OutputString("1 path found.\n", DECORATION_YELLOW); |
145 } else { | 164 } else { |
146 if (print_all) { | 165 if (print_all) { |
147 OutputString(base::StringPrintf("%d unique paths found.\n", found), | 166 OutputString(base::StringPrintf("%d unique paths found.\n", found), |
148 DECORATION_YELLOW); | 167 DECORATION_YELLOW); |
149 } else { | 168 } else { |
150 OutputString( | 169 OutputString( |
151 base::StringPrintf("Showing the first of %d unique paths. ", found), | 170 base::StringPrintf("Showing the first of %d unique paths. ", found), |
152 DECORATION_YELLOW); | 171 DECORATION_YELLOW); |
153 OutputString("Use --all to print all paths.\n"); | 172 OutputString("Use --all to print all paths.\n"); |
154 } | 173 } |
155 } | 174 } |
156 return 0; | 175 return 0; |
157 } | 176 } |
158 | 177 |
159 } // namespace commands | 178 } // namespace commands |
OLD | NEW |