summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2016-11-07 18:34:46 (GMT)
committerNico Weber <nicolasweber@gmx.de>2016-11-07 18:34:46 (GMT)
commit717b7b4a31db6027207588c0fb89c3ead384747b (patch)
treef95fbdb0340abd28dba6ad67aa19d6e12083450a /src
parentb49b0fc01bb052b6ac856b1e72be9391e962398e (diff)
parentb0cce09f563d0942fcf1c1256db679cebcbd6bea (diff)
downloadNinja-1.7.2.zip
Ninja-1.7.2.tar.gz
Ninja-1.7.2.tar.bz2
v1.7.2v1.7.2
Diffstat (limited to 'src')
-rwxr-xr-xsrc/browse.py16
-rw-r--r--src/build.cc36
-rw-r--r--src/build.h20
-rw-r--r--src/build_test.cc14
-rw-r--r--src/graph_test.cc39
-rw-r--r--src/manifest_parser.cc10
-rw-r--r--src/manifest_parser_test.cc5
-rw-r--r--src/state.cc9
-rw-r--r--src/state.h4
-rw-r--r--src/subprocess.h8
-rw-r--r--src/subprocess_test.cc4
-rw-r--r--src/version.cc2
12 files changed, 122 insertions, 45 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 8c0fbf8..64710dd 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -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,14 +220,14 @@ 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;
@@ -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 a048a18..eafa082 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -18,7 +18,7 @@
#include "util.h"
-const char* kNinjaVersion = "1.7.1";
+const char* kNinjaVersion = "1.7.2";
void ParseVersion(const string& version, int* major, int* minor) {
size_t end = version.find('.');