Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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 <map> | 5 #include <map> |
| 6 #include <set> | 6 #include <set> |
| 7 | 7 |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "tools/gn/commands.h" | 9 #include "tools/gn/commands.h" |
| 10 #include "tools/gn/deps_iterator.h" | 10 #include "tools/gn/deps_iterator.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 typedef std::multimap<const Target*, const Target*> DepMap; | 26 typedef std::multimap<const Target*, const Target*> DepMap; |
| 27 | 27 |
| 28 // Populates the reverse dependency map for the targets in the Setup. | 28 // Populates the reverse dependency map for the targets in the Setup. |
| 29 void FillDepMap(Setup* setup, DepMap* dep_map) { | 29 void FillDepMap(Setup* setup, DepMap* dep_map) { |
| 30 for (const auto& target : setup->builder()->GetAllResolvedTargets()) { | 30 for (const auto& target : setup->builder()->GetAllResolvedTargets()) { |
| 31 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) | 31 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) |
| 32 dep_map->insert(std::make_pair(dep_pair.ptr, target)); | 32 dep_map->insert(std::make_pair(dep_pair.ptr, target)); |
| 33 } | 33 } |
| 34 } | 34 } |
| 35 | 35 |
| 36 // Returns the file path generating this item. | 36 // Forward declaration for function below. |
| 37 base::FilePath FilePathForItem(const Item* item) { | |
| 38 return item->defined_from()->GetRange().begin().file()->physical_name(); | |
| 39 } | |
| 40 | |
| 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; | |
| 47 | |
| 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))); | |
| 53 | |
| 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()); | |
| 62 | |
| 63 // Grab the label of the default toolchain from a random target. | |
| 64 Label default_tc_label = | |
| 65 (*results.begin())->settings()->default_toolchain_label(); | |
| 66 | |
| 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"); | |
| 72 } | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 // Forward declatation for function below. | |
| 77 void RecursivePrintTargetDeps(const DepMap& dep_map, | 37 void RecursivePrintTargetDeps(const DepMap& dep_map, |
| 78 const Target* target, | 38 const Target* target, |
| 79 TargetSet* seen_targets, | 39 TargetSet* seen_targets, |
| 80 int indent_level); | 40 int indent_level); |
| 81 | 41 |
| 82 // Prints the target and its dependencies in tree form. If the set is non-null, | 42 // 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 | 43 // 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 | 44 // already, it will not be recused into. When the set is null, all refs will be |
| 85 // printed. | 45 // printed. |
| 86 void RecursivePrintTarget(const DepMap& dep_map, | 46 void RecursivePrintTarget(const DepMap& dep_map, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 return true; | 127 return true; |
| 168 } | 128 } |
| 169 for (const auto& cur_file : target->data()) { | 129 for (const auto& cur_file : target->data()) { |
| 170 if (cur_file == file) | 130 if (cur_file == file) |
| 171 return true; | 131 return true; |
| 172 } | 132 } |
| 173 return false; | 133 return false; |
| 174 } | 134 } |
| 175 | 135 |
| 176 void GetTargetsContainingFile(Setup* setup, | 136 void GetTargetsContainingFile(Setup* setup, |
| 177 const std::string& input, | 137 const std::vector<const Target*>& all_targets, |
| 138 const SourceFile& file, | |
| 178 bool all_toolchains, | 139 bool all_toolchains, |
| 179 std::vector<const Target*>* matches) { | 140 UniqueVector<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()); | |
| 184 | |
| 185 Label default_toolchain = setup->loader()->default_toolchain_label(); | 141 Label default_toolchain = setup->loader()->default_toolchain_label(); |
| 186 | |
| 187 std::vector<const Target*> all_targets = | |
| 188 setup->builder()->GetAllResolvedTargets(); | |
| 189 | |
| 190 for (const auto& target : all_targets) { | 142 for (const auto& target : all_targets) { |
| 191 if (!all_toolchains) { | 143 if (!all_toolchains) { |
| 192 // Only check targets in the default toolchain. | 144 // Only check targets in the default toolchain. |
| 193 if (target->label().GetToolchainLabel() != default_toolchain) | 145 if (target->label().GetToolchainLabel() != default_toolchain) |
| 194 continue; | 146 continue; |
| 195 } | 147 } |
| 196 if (TargetContainsFile(target, file)) | 148 if (TargetContainsFile(target, file)) |
| 197 matches->push_back(target); | 149 matches->push_back(target); |
| 198 } | 150 } |
| 199 } | 151 } |
| 200 | 152 |
| 153 bool TargetReferencesConfig(const Target* target, const Config* config) { | |
| 154 for (const LabelConfigPair& cur : target->configs()) { | |
| 155 if (cur.ptr == config) | |
| 156 return true; | |
| 157 } | |
| 158 for (const LabelConfigPair& cur : target->public_configs()) { | |
| 159 if (cur.ptr == config) | |
| 160 return true; | |
| 161 } | |
| 162 return false; | |
| 163 } | |
| 164 | |
| 165 void GetTargetsReferencingConfig(Setup* setup, | |
| 166 const std::vector<const Target*>& all_targets, | |
| 167 const Config* config, | |
| 168 bool all_toolchains, | |
| 169 UniqueVector<const Target*>* matches) { | |
| 170 Label default_toolchain = setup->loader()->default_toolchain_label(); | |
| 171 for (const auto& target : all_targets) { | |
| 172 if (!all_toolchains) { | |
| 173 // Only check targets in the default toolchain. | |
| 174 if (target->label().GetToolchainLabel() != default_toolchain) | |
| 175 continue; | |
| 176 } | |
| 177 if (TargetReferencesConfig(target, config)) | |
| 178 matches->push_back(target); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 void DoTreeOutput(const DepMap& dep_map, | |
| 183 const UniqueVector<const Target*>& implicit_target_matches, | |
| 184 const UniqueVector<const Target*>& explicit_target_matches, | |
| 185 bool all) { | |
| 186 TargetSet seen_targets; | |
| 187 | |
| 188 // Implicit targets don't get printed themselves. | |
| 189 for (const Target* target : implicit_target_matches) { | |
| 190 if (all) | |
| 191 RecursivePrintTargetDeps(dep_map, target, nullptr, 0); | |
| 192 else | |
| 193 RecursivePrintTargetDeps(dep_map, target, &seen_targets, 0); | |
| 194 } | |
| 195 | |
| 196 // Explicit targets appear in the output. | |
| 197 for (const Target* target : implicit_target_matches) { | |
| 198 if (all) | |
| 199 RecursivePrintTarget(dep_map, target, nullptr, 0); | |
| 200 else | |
| 201 RecursivePrintTarget(dep_map, target, &seen_targets, 0); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void DoAllListOutput( | |
| 206 const DepMap& dep_map, | |
| 207 const UniqueVector<const Target*>& implicit_target_matches, | |
| 208 const UniqueVector<const Target*>& explicit_target_matches) { | |
| 209 // Output recursive dependencies, uniquified and flattened. | |
| 210 TargetSet results; | |
| 211 | |
| 212 for (const Target* target : implicit_target_matches) | |
| 213 RecursiveCollectChildRefs(dep_map, target, &results); | |
| 214 for (const Target* target : explicit_target_matches) { | |
| 215 // Explicit targets also get added to the output themselves. | |
| 216 results.insert(target); | |
| 217 RecursiveCollectChildRefs(dep_map, target, &results); | |
| 218 } | |
| 219 | |
| 220 FilterAndPrintTargetSet(false, results); | |
| 221 } | |
| 222 | |
| 223 void DoDirectListOutput( | |
| 224 const DepMap& dep_map, | |
| 225 const UniqueVector<const Target*>& implicit_target_matches, | |
| 226 const UniqueVector<const Target*>& explicit_target_matches) { | |
| 227 TargetSet results; | |
| 228 | |
| 229 // Output everything that refers to the implicit ones. | |
| 230 for (const Target* target : implicit_target_matches) { | |
| 231 DepMap::const_iterator dep_begin = dep_map.lower_bound(target); | |
| 232 DepMap::const_iterator dep_end = dep_map.upper_bound(target); | |
| 233 for (DepMap::const_iterator cur_dep = dep_begin; | |
| 234 cur_dep != dep_end; cur_dep++) | |
| 235 results.insert(cur_dep->second); | |
| 236 } | |
| 237 | |
| 238 // And just output the explicit ones directly (these are the target matches | |
| 239 // when referring to what references a file or config). | |
| 240 for (const Target* target : explicit_target_matches) | |
| 241 results.insert(target); | |
| 242 | |
| 243 FilterAndPrintTargetSet(false, results); | |
| 244 } | |
| 245 | |
| 201 } // namespace | 246 } // namespace |
| 202 | 247 |
| 203 const char kRefs[] = "refs"; | 248 const char kRefs[] = "refs"; |
| 204 const char kRefs_HelpShort[] = | 249 const char kRefs_HelpShort[] = |
| 205 "refs: Find stuff referencing a target or file."; | 250 "refs: Find stuff referencing a target or file."; |
| 206 const char kRefs_Help[] = | 251 const char kRefs_Help[] = |
| 207 "gn refs <out_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n" | 252 "gn refs <out_dir> (<label_pattern>|<label>|<file>)* [--files] [--tree]\n" |
|
scottmg
2015/02/19 21:52:01
--as, etc?
| |
| 208 " [--all-toolchains]\n" | 253 " [--all] [--all-toolchains]\n" |
| 209 "\n" | 254 "\n" |
| 210 " Finds reverse dependencies (which targets reference something). The\n" | 255 " Finds reverse dependencies (which targets reference something). The\n" |
| 211 " input is either a target label, a target label pattern, or a file\n" | 256 " input is a list containing:\n" |
| 212 " name.\n" | |
| 213 "\n" | 257 "\n" |
| 214 " The <label_pattern> can take exact labels or patterns that match more\n" | 258 " - Target label: The result will be which targets depend on it.\n" |
| 215 " than one (although not general regular expressions).\n" | |
| 216 " See \"gn help label_pattern\" for details.\n" | |
| 217 "\n" | 259 "\n" |
| 218 " If the input is a file name, the output will be the target(s)\n" | 260 " - Config label: The result will be which targets list the given\n" |
| 219 " referencing that file (potentially recursively if used with --tree\n" | 261 " config in its \"configs\" or \"public_configs\" list.\n" |
| 220 " or --all). By default, only targets from the default toolchain that\n" | 262 "\n" |
| 221 " reference the file will be listed.\n" | 263 " - Label pattern: The result will be which targets depend on any\n" |
| 264 " target matching the given pattern. Patterns will not match\n" | |
| 265 " configs. These are not general regular expressions, see\n" | |
| 266 " \"gn help label_pattern\" for details.\n" | |
| 267 "\n" | |
| 268 " - File name: The result will be which targets list the given file in\n" | |
| 269 " its \"inputs\", \"sources\", \"public\", or \"data\". Any input\n" | |
| 270 " that does not contain wildcards and does not match a target or a\n" | |
| 271 " config will be treated as a file.\n" | |
| 272 "\n" | |
| 273 "Options\n" | |
| 222 "\n" | 274 "\n" |
| 223 " --all\n" | 275 " --all\n" |
| 224 " When used without --tree, will recurse and display all unique\n" | 276 " When used without --tree, will recurse and display all unique\n" |
| 225 " dependencies of the given targets. When used with --tree, turns\n" | 277 " dependencies of the given targets. For example, if the input is\n" |
| 226 " off eliding to show a complete tree.\n" | 278 " a target, this will output all targets that depend directly or\n" |
| 279 " indirectly on the input. If the input is a file, this will output\n" | |
| 280 " all targets that depend directly or indirectly on that file.\n" | |
| 281 "\n" | |
| 282 " When used with --tree, turns off eliding to show a complete tree.\n" | |
| 227 "\n" | 283 "\n" |
| 228 " --all-toolchains\n" | 284 " --all-toolchains\n" |
| 229 " For target patterns, make the label pattern match all toolchains.\n" | 285 " Normally only inputs in the default toolchain will be included.\n" |
| 230 " If the label pattern does not specify an explicit toolchain,\n" | 286 " This switch will turn on matching all toolchains.\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" | 287 "\n" |
| 234 " For filename inputs, lists targets from all toolchains that\n" | 288 " For example, a file is in a target might be compiled twice:\n" |
| 235 " include the file.\n" | 289 " once in the default toolchain and once in a secondary one. Without\n" |
| 290 " this flag, only the default toolchain one will be matched and\n" | |
| 291 " printed (potentially with its recursive dependencies, depending on\n" | |
| 292 " the other options). With this flag, both will be printed\n" | |
| 293 " (potentially with both of their recursive dependencies).\n" | |
| 236 "\n" | 294 "\n" |
| 237 " --files\n" | 295 TARGET_PRINTING_MODE_COMMAND_LINE_HELP |
| 238 " Output unique filenames referencing a matched target or config.\n" | 296 "\n" |
| 239 " These will be relative to the source root directory such that they\n" | 297 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP |
| 240 " are suitable for piping to other commands.\n" | |
| 241 "\n" | 298 "\n" |
| 242 " --tree\n" | 299 " --tree\n" |
| 243 " Outputs a reverse dependency tree from the given target.\n" | 300 " Outputs a reverse dependency tree from the given target.\n" |
| 244 " Duplicates will be elided. Combine with --all to see a full\n" | 301 " Duplicates will be elided. Combine with --all to see a full\n" |
| 245 " dependency tree.\n" | 302 " dependency tree.\n" |
| 246 "\n" | 303 "\n" |
| 304 " Tree output can not be used with the filtering or output flags:\n" | |
| 305 " --as, --type, --testonly.\n" | |
| 306 "\n" | |
| 307 TARGET_TYPE_FILTER_COMMAND_LINE_HELP | |
| 308 "\n" | |
| 247 "Examples (target input)\n" | 309 "Examples (target input)\n" |
| 248 "\n" | 310 "\n" |
| 249 " gn refs out/Debug //tools/gn:gn\n" | 311 " gn refs out/Debug //tools/gn:gn\n" |
| 250 " Find all targets depending on the given exact target name.\n" | 312 " Find all targets depending on the given exact target name.\n" |
| 251 "\n" | 313 "\n" |
| 252 " gn refs out/Debug //base:i18n --files | xargs gvim\n" | 314 " gn refs out/Debug //base:i18n --as=buildfiles | xargs gvim\n" |
| 253 " Edit all files containing references to //base:i18n\n" | 315 " Edit all .gn files containing references to //base:i18n\n" |
| 254 "\n" | 316 "\n" |
| 255 " gn refs out/Debug //base --all\n" | 317 " gn refs out/Debug //base --all\n" |
| 256 " List all targets depending directly or indirectly on //base:base.\n" | 318 " List all targets depending directly or indirectly on //base:base.\n" |
| 257 "\n" | 319 "\n" |
| 258 " gn refs out/Debug \"//base/*\"\n" | 320 " gn refs out/Debug \"//base/*\"\n" |
| 259 " List all targets depending directly on any target in //base or\n" | 321 " List all targets depending directly on any target in //base or\n" |
| 260 " its subdirectories.\n" | 322 " its subdirectories.\n" |
| 261 "\n" | 323 "\n" |
| 262 " gn refs out/Debug \"//base:*\"\n" | 324 " gn refs out/Debug \"//base:*\"\n" |
| 263 " List all targets depending directly on any target in\n" | 325 " List all targets depending directly on any target in\n" |
| 264 " //base/BUILD.gn.\n" | 326 " //base/BUILD.gn.\n" |
| 265 "\n" | 327 "\n" |
| 266 " gn refs out/Debug //base --tree\n" | 328 " gn refs out/Debug //base --tree\n" |
| 267 " Print a reverse dependency tree of //base:base\n" | 329 " Print a reverse dependency tree of //base:base\n" |
| 268 "\n" | 330 "\n" |
| 269 "Examples (file input)\n" | 331 "Examples (file input)\n" |
| 270 "\n" | 332 "\n" |
| 271 " gn refs out/Debug //base/macros.h\n" | 333 " gn refs out/Debug //base/macros.h\n" |
| 272 " Print targets listing //base/macros.h as a source.\n" | 334 " Print target(s) listing //base/macros.h as a source.\n" |
| 273 "\n" | 335 "\n" |
| 274 " gn refs out/Debug //base/macros.h --tree\n" | 336 " gn refs out/Debug //base/macros.h --tree\n" |
| 275 " Display a reverse dependency tree to get to the given file. This\n" | 337 " Display a reverse dependency tree to get to the given file. This\n" |
| 276 " will show how dependencies will reference that file.\n" | 338 " will show how dependencies will reference that file.\n" |
| 277 "\n" | 339 "\n" |
| 278 " gn refs out/Debug //base/macros.h --all\n" | 340 " gn refs out/Debug //base/macros.h //base/basictypes.h --all\n" |
| 279 " Display all unique targets with some dependency path to a target\n" | 341 " Display all unique targets with some dependency path to a target\n" |
| 280 " containing the given file as a source.\n"; | 342 " containing either of the given files as a source.\n" |
| 343 "\n" | |
| 344 " gn refs out/Debug //base/macros.h --testonly=true --type=executable\n" | |
| 345 " --all --as=output\n" | |
| 346 " Display the executable file names of all test executables\n" | |
| 347 " potentially affected by a change to the given file.\n"; | |
| 281 | 348 |
| 282 int RunRefs(const std::vector<std::string>& args) { | 349 int RunRefs(const std::vector<std::string>& args) { |
| 283 if (args.size() != 2) { | 350 if (args.size() != 2) { |
| 284 Err(Location(), "You're holding it wrong.", | 351 Err(Location(), "You're holding it wrong.", |
| 285 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"") | 352 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"") |
| 286 .PrintToStdout(); | 353 .PrintToStdout(); |
| 287 return 1; | 354 return 1; |
| 288 } | 355 } |
| 289 | 356 |
| 290 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); | 357 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); |
| 291 bool tree = cmdline->HasSwitch("tree"); | 358 bool tree = cmdline->HasSwitch("tree"); |
| 292 bool all = cmdline->HasSwitch("all"); | 359 bool all = cmdline->HasSwitch("all"); |
| 293 bool all_toolchains = cmdline->HasSwitch("all-toolchains"); | 360 bool all_toolchains = cmdline->HasSwitch("all-toolchains"); |
| 294 bool files = cmdline->HasSwitch("files"); | |
| 295 | 361 |
| 296 Setup* setup = new Setup; | 362 Setup* setup = new Setup; |
| 297 setup->set_check_for_bad_items(false); | 363 setup->set_check_for_bad_items(false); |
| 298 if (!setup->DoSetup(args[0], false) || !setup->Run()) | 364 if (!setup->DoSetup(args[0], false) || !setup->Run()) |
| 299 return 1; | 365 return 1; |
| 300 | 366 |
| 301 // Figure out the target or targets that the user is querying. | 367 // The inputs are everything but the first arg (which is the build dir). |
| 302 bool is_file_input = false; | 368 std::vector<std::string> inputs(args.begin() + 1, args.end()); |
| 303 std::vector<const Target*> query; | 369 |
| 304 if (!ResolveTargetsFromCommandLinePattern(setup, args[1], all_toolchains, | 370 // Get the matches for the command-line input. |
| 305 &query)) | 371 UniqueVector<const Target*> target_matches; |
| 372 UniqueVector<const Config*> config_matches; | |
| 373 UniqueVector<const Toolchain*> toolchain_matches; | |
| 374 UniqueVector<SourceFile> file_matches; | |
| 375 if (!ResolveFromCommandLineInput(setup, inputs, all_toolchains, | |
| 376 &target_matches, &config_matches, | |
| 377 &toolchain_matches, &file_matches)) | |
| 306 return 1; | 378 return 1; |
| 307 if (query.empty()) { | 379 |
| 308 // If it doesn't match any targets, assume input is file. | 380 // When you give a file or config as an input, you want the targets that are |
| 309 GetTargetsContainingFile(setup, args[1], all_toolchains, &query); | 381 // associated with it. We don't want to just append this to the |
| 310 if (query.empty()) { | 382 // target_matches, however, since these targets should actually be listed in |
| 311 OutputString("\"" + args[1] + "\" matches no targets.\n"); | 383 // the output, while for normal targets you don't want to see the inputs, |
| 312 return 0; | 384 // only what refers to them. |
| 313 } | 385 std::vector<const Target*> all_targets = |
| 314 is_file_input = true; | 386 setup->builder()->GetAllResolvedTargets(); |
| 387 UniqueVector<const Target*> explicit_target_matches; | |
| 388 for (const auto& file : file_matches) { | |
| 389 GetTargetsContainingFile(setup, all_targets, file, all_toolchains, | |
| 390 &explicit_target_matches); | |
| 391 } | |
| 392 for (const auto& config : config_matches) { | |
| 393 GetTargetsReferencingConfig(setup, all_targets, config, all_toolchains, | |
| 394 &explicit_target_matches); | |
| 315 } | 395 } |
| 316 | 396 |
| 317 // Construct the reverse dependency tree. | 397 // Construct the reverse dependency tree. |
| 318 DepMap dep_map; | 398 DepMap dep_map; |
| 319 FillDepMap(setup, &dep_map); | 399 FillDepMap(setup, &dep_map); |
| 320 | 400 |
| 321 // When the input is a file, we want to print the targets in |query|, which | 401 if (tree) |
| 322 // are the things that directly reference the file, but when the input is a | 402 DoTreeOutput(dep_map, target_matches, explicit_target_matches, all); |
| 323 // target, we skip that since the user is asking for what reference those. | 403 else if (all) |
| 324 if (tree) { | 404 DoAllListOutput(dep_map, target_matches, explicit_target_matches); |
| 325 // Output dependency tree. | 405 else |
| 326 if (files) { | 406 DoDirectListOutput(dep_map, target_matches, explicit_target_matches); |
| 327 Err(nullptr, "--files option can't be used with --tree option.") | |
| 328 .PrintToStdout(); | |
| 329 return 1; | |
| 330 } | |
| 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; | |
| 335 } | |
| 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); | |
| 343 } | |
| 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); | |
| 352 } | |
| 353 } | |
| 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); | |
| 362 } | |
| 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); | |
| 379 } | |
| 380 } | |
| 381 OutputResultSet(results, files); | |
| 382 } | |
| 383 | 407 |
| 384 return 0; | 408 return 0; |
| 385 } | 409 } |
| 386 | 410 |
| 387 } // namespace commands | 411 } // namespace commands |
| OLD | NEW |