Permalink
Browse files

move single-line printing to new class

  • Loading branch information...
nico committed Apr 9, 2013
1 parent 94f999b commit 10d1c939ae788bfb410eb37c7e71da2be07797f9
Showing with 162 additions and 92 deletions.
  1. +1 −0 configure.py
  2. +9 −88 src/build.cc
  3. +3 −4 src/build.h
  4. +98 −0 src/line_printer.cc
  5. +37 −0 src/line_printer.h
  6. +14 −0 src/ninja_test.cc
View
@@ -276,6 +276,7 @@ def has_re2c():
'graph',
'graphviz',
'lexer',
'line_printer',
'manifest_parser',
'metrics',
'state',
View
@@ -19,14 +19,6 @@
#include <stdlib.h>
#include <functional>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#endif
#if defined(__SVR4) && defined(__sun)
#include <sys/termios.h>
#endif
@@ -80,25 +72,12 @@ BuildStatus::BuildStatus(const BuildConfig& config)
: config_(config),
start_time_millis_(GetTimeMillis()),
started_edges_(0), finished_edges_(0), total_edges_(0),
have_blank_line_(true), progress_status_format_(NULL),
progress_status_format_(NULL),
overall_rate_(), current_rate_(config.parallelism) {
#ifndef _WIN32
const char* term = getenv("TERM");
smart_terminal_ = isatty(1) && term && string(term) != "dumb";
#else
// Disable output buffer. It'd be nice to use line buffering but
// MSDN says: "For some systems, [_IOLBF] provides line
// buffering. However, for Win32, the behavior is the same as _IOFBF
// - Full Buffering."
setvbuf(stdout, NULL, _IONBF, 0);
console_ = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
#endif
// Don't do anything fancy in verbose mode.
if (config_.verbosity != BuildConfig::NORMAL)
smart_terminal_ = false;
printer_.smart_terminal_ = false;
progress_status_format_ = getenv("NINJA_STATUS");
if (!progress_status_format_)
@@ -133,11 +112,11 @@ void BuildStatus::BuildEdgeFinished(Edge* edge,
if (config_.verbosity == BuildConfig::QUIET)
return;
if (smart_terminal_)
if (printer_.smart_terminal_)
PrintStatus(edge);
if (!success || !output.empty()) {
if (smart_terminal_)
if (printer_.smart_terminal_)
printf("\n");
// Print the command that is spewing before printing its output.
@@ -157,20 +136,20 @@ void BuildStatus::BuildEdgeFinished(Edge* edge,
// thousands of parallel compile commands.)
// TODO: There should be a flag to disable escape code stripping.
string final_output;
if (!smart_terminal_)
if (!printer_.smart_terminal_)
final_output = StripAnsiEscapeCodes(output);
else
final_output = output;
if (!final_output.empty())
printf("%s", final_output.c_str());
have_blank_line_ = true;
printer_.have_blank_line_ = true;
}
}
void BuildStatus::BuildFinished() {
if (smart_terminal_ && !have_blank_line_)
if (printer_.smart_terminal_ && !printer_.have_blank_line_)
printf("\n");
}
@@ -267,72 +246,14 @@ void BuildStatus::PrintStatus(Edge* edge) {
if (to_print.empty() || force_full_command)
to_print = edge->GetBinding("command");
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(console_, &csbi);
#endif
if (smart_terminal_) {
#ifndef _WIN32
printf("\r"); // Print over previous line, if any.
#else
csbi.dwCursorPosition.X = 0;
SetConsoleCursorPosition(console_, csbi.dwCursorPosition);
#endif
}
if (finished_edges_ == 0) {
overall_rate_.Restart();
current_rate_.Restart();
}
to_print = FormatProgressStatus(progress_status_format_) + to_print;
if (smart_terminal_ && !force_full_command) {
#ifndef _WIN32
// Limit output to width of the terminal if provided so we don't cause
// line-wrapping.
winsize size;
if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) {
to_print = ElideMiddle(to_print, size.ws_col);
}
#else
// Don't use the full width or console will move to next line.
size_t width = static_cast<size_t>(csbi.dwSize.X) - 1;
to_print = ElideMiddle(to_print, width);
#endif
}
if (smart_terminal_ && !force_full_command) {
#ifndef _WIN32
printf("%s", to_print.c_str());
printf("\x1B[K"); // Clear to end of line.
fflush(stdout);
have_blank_line_ = false;
#else
// We don't want to have the cursor spamming back and forth, so
// use WriteConsoleOutput instead which updates the contents of
// the buffer, but doesn't move the cursor position.
GetConsoleScreenBufferInfo(console_, &csbi);
COORD buf_size = { csbi.dwSize.X, 1 };
COORD zero_zero = { 0, 0 };
SMALL_RECT target = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,
(SHORT)(csbi.dwCursorPosition.X + csbi.dwSize.X - 1),
csbi.dwCursorPosition.Y };
CHAR_INFO* char_data = new CHAR_INFO[csbi.dwSize.X];
memset(char_data, 0, sizeof(CHAR_INFO) * csbi.dwSize.X);
for (int i = 0; i < csbi.dwSize.X; ++i) {
char_data[i].Char.AsciiChar = ' ';
char_data[i].Attributes = csbi.wAttributes;
}
for (size_t i = 0; i < to_print.size(); ++i)
char_data[i].Char.AsciiChar = to_print[i];
WriteConsoleOutput(console_, char_data, buf_size, zero_zero, &target);
delete[] char_data;
have_blank_line_ = false;
#endif
} else {
printf("%s\n", to_print.c_str());
}
printer_.Print(to_print,
force_full_command ? LinePrinter::FULL : LinePrinter::SHORT);
}
Plan::Plan() : command_edges_(0), wanted_edges_(0) {}
View
@@ -25,6 +25,7 @@
#include "graph.h" // XXX needed for DependencyScan; should rearrange.
#include "exit_status.h"
#include "line_printer.h"
#include "metrics.h"
#include "util.h" // int64_t
@@ -198,14 +199,12 @@ struct BuildStatus {
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_;
/// Prints progress output.
LinePrinter printer_;
/// The custom progress status format to use.
const char* progress_status_format_;
View
@@ -0,0 +1,98 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "line_printer.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#endif
#include "util.h"
LinePrinter::LinePrinter() : have_blank_line_(true) {
#ifndef _WIN32
const char* term = getenv("TERM");
smart_terminal_ = isatty(1) && term && string(term) != "dumb";
#else
// Disable output buffer. It'd be nice to use line buffering but
// MSDN says: "For some systems, [_IOLBF] provides line
// buffering. However, for Win32, the behavior is the same as _IOFBF
// - Full Buffering."
setvbuf(stdout, NULL, _IONBF, 0);
console_ = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
#endif
}
void LinePrinter::Print(std::string to_print, LineType type) {

This comment has been minimized.

Show comment
Hide comment
@tfarina

tfarina May 5, 2013

Contributor

const std::string& ?

@tfarina

tfarina May 5, 2013

Contributor

const std::string& ?

This comment has been minimized.

Show comment
Hide comment
@nico

nico May 6, 2013

Collaborator

This is assigned to below. It could be a std::string&, but then there would have to be a local variable that's initialized by the reference, so it doesn't really seem worth it?

@nico

nico May 6, 2013

Collaborator

This is assigned to below. It could be a std::string&, but then there would have to be a local variable that's initialized by the reference, so it doesn't really seem worth it?

#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(console_, &csbi);
#endif
if (smart_terminal_) {
#ifndef _WIN32
printf("\r"); // Print over previous line, if any.
#else
csbi.dwCursorPosition.X = 0;
SetConsoleCursorPosition(console_, csbi.dwCursorPosition);
#endif
}
if (smart_terminal_ && type == SHORT) {
#ifdef _WIN32
// Don't use the full width or console will move to next line.
size_t width = static_cast<size_t>(csbi.dwSize.X) - 1;
to_print = ElideMiddle(to_print, width);
// We don't want to have the cursor spamming back and forth, so
// use WriteConsoleOutput instead which updates the contents of
// the buffer, but doesn't move the cursor position.
GetConsoleScreenBufferInfo(console_, &csbi);
COORD buf_size = { csbi.dwSize.X, 1 };
COORD zero_zero = { 0, 0 };
SMALL_RECT target = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,
(SHORT)(csbi.dwCursorPosition.X + csbi.dwSize.X - 1),
csbi.dwCursorPosition.Y };
CHAR_INFO* char_data = new CHAR_INFO[csbi.dwSize.X];
memset(char_data, 0, sizeof(CHAR_INFO) * csbi.dwSize.X);
for (int i = 0; i < csbi.dwSize.X; ++i) {
char_data[i].Char.AsciiChar = ' ';
char_data[i].Attributes = csbi.wAttributes;
}
for (size_t i = 0; i < to_print.size(); ++i)
char_data[i].Char.AsciiChar = to_print[i];
WriteConsoleOutput(console_, char_data, buf_size, zero_zero, &target);
delete[] char_data;
#else
// Limit output to width of the terminal if provided so we don't cause
// line-wrapping.
winsize size;
if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) {
to_print = ElideMiddle(to_print, size.ws_col);
}
printf("%s", to_print.c_str());
printf("\x1B[K"); // Clear to end of line.
fflush(stdout);
#endif
have_blank_line_ = false;
} else {
printf("%s\n", to_print.c_str());
}
}
View
@@ -0,0 +1,37 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NINJA_LINE_PRINTER_H_
#define NINJA_LINE_PRINTER_H_
#include <string>
class LinePrinter {
public:
LinePrinter();
enum LineType {
FULL,
SHORT
};
void Print(std::string to_print, LineType type);
//private:
/// Whether we can do fancy terminal control codes.
bool smart_terminal_;
bool have_blank_line_;
};
#endif // NINJA_LINE_PRINTER_H_
View
@@ -1,3 +1,17 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gtest/gtest.h"
/// A test result printer that's less wordy than gtest's default.

0 comments on commit 10d1c93

Please sign in to comment.