Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Unified Diff: tools/gn/command_path.cc

Issue 1424313009: Improve gn path command. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/command_path.cc
diff --git a/tools/gn/command_path.cc b/tools/gn/command_path.cc
index ae39c8c557191789a2ac2b358fb640ccb8413b95..021ffe32bca215b78f64d1531addee6ad89371db 100644
--- a/tools/gn/command_path.cc
+++ b/tools/gn/command_path.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/strings/stringprintf.h"
@@ -25,8 +27,47 @@ enum DepType {
using TargetDep = std::pair<const Target*, DepType>;
using DepStack = std::vector<TargetDep>;
+// Note that this uses raw pointers. These need to be manually deleted (which
+// we won't normally bother with). This allows the vector to be resized
+// more quickly.
+using DepStackVector = std::vector<DepStack*>;
+
using DepSet = base::hash_set<const Target*>;
+struct Options {
+ Options()
+ : all(false),
+ public_only(false),
+ with_data(false) {
+ }
+
+ bool all;
+ bool public_only;
+ bool with_data;
+};
+
+struct State {
+ State() : found_count(0) {
+ // Reserve fairly large buffers for the found vectors.
+ const size_t kReserveSize = 32768;
+ found_public.reserve(kReserveSize);
+ found_other.reserve(kReserveSize);
+ }
+
+ // Stores targets that do not have any paths to the destination. This is
+ // an optimization to avoid revisiting useless paths.
+ DepSet rejected;
+
+ // Total number of paths found.
+ int found_count;
+
+ // The pointers in these vectors are owned by this object, but are
+ // deliberately leaked. There can be a lot of them which can take a long time
+ // to free, and GN will just exit after this is used anyway.
+ DepStackVector found_public;
+ DepStackVector found_other;
+};
+
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();
@@ -51,46 +92,89 @@ void PrintDepStack(const DepStack& stack) {
OutputString("\n");
}
+bool AreAllPublic(const DepStack& stack) {
+ // Don't check the type of the last one since that doesn't point to anything.
+ for (size_t i = 0; i < stack.size() - 1; i++) {
+ if (stack[i].second != DEP_PUBLIC)
+ return false;
+ }
+ return true;
+}
+
// Increments *found_count to reflect how many results are found. If print_all
// is not set, only the first result will be printed.
//
// As an optimization, targets that do not have any paths are added to
// *reject so this function doesn't waste time revisiting them.
-void RecursiveFindPath(const Target* current,
+void RecursiveFindPath(const Options& options,
+ State* state,
+ const Target* current,
const Target* desired,
- DepStack* stack,
- DepSet* reject,
- int* found_count,
- bool print_all) {
- if (reject->find(current) != reject->end())
+ DepStack* stack) {
+ if (state->rejected.find(current) != state->rejected.end())
return;
- int initial_found_count = *found_count;
+ int initial_found_count = state->found_count;
if (current == desired) {
- (*found_count)++;
- if (print_all || *found_count == 1) {
- stack->push_back(TargetDep(current, DEP_NONE));
- PrintDepStack(*stack);
- stack->pop_back();
- }
+ // Found a path.
+ state->found_count++;
+ stack->push_back(TargetDep(current, DEP_NONE));
+ if (AreAllPublic(*stack))
+ state->found_public.push_back(new DepStack(*stack));
+ else
+ state->found_other.push_back(new DepStack(*stack));
+ stack->pop_back();
return;
}
stack->push_back(TargetDep(current, DEP_PUBLIC));
for (const auto& pair : current->public_deps())
- RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all);
+ RecursiveFindPath(options, state, pair.ptr, desired, stack);
- stack->back().second = DEP_PRIVATE;
- for (const auto& pair : current->private_deps())
- RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all);
+ if (!options.public_only) {
+ stack->back().second = DEP_PRIVATE;
+ for (const auto& pair : current->private_deps())
+ RecursiveFindPath(options, state, pair.ptr, desired, stack);
+ }
+
+ if (options.with_data) {
+ stack->back().second = DEP_DATA;
+ for (const auto& pair : current->data_deps())
+ RecursiveFindPath(options, state, pair.ptr, desired, stack);
+ }
- stack->back().second = DEP_DATA;
- for (const auto& pair : current->data_deps())
- RecursiveFindPath(pair.ptr, desired, stack, reject, found_count, print_all);
stack->pop_back();
- if (*found_count == initial_found_count)
- reject->insert(current); // Eliminated this target.
+ if (state->found_count == initial_found_count)
+ state->rejected.insert(current); // Eliminated this target.
+}
+
+bool StackLengthLess(const DepStack* a, const DepStack* b) {
+ return a->size() < b->size();
+}
+
+// Prints one result vector. The vector will be modified.
+void PrintResultVector(const Options& options, DepStackVector* result) {
+ if (!options.all && !result->empty()) {
+ // Just print the smallest one.
+ PrintDepStack(**std::min_element(result->begin(), result->end(),
+ &StackLengthLess));
+ return;
+ }
+
+ // Print all in order of increasing length.
+ std::sort(result->begin(), result->end(), &StackLengthLess);
+ for (const auto& stack : *result)
+ PrintDepStack(*stack);
+}
+
+void PrintResults(const Options& options, State* state) {
+ PrintResultVector(options, &state->found_public);
+
+ // Consider non-public paths only if all paths are requested or there were
+ // no public paths.
+ if (state->found_public.empty() || options.all)
+ PrintResultVector(options, &state->found_other);
}
} // namespace
@@ -106,14 +190,26 @@ const char kPath_Help[] =
" 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"
+ " By default, a single path will be printed. If there is a path with\n"
+ " only public dependencies, the shortest public path will be printed.\n"
+ " Otherwise, the shortest path using either public or private\n"
+ " dependencies will be printed. If --with-data is specified, data deps\n"
+ " will also be considered. If there are multiple shortest paths, an\n"
+ " arbitrary one will be selected.\n"
"\n"
"Options\n"
"\n"
" --all\n"
- " Prints all paths found rather than just the first one.\n"
+ " Prints all paths found rather than just the first one. Public paths\n"
+ " will be printed first in order of increasing length, followed by\n"
+ " non-public paths in order of increasing length.\n"
+ "\n"
+ " --public\n"
+ " Considers only public paths. Can't be used with --with-data.\n"
+ "\n"
+ " --with-data\n"
+ " Additionally follows data deps. Without this flag, only public and\n"
+ " private linked deps will be followed. Can't be used with --public.\n"
"\n"
"Example\n"
"\n"
@@ -140,35 +236,79 @@ int RunPath(const std::vector<std::string>& args) {
if (!target2)
return 1;
- bool print_all = base::CommandLine::ForCurrentProcess()->HasSwitch("all");
+ Options options;
+ options.all = base::CommandLine::ForCurrentProcess()->HasSwitch("all");
+ options.public_only =
+ base::CommandLine::ForCurrentProcess()->HasSwitch("public");
+ options.with_data =
+ base::CommandLine::ForCurrentProcess()->HasSwitch("with-data");
+ if (options.public_only && options.with_data) {
+ Err(Location(), "Can't use --public with --with-data for 'gn path'.",
+ "Your zealous over-use of arguments has inevitably resulted in an "
+ "invalid\ncombination of flags.").PrintToStdout();
+ return 1;
+ }
// 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.
+ State state;
DepStack stack;
- DepSet rejected;
- int found = 0;
- RecursiveFindPath(target1, target2, &stack, &rejected, &found, print_all);
- if (found == 0) {
+ RecursiveFindPath(options, &state, target1, target2, &stack);
+ if (state.found_count == 0) {
// Need to reset the rejected set for a new invocation since the reverse
// search will revisit the same targets looking for something else.
- rejected.clear();
- RecursiveFindPath(target2, target1, &stack, &rejected, &found, print_all);
+ state.rejected.clear();
+ RecursiveFindPath(options, &state, target2, target1, &stack);
}
- if (found == 0) {
- OutputString("No paths found between these two targets.\n",
+ PrintResults(options, &state);
+
+ // This string is inserted in the results to annotate whether the result
+ // is only public or includes data deps or not.
+ const char* path_annotation = "";
+ if (options.public_only)
+ path_annotation = "public ";
+ else if (!options.with_data)
+ path_annotation = "non-data ";
+
+ if (state.found_count == 0) {
+ // No results.
+ OutputString(base::StringPrintf(
+ "No %spaths found between these two targets.\n", path_annotation),
+ DECORATION_YELLOW);
+ } else if (state.found_count == 1) {
+ // Exactly one result.
+ OutputString(base::StringPrintf("1 %spath found.", path_annotation),
DECORATION_YELLOW);
- } else if (found == 1) {
- OutputString("1 path found.\n", DECORATION_YELLOW);
+ if (!options.public_only) {
+ if (state.found_public.empty())
+ OutputString(" It is not public.");
+ else
+ OutputString(" It is public.");
+ }
+ OutputString("\n");
} else {
- if (print_all) {
- OutputString(base::StringPrintf("%d unique paths found.\n", found),
+ if (options.all) {
+ // Showing all paths when there are many.
+ OutputString(base::StringPrintf("%d unique %spaths found.",
+ state.found_count, path_annotation),
DECORATION_YELLOW);
+ if (!options.public_only) {
+ OutputString(base::StringPrintf(" %d of them are public.",
+ static_cast<int>(state.found_public.size())));
+ }
+ OutputString("\n");
} else {
+ // Showing one path when there are many.
OutputString(
- base::StringPrintf("Showing the first of %d unique paths. ", found),
+ base::StringPrintf("Showing one of %d unique %spaths.",
+ state.found_count, path_annotation),
DECORATION_YELLOW);
+ if (!options.public_only) {
+ OutputString(base::StringPrintf(" %d of them are public.\n",
+ static_cast<int>(state.found_public.size())));
+ }
OutputString("Use --all to print all paths.\n");
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698