diff --git a/misc/output_test.py b/misc/output_test.py index cba3ff02fa..b82664c3d7 100755 --- a/misc/output_test.py +++ b/misc/output_test.py @@ -213,6 +213,27 @@ def test_tool_inputs(self) -> None: out2 ''') + # Verify that results are shell-escaped by default. + # Also verify that phony outputs are never part of the results. + quote = '"' if platform.system() == "Windows" else "'" + + plan = ''' +rule cat + command = cat $in $out +build out1 : cat in1 +build out$ 2 : cat out1 +build out$ 3 : phony out$ 2 +build all: phony out$ 3 +''' + + self.assertEqual(run(plan, flags='-t inputs all'), +f'''{quote}out 2{quote} +in1 +out1 +''') + + + def test_explain_output(self): b = BuildDir('''\ build .FORCE: phony diff --git a/src/graph.cc b/src/graph.cc index 072e3d1365..f04ffb47c8 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -496,28 +496,6 @@ std::string EdgeEnv::MakePathList(const Node* const* const span, return result; } -void Edge::CollectInputs(bool shell_escape, - std::vector* out) const { - for (std::vector::const_iterator it = inputs_.begin(); - it != inputs_.end(); ++it) { - std::string path = (*it)->PathDecanonicalized(); - if (shell_escape) { - std::string unescaped; - unescaped.swap(path); -#ifdef _WIN32 - GetWin32EscapedString(unescaped, &path); -#else - GetShellEscapedString(unescaped, &path); -#endif - } -#if __cplusplus >= 201103L - out->push_back(std::move(path)); -#else - out->push_back(path); -#endif - } -} - std::string Edge::EvaluateCommand(const bool incl_rsp_file) const { string command = GetBinding("command"); if (incl_rsp_file) { diff --git a/src/graph.h b/src/graph.h index 5af85a27a7..806260e5d7 100644 --- a/src/graph.h +++ b/src/graph.h @@ -201,9 +201,6 @@ struct Edge { void Dump(const char* prefix="") const; - // Append all edge explicit inputs to |*out|. Possibly with shell escaping. - void CollectInputs(bool shell_escape, std::vector* out) const; - // critical_path_weight is the priority during build scheduling. The // "critical path" between this edge's inputs and any target node is // the path which maximises the sum oof weights along that path. diff --git a/src/graph_test.cc b/src/graph_test.cc index 2b858f5716..6c654eeb32 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -215,39 +215,6 @@ TEST_F(GraphTest, RootNodes) { } } -TEST_F(GraphTest, CollectInputs) { - ASSERT_NO_FATAL_FAILURE(AssertParse( - &state_, - "build out$ 1: cat in1 in2 in$ with$ space | implicit || order_only\n")); - - std::vector inputs; - Edge* edge = GetNode("out 1")->in_edge(); - - // Test without shell escaping. - inputs.clear(); - edge->CollectInputs(false, &inputs); - EXPECT_EQ(5u, inputs.size()); - EXPECT_EQ("in1", inputs[0]); - EXPECT_EQ("in2", inputs[1]); - EXPECT_EQ("in with space", inputs[2]); - EXPECT_EQ("implicit", inputs[3]); - EXPECT_EQ("order_only", inputs[4]); - - // Test with shell escaping. - inputs.clear(); - edge->CollectInputs(true, &inputs); - EXPECT_EQ(5u, inputs.size()); - EXPECT_EQ("in1", inputs[0]); - EXPECT_EQ("in2", inputs[1]); -#ifdef _WIN32 - EXPECT_EQ("\"in with space\"", inputs[2]); -#else - EXPECT_EQ("'in with space'", inputs[2]); -#endif - EXPECT_EQ("implicit", inputs[3]); - EXPECT_EQ("order_only", inputs[4]); -} - TEST_F(GraphTest, InputsCollector) { // Build plan for the following graph: // diff --git a/src/ninja.cc b/src/ninja.cc index 2902359f15..cb4f5865df 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -761,27 +761,12 @@ int NinjaMain::ToolCommands(const Options* options, int argc, char* argv[]) { return 0; } -void CollectInputs(Edge* edge, std::set* seen, - std::vector* result) { - if (!edge) - return; - if (!seen->insert(edge).second) - return; - - for (vector::iterator in = edge->inputs_.begin(); - in != edge->inputs_.end(); ++in) - CollectInputs((*in)->in_edge(), seen, result); - - if (!edge->is_phony()) { - edge->CollectInputs(true, result); - } -} - int NinjaMain::ToolInputs(const Options* options, int argc, char* argv[]) { // The inputs tool uses getopt, and expects argv[0] to contain the name of // the tool, i.e. "inputs". argc++; argv--; + optind = 1; int opt; const option kLongOptions[] = { { "help", no_argument, NULL, 'h' }, @@ -794,8 +779,9 @@ int NinjaMain::ToolInputs(const Options* options, int argc, char* argv[]) { printf( "Usage '-t inputs [options] [targets]\n" "\n" -"List all inputs used for a set of targets. Note that this includes\n" -"explicit, implicit and order-only inputs, but not validation ones.\n\n" +"List all inputs used for a set of targets.\n" +"Note that results are shell escaped, and sorted alphabetically,\n" +"and never include validation target paths.\n\n" "Options:\n" " -h, --help Print this message.\n"); // clang-format on @@ -805,24 +791,22 @@ int NinjaMain::ToolInputs(const Options* options, int argc, char* argv[]) { argv += optind; argc -= optind; - vector nodes; - string err; + std::vector nodes; + std::string err; if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { Error("%s", err.c_str()); return 1; } - std::set seen; - std::vector result; - for (vector::iterator in = nodes.begin(); in != nodes.end(); ++in) - CollectInputs((*in)->in_edge(), &seen, &result); + InputsCollector collector; + for (const Node* node : nodes) + collector.VisitNode(node); - // Make output deterministic by sorting then removing duplicates. - std::sort(result.begin(), result.end()); - result.erase(std::unique(result.begin(), result.end()), result.end()); + std::vector inputs = collector.GetInputsAsStrings(true); + std::sort(inputs.begin(), inputs.end()); - for (size_t n = 0; n < result.size(); ++n) - puts(result[n].c_str()); + for (const std::string& input : inputs) + puts(input.c_str()); return 0; }