Chromium Code Reviews| Index: tools/gn/command_path.cc |
| diff --git a/tools/gn/command_path.cc b/tools/gn/command_path.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..573e8cbfeed214a684de0733d8421ce768df563c |
| --- /dev/null |
| +++ b/tools/gn/command_path.cc |
| @@ -0,0 +1,159 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/command_line.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "tools/gn/commands.h" |
| +#include "tools/gn/setup.h" |
| +#include "tools/gn/standard_out.h" |
| + |
| +namespace commands { |
| + |
| +namespace { |
| + |
| +enum DepType { |
| + DEP_NONE, |
| + DEP_PUBLIC, |
| + DEP_PRIVATE, |
| + DEP_DATA |
| +}; |
| + |
| +// As we do a depth-first search, this vector will store the current path |
| +// the current target for printing when a match is found. |
| +using TargetDep = std::pair<const Target*, DepType>; |
| +using DepStack = std::vector<TargetDep>; |
| + |
| +void PrintDepStack(const DepStack& stack) { |
| + // Don't print toolchains unless they differ from the first target. |
| + const Label& default_toolchain = stack[0].first->label().GetToolchainLabel(); |
| + |
| + for (const auto& pair : stack) { |
| + OutputString(pair.first->label().GetUserVisibleName(default_toolchain)); |
| + switch (pair.second) { |
| + case DEP_NONE: |
| + break; |
| + case DEP_PUBLIC: |
| + OutputString(" --[public]-->", DECORATION_DIM); |
| + break; |
| + case DEP_PRIVATE: |
| + OutputString(" --[private]-->", DECORATION_DIM); |
| + break; |
| + case DEP_DATA: |
| + OutputString(" --[data]-->", DECORATION_DIM); |
| + break; |
| + } |
| + OutputString("\n"); |
| + } |
| + OutputString("\n"); |
| +} |
| + |
| +// Increments *found_count to reflect how many results are found. If print_all |
| +// is not set, only the first result will be printed. |
| +void RecursiveFindPath(const Target* current, |
| + const Target* desired, |
| + DepStack* stack, |
| + int* found_count, |
| + bool print_all) { |
| + if (current == desired) { |
| + (*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
|
| + if (print_all || *found_count == 1) { |
| + stack->push_back(TargetDep(current, DEP_NONE)); |
| + PrintDepStack(*stack); |
| + stack->pop_back(); |
| + } |
| + return; |
| + } |
| + |
| + stack->push_back(TargetDep(current, DEP_PUBLIC)); |
| + for (const auto& pair : current->public_deps()) |
| + RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); |
| + |
| + stack->back().second = DEP_PRIVATE; |
| + for (const auto& pair : current->private_deps()) |
| + RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); |
| + |
| + stack->back().second = DEP_DATA; |
| + for (const auto& pair : current->data_deps()) |
| + RecursiveFindPath(pair.ptr, desired, stack, found_count, print_all); |
| + stack->pop_back(); |
| +} |
| + |
| +} // namespace |
| + |
| +const char kPath[] = "path"; |
| +const char kPath_HelpShort[] = |
| + "path: Find paths between two targets."; |
| +const char kPath_Help[] = |
| + "gn path <out_dir> <target_one> <target_two>\n" |
| + "\n" |
| + " Finds paths of dependencies between two targets. Each unique path\n" |
| + " will be printed in one group, and groups will be separate by newlines.\n" |
| + " The two targets can appear in either order: paths will be found going\n" |
| + " in either direction.\n" |
| + "\n" |
| + " Each dependency will be annotated with its type. By default, only the\n" |
| + " first path encountered will be printed, which is not necessarily the\n" |
| + " shortest path.\n" |
| + "\n" |
| + "Options\n" |
| + "\n" |
| + " --all\n" |
| + " Prints all paths found rather than just the first one.\n" |
| + "\n" |
| + "Example\n" |
| + "\n" |
| + " gn path out/Default //base //tools/gn\n"; |
| + |
| +int RunPath(const std::vector<std::string>& args) { |
| + if (args.size() != 3) { |
| + Err(Location(), "You're holding it wrong.", |
| + "Usage: \"gn path <out_dir> <target_one> <target_two>\"") |
| + .PrintToStdout(); |
| + return 1; |
| + } |
| + |
| + Setup* setup = new Setup; |
| + if (!setup->DoSetup(args[0], false)) |
| + return 1; |
| + if (!setup->Run()) |
| + return 1; |
| + |
| + const Target* target1 = ResolveTargetFromCommandLineString(setup, args[1]); |
| + if (!target1) |
| + return 1; |
| + const Target* target2 = ResolveTargetFromCommandLineString(setup, args[2]); |
| + if (!target2) |
| + return 1; |
| + |
| + bool print_all = base::CommandLine::ForCurrentProcess()->HasSwitch("all"); |
| + |
| + // If we don't find a path going "forwards", try the reverse direction. Deps |
| + // can only go in one direction without having a cycle, which will have |
| + // caused a run failure above. |
| + DepStack stack; |
| + int found = 0; |
| + RecursiveFindPath(target1, target2, &stack, &found, print_all); |
| + if (found == 0) |
| + RecursiveFindPath(target2, target1, &stack, &found, print_all); |
| + |
| + if (found == 0) { |
| + OutputString("No paths found between these two targets.\n", |
| + DECORATION_YELLOW); |
| + } else if (found == 1) { |
| + OutputString("1 path found.\n", DECORATION_YELLOW); |
| + } else { |
| + if (print_all) { |
| + OutputString(base::StringPrintf("%d unique paths found.\n", found), |
| + DECORATION_YELLOW); |
| + } else { |
| + OutputString( |
| + base::StringPrintf("Showing the first of %d unique paths. ", found), |
| + DECORATION_YELLOW); |
| + OutputString("Use --all to print all paths.\n"); |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| +} // namespace commands |