fancier output
authorEvan Martin <martine@danga.com>
Sat, 5 Feb 2011 19:29:04 +0000 (11:29 -0800)
committerEvan Martin <martine@danga.com>
Sat, 5 Feb 2011 19:29:04 +0000 (11:29 -0800)
src/build.cc
src/build.h

index 3e3482c..b380845 100644 (file)
@@ -15,6 +15,8 @@ struct BuildStatus {
   // Returns the time the edge took, in ms.
   int BuildEdgeFinished(Edge* edge);
 
+  void PrintStatus(Edge* edge);
+
   time_t last_update_;
   int finished_edges_, total_edges_;
 
@@ -22,11 +24,16 @@ struct BuildStatus {
   RunningEdgeMap running_edges_;
 
   BuildConfig::Verbosity verbosity_;
+  // Whether we can do fancy terminal control codes.
+  bool smart_terminal_;
 };
 
 BuildStatus::BuildStatus()
     : last_update_(time(NULL)), finished_edges_(0), total_edges_(0),
-      verbosity_(BuildConfig::NORMAL) {}
+      verbosity_(BuildConfig::NORMAL) {
+  const char* term = getenv("TERM");
+  smart_terminal_ = isatty(1) && term && string(term) != "dumb";
+}
 
 void BuildStatus::PlanHasTotalEdges(int total) {
   total_edges_ = total;
@@ -37,13 +44,7 @@ void BuildStatus::BuildEdgeStarted(Edge* edge) {
   gettimeofday(&now, NULL);
   running_edges_.insert(make_pair(edge, now));
 
-  string desc = edge->GetDescription();
-  if (verbosity_ != BuildConfig::QUIET) {
-    if (verbosity_ != BuildConfig::VERBOSE && !desc.empty())
-      printf("%s\n", desc.c_str());
-    else
-      printf("%s\n", edge->EvaluateCommand().c_str());
-  }
+  PrintStatus(edge);
 }
 
 int BuildStatus::BuildEdgeFinished(Edge* edge) {
@@ -51,10 +52,18 @@ int BuildStatus::BuildEdgeFinished(Edge* edge) {
   gettimeofday(&now, NULL);
   ++finished_edges_;
 
-  if (now.tv_sec - last_update_ > 5) {
-    printf("%.1f%% %d/%d\n", finished_edges_ * 100 / (float)total_edges_,
-           finished_edges_, total_edges_);
-    last_update_ = now.tv_sec;
+  if (verbosity_ != BuildConfig::QUIET) {
+    if (smart_terminal_ && verbosity_ == BuildConfig::NORMAL) {
+      PrintStatus(edge);
+      if (finished_edges_ == total_edges_)
+        printf("\n");
+    } else {
+      if (now.tv_sec - last_update_ > 5) {
+        printf("%.1f%% %d/%d\n", finished_edges_ * 100 / (float)total_edges_,
+               finished_edges_, total_edges_);
+        last_update_ = now.tv_sec;
+      }
+    }
   }
 
   RunningEdgeMap::iterator i = running_edges_.find(edge);
@@ -66,6 +75,33 @@ int BuildStatus::BuildEdgeFinished(Edge* edge) {
   return ms;
 }
 
+void BuildStatus::PrintStatus(Edge* edge) {
+  switch (verbosity_) {
+  case BuildConfig::QUIET:
+    return;
+
+  case BuildConfig::VERBOSE:
+    printf("%s\n", edge->EvaluateCommand().c_str());
+    break;
+
+  default: {
+    string to_print = edge->GetDescription();
+    if (to_print.empty() || verbosity_ == BuildConfig::VERBOSE)
+      to_print = edge->EvaluateCommand();
+
+    if (smart_terminal_) {
+      printf("\r[%d/%d] %s\e[K", finished_edges_, total_edges_,
+             to_print.c_str());
+      fflush(stdout);
+    } else {
+      printf("%s\n", to_print.c_str());
+    }
+  }
+  }
+}
+
+Plan::Plan() : command_edges_(0) {}
+
 bool Plan::AddTarget(Node* node, string* err) {
   vector<Node*> stack;
   return AddSubTarget(node, &stack, err);
@@ -93,6 +129,8 @@ bool Plan::AddSubTarget(Node* node, vector<Node*>* stack, string* err) {
   if (want_.find(edge) != want_.end())
     return true;  // We've already enqueued it.
   want_.insert(edge);
+  if (!edge->is_phony())
+    ++command_edges_;
 
   stack->push_back(node);
   bool awaiting_inputs = false;
@@ -302,7 +340,7 @@ bool Builder::Build(string* err) {
     return true;
   }
 
-  status_->PlanHasTotalEdges(plan_.edge_count());
+  status_->PlanHasTotalEdges(plan_.command_edge_count());
   while (plan_.more_to_do()) {
     while (command_runner_->CanRunMore()) {
       Edge* edge = plan_.FindWork();
index a1d6d4c..618cc28 100644 (file)
@@ -15,6 +15,8 @@ struct State;
 // Plan stores the state of a build plan: what we intend to build,
 // which steps we're ready to execute.
 struct Plan {
+  Plan();
+
   // Add a target to our plan (including all its dependencies).
   // Returns false if we don't need to build this target; may
   // fill in |err| with an error message if there's a problem.
@@ -34,8 +36,8 @@ struct Plan {
   // tests.
   void EdgeFinished(Edge* edge);
 
-  // Number of edges to run.
-  int edge_count() const { return want_.size(); }
+  // Number of edges with commands to run.
+  int command_edge_count() const { return command_edges_; }
 
 private:
   bool AddSubTarget(Node* node, vector<Node*>* stack, string* err);
@@ -44,6 +46,9 @@ private:
 
   set<Edge*> want_;
   set<Edge*> ready_;
+
+  // Total number of edges that have commands (not phony).
+  int command_edges_;
 };
 
 // CommandRunner is an interface that wraps running the build