summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNicolas Despres <nicolas.despres@gmail.com>2012-04-24 09:09:28 (GMT)
committerNicolas Despres <nicolas.despres@gmail.com>2012-04-24 09:19:04 (GMT)
commiteeb572aa84564768311b70e14c5b5354a31bfd29 (patch)
tree509cdc0fdf16aa953b43c3841349a38d0dbe5cd7 /src
parent34ad4de66455d06b5586579f9f304b4c904ac7cc (diff)
downloadNinja-eeb572aa84564768311b70e14c5b5354a31bfd29.zip
Ninja-eeb572aa84564768311b70e14c5b5354a31bfd29.tar.gz
Ninja-eeb572aa84564768311b70e14c5b5354a31bfd29.tar.bz2
Refactor and test progress status formatting.
Diffstat (limited to 'src')
-rw-r--r--src/build.cc114
-rw-r--r--src/build.h58
-rw-r--r--src/build_test.cc37
3 files changed, 140 insertions, 69 deletions
diff --git a/src/build.cc b/src/build.cc
index 303f134..aa44d8b 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -16,6 +16,7 @@
#include <assert.h>
#include <stdio.h>
+#include <sstream>
#ifdef _WIN32
#include <windows.h>
@@ -33,52 +34,6 @@
#include "subprocess.h"
#include "util.h"
-/// Tracks the status of a build: completion fraction, printing updates.
-struct BuildStatus {
- BuildStatus(const BuildConfig& config);
- void PlanHasTotalEdges(int total);
- void BuildEdgeStarted(Edge* edge);
- void BuildEdgeFinished(Edge* edge, bool success, const string& output,
- int* start_time, int* end_time);
- void BuildFinished();
-
- private:
- void PrintStatus(Edge* edge);
- /// Print the progress status.
- ///
- /// Get the status from the NINJA_STATUS environment variable if defined.
- /// See the user manual for more information about the available
- /// placeholders.
- ///
- /// @return The number of printed characters.
- int PrintProgressStatus() const;
-
- const BuildConfig& config_;
-
- /// Time the build started.
- int64_t start_time_millis_;
- /// Time we last printed an update.
- int64_t last_update_millis_;
-
- int started_edges_, finished_edges_, total_edges_;
-
- bool have_blank_line_;
-
- /// Map of running edge to time the edge started running.
- typedef map<Edge*, int> RunningEdgeMap;
- RunningEdgeMap running_edges_;
-
- /// Whether we can do fancy terminal control codes.
- bool smart_terminal_;
-
- /// The custom progress status format to use.
- const char* progress_status_format_;
-
-#ifdef _WIN32
- HANDLE console_;
-#endif
-};
-
BuildStatus::BuildStatus(const BuildConfig& config)
: config_(config),
start_time_millis_(GetTimeMillis()),
@@ -186,68 +141,91 @@ void BuildStatus::BuildFinished() {
printf("\n");
}
-int BuildStatus::PrintProgressStatus() const {
- // Print the custom status.
- const int kBUFF_SIZE = 1024;
- char buff[kBUFF_SIZE] = { '\0' };
+int BuildStatus::FormatProgressStatus(const char* progress_status_format,
+ char* buffer,
+ const int buffer_size,
+ string* err) const {
int i = 0;
- for (const char* s = progress_status_format_;
- *s != '\0' && i < kBUFF_SIZE;
+ for (const char* s = progress_status_format;
+ *s != '\0' && i < buffer_size;
++s) {
if (*s == '%') {
++s;
switch(*s) {
case '%':
- buff[i] = '%';
+ buffer[i] = '%';
++i;
break;
// Started edges.
case 's':
- i += snprintf(&buff[i], kBUFF_SIZE - i, "%d", started_edges_);
+ i += snprintf(&buffer[i], buffer_size - i, "%d", started_edges_);
break;
// Total edges.
case 't':
- i += snprintf(&buff[i], kBUFF_SIZE - i, "%d", total_edges_);
+ i += snprintf(&buffer[i], buffer_size - i, "%d", total_edges_);
break;
// Running edges.
case 'r':
- i += snprintf(&buff[i], kBUFF_SIZE - i, "%d",
+ i += snprintf(&buffer[i], buffer_size - i, "%d",
started_edges_ - finished_edges_);
break;
// Unstarted edges.
case 'u':
- i += snprintf(&buff[i], kBUFF_SIZE - i, "%d",
+ i += snprintf(&buffer[i], buffer_size - i, "%d",
total_edges_ - started_edges_);
break;
// Finished edges.
case 'f':
- i += snprintf(&buff[i], kBUFF_SIZE - i, "%d", finished_edges_);
+ i += snprintf(&buffer[i], buffer_size - i, "%d", finished_edges_);
break;
default:
- return printf("!! unknown placeholders '%c' in NINJA_STATUS !! ",
- *s);
- break;
+ if (err != NULL) {
+ ostringstream oss;
+ oss << "unknown placeholders '%" << *s << "' in NINJA_STATUS";
+ *err = oss.str();
+ }
+ return -1;
}
} else {
- buff[i] = *s;
+ buffer[i] = *s;
++i;
}
}
- if (i >= kBUFF_SIZE)
- return printf("!! custom NINJA_STATUS exceed buffer size %d !! ",
- kBUFF_SIZE);
- else {
- buff[i] = '\0';
- return printf("%s", buff);
+ if (i >= buffer_size) {
+ if (err != NULL) {
+ ostringstream oss;
+ oss << "custom NINJA_STATUS exceed buffer size " << buffer_size;
+ *err = oss.str();
+ }
+ return -1;
+ } else {
+ buffer[i] = '\0';
+ if (err != NULL)
+ *err = "";
+ return i;
}
}
+int BuildStatus::PrintProgressStatus() const {
+ const int kBUFF_SIZE = 1024;
+ char buff[kBUFF_SIZE] = { '\0' };
+ string err;
+ int progress_chars = FormatProgressStatus(progress_status_format_,
+ buff,
+ kBUFF_SIZE,
+ &err);
+ if (progress_chars < 0)
+ return printf("!! %s !! ", err.c_str());
+ else
+ return printf("%s", buff);
+}
+
void BuildStatus::PrintStatus(Edge* edge) {
if (config_.verbosity == BuildConfig::QUIET)
return;
diff --git a/src/build.h b/src/build.h
index 179fca6..8078910 100644
--- a/src/build.h
+++ b/src/build.h
@@ -149,4 +149,62 @@ private:
void operator=(const Builder &other); // DO NOT IMPLEMENT
};
+/// Tracks the status of a build: completion fraction, printing updates.
+struct BuildStatus {
+ BuildStatus(const BuildConfig& config);
+ void PlanHasTotalEdges(int total);
+ void BuildEdgeStarted(Edge* edge);
+ void BuildEdgeFinished(Edge* edge, bool success, const string& output,
+ int* start_time, int* end_time);
+ void BuildFinished();
+
+ /// 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.
+ /// @param buffer The buffer where is stored the formatted progress status.
+ /// @param buffer_size The size of the given @a buffer.
+ /// @param err The error message if -1 is returned.
+ /// @return The number of characters inserted in @a buffer and -1 on error.
+ int FormatProgressStatus(const char* progress_status_format,
+ char* buffer,
+ const int buffer_size,
+ string* err) const;
+
+ private:
+ void PrintStatus(Edge* edge);
+
+ /// Print the progress status.
+ ///
+ /// Get the status from the NINJA_STATUS environment variable if defined.
+ ///
+ /// @return The number of printed characters.
+ int PrintProgressStatus() const;
+
+ const BuildConfig& config_;
+
+ /// Time the build started.
+ int64_t start_time_millis_;
+ /// Time we last printed an update.
+ int64_t last_update_millis_;
+
+ int started_edges_, finished_edges_, total_edges_;
+
+ bool have_blank_line_;
+
+ /// Map of running edge to time the edge started running.
+ typedef map<Edge*, int> RunningEdgeMap;
+ RunningEdgeMap running_edges_;
+
+ /// Whether we can do fancy terminal control codes.
+ bool smart_terminal_;
+
+ /// The custom progress status format to use.
+ const char* progress_status_format_;
+
+#ifdef _WIN32
+ HANDLE console_;
+#endif
+};
+
#endif // NINJA_BUILD_H_
diff --git a/src/build_test.cc b/src/build_test.cc
index 467a908..f3f5472 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -179,7 +179,7 @@ TEST_F(PlanTest, DependencyCycle) {
struct BuildTest : public StateTestWithBuiltinRules,
public CommandRunner {
BuildTest() : config_(MakeConfig()), builder_(&state_, config_), now_(1),
- last_command_(NULL) {
+ last_command_(NULL), status_(config_) {
builder_.disk_interface_ = &fs_;
builder_.command_runner_.reset(this);
AssertParse(&state_,
@@ -219,6 +219,7 @@ struct BuildTest : public StateTestWithBuiltinRules,
vector<string> commands_ran_;
Edge* last_command_;
+ BuildStatus status_;
};
void BuildTest::Dirty(const string& path) {
@@ -1022,3 +1023,37 @@ TEST_F(BuildTest, PhonyWithNoInputs) {
EXPECT_EQ("", err);
ASSERT_EQ(1u, commands_ran_.size());
}
+
+TEST_F(BuildTest, StatusFormatBufferTooSmall) {
+ const int kBUFF_SIZE = 5;
+ char buff[kBUFF_SIZE] = { '\0' };
+ string err;
+
+ EXPECT_EQ(-1, status_.FormatProgressStatus("0123456789",
+ buff, kBUFF_SIZE,
+ &err));
+ EXPECT_EQ("custom NINJA_STATUS exceed buffer size 5", err);
+}
+
+TEST_F(BuildTest, StatusFormatWrongPlaceholder) {
+ const int kBUFF_SIZE = 1024;
+ char buff[kBUFF_SIZE] = { '\0' };
+ string err;
+
+ EXPECT_EQ(-1, status_.FormatProgressStatus("[%r/%X]",
+ buff, kBUFF_SIZE,
+ &err));
+ EXPECT_EQ("unknown placeholders '%X' in NINJA_STATUS", err);
+}
+
+TEST_F(BuildTest, StatusFormatReplacePlaceholder) {
+ const int kBUFF_SIZE = 1024;
+ char buff[kBUFF_SIZE] = { '\0' };
+ string err;
+
+ EXPECT_EQ(18, status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]",
+ buff, kBUFF_SIZE,
+ &err));
+ EXPECT_EQ("", err);
+ EXPECT_STREQ("[%/s0/t0/r0/u0/f0]", buff);
+}