diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/browse.py | 16 | ||||
-rw-r--r-- | src/build.cc | 40 | ||||
-rw-r--r-- | src/build.h | 20 | ||||
-rw-r--r-- | src/build_test.cc | 14 | ||||
-rw-r--r-- | src/graph_test.cc | 39 | ||||
-rw-r--r-- | src/manifest_parser.cc | 10 | ||||
-rw-r--r-- | src/manifest_parser_test.cc | 5 | ||||
-rw-r--r-- | src/state.cc | 9 | ||||
-rw-r--r-- | src/state.h | 4 | ||||
-rw-r--r-- | src/subprocess.h | 8 | ||||
-rw-r--r-- | src/subprocess_test.cc | 4 | ||||
-rw-r--r-- | src/version.cc | 2 |
12 files changed, 124 insertions, 47 deletions
diff --git a/src/browse.py b/src/browse.py index 32792f3..4b4faa8 100755 --- a/src/browse.py +++ b/src/browse.py @@ -27,6 +27,7 @@ try: except ImportError: import BaseHTTPServer as httpserver import argparse +import cgi import os import socket import subprocess @@ -58,6 +59,9 @@ def match_strip(line, prefix): return (False, line) return (True, line[len(prefix):]) +def html_escape(text): + return cgi.escape(text, quote=True) + def parse(text): lines = iter(text.split('\n')) @@ -124,19 +128,19 @@ tt { ''' + body def generate_html(node): - document = ['<h1><tt>%s</tt></h1>' % node.target] + document = ['<h1><tt>%s</tt></h1>' % html_escape(node.target)] if node.inputs: document.append('<h2>target is built using rule <tt>%s</tt> of</h2>' % - node.rule) + html_escape(node.rule)) if len(node.inputs) > 0: document.append('<div class=filelist>') for input, type in sorted(node.inputs): extra = '' if type: - extra = ' (%s)' % type + extra = ' (%s)' % html_escape(type) document.append('<tt><a href="?%s">%s</a>%s</tt><br>' % - (input, input, extra)) + (html_escape(input), html_escape(input), extra)) document.append('</div>') if node.outputs: @@ -144,7 +148,7 @@ def generate_html(node): document.append('<div class=filelist>') for output in sorted(node.outputs): document.append('<tt><a href="?%s">%s</a></tt><br>' % - (output, output)) + (html_escape(output), html_escape(output))) document.append('</div>') return '\n'.join(document) @@ -177,7 +181,7 @@ class RequestHandler(httpserver.BaseHTTPRequestHandler): page_body = generate_html(parse(ninja_output.strip())) else: # Relay ninja's error message. - page_body = '<h1><tt>%s</tt></h1>' % ninja_error + page_body = '<h1><tt>%s</tt></h1>' % html_escape(ninja_error) self.send_response(200) self.end_headers() diff --git a/src/build.cc b/src/build.cc index 3a17bdb..64710dd 100644 --- a/src/build.cc +++ b/src/build.cc @@ -84,7 +84,7 @@ BuildStatus::BuildStatus(const BuildConfig& config) progress_status_format_ = getenv("NINJA_STATUS"); if (!progress_status_format_) - progress_status_format_ = "[%s/%t] "; + progress_status_format_ = "[%f/%t] "; } void BuildStatus::PlanHasTotalEdges(int total) { @@ -97,7 +97,7 @@ void BuildStatus::BuildEdgeStarted(Edge* edge) { ++started_edges_; if (edge->use_console() || printer_.is_smart_terminal()) - PrintStatus(edge); + PrintStatus(edge, kEdgeStarted); if (edge->use_console()) printer_.SetConsoleLocked(true); @@ -109,6 +109,7 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, int* start_time, int* end_time) { int64_t now = GetTimeMillis(); + ++finished_edges_; RunningEdgeMap::iterator i = running_edges_.find(edge); @@ -123,7 +124,7 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, return; if (!edge->use_console()) - PrintStatus(edge); + PrintStatus(edge, kEdgeFinished); // Print the command that is spewing before printing its output. if (!success) { @@ -158,13 +159,18 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, } } +void BuildStatus::BuildStarted() { + overall_rate_.Restart(); + current_rate_.Restart(); +} + void BuildStatus::BuildFinished() { printer_.SetConsoleLocked(false); printer_.PrintOnNewLine(""); } string BuildStatus::FormatProgressStatus( - const char* progress_status_format) const { + const char* progress_status_format, EdgeStatus status) const { string out; char buf[32]; int percent; @@ -189,10 +195,15 @@ string BuildStatus::FormatProgressStatus( break; // Running edges. - case 'r': - snprintf(buf, sizeof(buf), "%d", started_edges_ - finished_edges_); + case 'r': { + int running_edges = started_edges_ - finished_edges_; + // count the edge that just finished as a running edge + if (status == kEdgeFinished) + running_edges++; + snprintf(buf, sizeof(buf), "%d", running_edges); out += buf; break; + } // Unstarted edges. case 'u': @@ -209,20 +220,20 @@ string BuildStatus::FormatProgressStatus( // Overall finished edges per second. case 'o': overall_rate_.UpdateRate(finished_edges_); - snprinfRate(overall_rate_.rate(), buf, "%.1f"); + SnprintfRate(overall_rate_.rate(), buf, "%.1f"); out += buf; break; // Current rate, average over the last '-j' jobs. case 'c': current_rate_.UpdateRate(finished_edges_); - snprinfRate(current_rate_.rate(), buf, "%.1f"); + SnprintfRate(current_rate_.rate(), buf, "%.1f"); out += buf; break; // Percentage case 'p': - percent = (100 * started_edges_) / total_edges_; + percent = (100 * finished_edges_) / total_edges_; snprintf(buf, sizeof(buf), "%3i%%", percent); out += buf; break; @@ -246,7 +257,7 @@ string BuildStatus::FormatProgressStatus( return out; } -void BuildStatus::PrintStatus(Edge* edge) { +void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) { if (config_.verbosity == BuildConfig::QUIET) return; @@ -256,11 +267,7 @@ void BuildStatus::PrintStatus(Edge* edge) { if (to_print.empty() || force_full_command) to_print = edge->GetBinding("command"); - if (finished_edges_ == 0) { - overall_rate_.Restart(); - current_rate_.Restart(); - } - to_print = FormatProgressStatus(progress_status_format_) + to_print; + to_print = FormatProgressStatus(progress_status_format_, status) + to_print; printer_.Print(to_print, force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE); @@ -643,6 +650,9 @@ bool Builder::Build(string* err) { command_runner_.reset(new RealCommandRunner(config_)); } + // We are about to start the build process. + status_->BuildStarted(); + // This main loop runs the entire build process. // It is structured like this: // First, we attempt to start as many commands as allowed by the diff --git a/src/build.h b/src/build.h index 51589ef..66ce607 100644 --- a/src/build.h +++ b/src/build.h @@ -200,16 +200,24 @@ struct BuildStatus { void BuildEdgeStarted(Edge* edge); void BuildEdgeFinished(Edge* edge, bool success, const string& output, int* start_time, int* end_time); + void BuildStarted(); void BuildFinished(); + enum EdgeStatus { + kEdgeStarted, + kEdgeFinished, + }; + /// Format the progress status string by replacing the placeholders. /// See the user manual for more information about the available /// placeholders. /// @param progress_status_format The format of the progress status. - string FormatProgressStatus(const char* progress_status_format) const; + /// @param status The status of the edge. + string FormatProgressStatus(const char* progress_status_format, + EdgeStatus status) const; private: - void PrintStatus(Edge* edge); + void PrintStatus(Edge* edge, EdgeStatus status); const BuildConfig& config_; @@ -229,9 +237,11 @@ struct BuildStatus { const char* progress_status_format_; template<size_t S> - void snprinfRate(double rate, char(&buf)[S], const char* format) const { - if (rate == -1) snprintf(buf, S, "?"); - else snprintf(buf, S, format, rate); + void SnprintfRate(double rate, char(&buf)[S], const char* format) const { + if (rate == -1) + snprintf(buf, S, "?"); + else + snprintf(buf, S, format, rate); } struct RateInfo { diff --git a/src/build_test.cc b/src/build_test.cc index 55d093e..640e1b0 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -1286,7 +1286,8 @@ TEST_F(BuildWithLogTest, RestatTest) { ASSERT_EQ("", err); EXPECT_TRUE(builder_.Build(&err)); ASSERT_EQ("", err); - EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]")); + EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]", + BuildStatus::kEdgeStarted)); command_runner_.commands_ran_.clear(); state_.Reset(); @@ -1724,9 +1725,18 @@ TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) { ASSERT_EQ(1u, command_runner_.commands_ran_.size()); } +TEST_F(BuildTest, StatusFormatElapsed) { + status_.BuildStarted(); + // Before any task is done, the elapsed time must be zero. + EXPECT_EQ("[%/e0.000]", + status_.FormatProgressStatus("[%%/e%e]", + BuildStatus::kEdgeStarted)); +} + TEST_F(BuildTest, StatusFormatReplacePlaceholder) { EXPECT_EQ("[%/s0/t0/r0/u0/f0]", - status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]")); + status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]", + BuildStatus::kEdgeStarted)); } TEST_F(BuildTest, FailedDepsParse) { diff --git a/src/graph_test.cc b/src/graph_test.cc index 723e8ea..be08b19 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -149,6 +149,45 @@ TEST_F(GraphTest, ImplicitOutputOutOfDate) { EXPECT_TRUE(GetNode("out.imp")->dirty()); } +TEST_F(GraphTest, ImplicitOutputOnlyParse) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + + Edge* edge = GetNode("out.imp")->in_edge(); + EXPECT_EQ(1, edge->outputs_.size()); + EXPECT_EQ("out.imp", edge->outputs_[0]->path()); + EXPECT_EQ(1, edge->implicit_outs_); + EXPECT_EQ(edge, GetNode("out.imp")->in_edge()); +} + +TEST_F(GraphTest, ImplicitOutputOnlyMissing) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + fs_.Create("in", ""); + + Edge* edge = GetNode("out.imp")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + +TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build | out.imp: cat in\n")); + fs_.Create("out.imp", ""); + fs_.Tick(); + fs_.Create("in", ""); + + Edge* edge = GetNode("out.imp")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + TEST_F(GraphTest, PathWithCurrentDirectory) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule catdep\n" diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc index a4f489e..d6dcf22 100644 --- a/src/manifest_parser.cc +++ b/src/manifest_parser.cc @@ -236,16 +236,13 @@ bool ManifestParser::ParseEdge(string* err) { EvalString out; if (!lexer_.ReadPath(&out, err)) return false; - if (out.empty()) - return lexer_.Error("expected path", err); - - do { + while (!out.empty()) { outs.push_back(out); out.Clear(); if (!lexer_.ReadPath(&out, err)) return false; - } while (!out.empty()); + } } // Add all implicit outs, counting how many as we go. @@ -262,6 +259,9 @@ bool ManifestParser::ParseEdge(string* err) { } } + if (outs.empty()) + return lexer_.Error("expected path", err); + if (!ExpectToken(Lexer::COLON, err)) return false; diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc index 1312d26..3c82dc5 100644 --- a/src/manifest_parser_test.cc +++ b/src/manifest_parser_test.cc @@ -976,13 +976,10 @@ TEST_F(ParserTest, ImplicitOutputDupes) { TEST_F(ParserTest, NoExplicitOutput) { ManifestParser parser(&state, NULL, kDupeEdgeActionWarn); string err; - EXPECT_FALSE(parser.ParseTest( + EXPECT_TRUE(parser.ParseTest( "rule cat\n" " command = cat $in > $out\n" "build | imp : cat bar\n", &err)); - ASSERT_EQ("input:3: expected path\n" - "build | imp : cat bar\n" - " ^ near here", err); } TEST_F(ParserTest, DefaultDefault) { diff --git a/src/state.cc b/src/state.cc index a70f211..d539e7b 100644 --- a/src/state.cc +++ b/src/state.cc @@ -159,11 +159,12 @@ bool State::AddDefault(StringPiece path, string* err) { return true; } -vector<Node*> State::RootNodes(string* err) { +vector<Node*> State::RootNodes(string* err) const { vector<Node*> root_nodes; // Search for nodes with no output. - for (vector<Edge*>::iterator e = edges_.begin(); e != edges_.end(); ++e) { - for (vector<Node*>::iterator out = (*e)->outputs_.begin(); + for (vector<Edge*>::const_iterator e = edges_.begin(); + e != edges_.end(); ++e) { + for (vector<Node*>::const_iterator out = (*e)->outputs_.begin(); out != (*e)->outputs_.end(); ++out) { if ((*out)->out_edges().empty()) root_nodes.push_back(*out); @@ -176,7 +177,7 @@ vector<Node*> State::RootNodes(string* err) { return root_nodes; } -vector<Node*> State::DefaultNodes(string* err) { +vector<Node*> State::DefaultNodes(string* err) const { return defaults_.empty() ? RootNodes(err) : defaults_; } diff --git a/src/state.h b/src/state.h index d7987ba..b530207 100644 --- a/src/state.h +++ b/src/state.h @@ -110,8 +110,8 @@ struct State { /// @return the root node(s) of the graph. (Root nodes have no output edges). /// @param error where to write the error message if somethings went wrong. - vector<Node*> RootNodes(string* error); - vector<Node*> DefaultNodes(string* error); + vector<Node*> RootNodes(string* error) const; + vector<Node*> DefaultNodes(string* error) const; /// Mapping of path -> Node. typedef ExternalStringHashMap<Node*>::Type Paths; diff --git a/src/subprocess.h b/src/subprocess.h index 51f40b2..b2d486c 100644 --- a/src/subprocess.h +++ b/src/subprocess.h @@ -26,6 +26,14 @@ using namespace std; #include <signal.h> #endif +// ppoll() exists on FreeBSD, but only on newer versions. +#ifdef __FreeBSD__ +# include <sys/param.h> +# if defined USE_PPOLL && __FreeBSD_version < 1002000 +# undef USE_PPOLL +# endif +#endif + #include "exit_status.h" /// Subprocess wraps a single async subprocess. It is entirely diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc index ee16190..0a8c206 100644 --- a/src/subprocess_test.cc +++ b/src/subprocess_test.cc @@ -214,9 +214,7 @@ TEST_F(SubprocessTest, SetWithMulti) { } } -// OS X's process limit is less than 1025 by default -// (|sysctl kern.maxprocperuid| is 709 on 10.7 and 10.8 and less prior to that). -#if !defined(__APPLE__) && !defined(_WIN32) +#if defined(USE_PPOLL) TEST_F(SubprocessTest, SetWithLots) { // Arbitrary big number; needs to be over 1024 to confirm we're no longer // hostage to pselect. diff --git a/src/version.cc b/src/version.cc index 6613514..e2a83bb 100644 --- a/src/version.cc +++ b/src/version.cc @@ -18,7 +18,7 @@ #include "util.h" -const char* kNinjaVersion = "1.7.0.git"; +const char* kNinjaVersion = "1.7.2.git"; void ParseVersion(const string& version, int* major, int* minor) { size_t end = version.find('.'); |