Skip to content

Commit

Permalink
Merge pull request #532 from nico/sshhh_gtest
Browse files Browse the repository at this point in the history
Make test runner less chatty.
  • Loading branch information
evmar committed Apr 9, 2013
2 parents 9f1852f + 5b04aad commit 76c8b11
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 106 deletions.
5 changes: 2 additions & 3 deletions configure.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ def has_re2c():
'graph', 'graph',
'graphviz', 'graphviz',
'lexer', 'lexer',
'line_printer',
'manifest_parser', 'manifest_parser',
'metrics', 'metrics',
'state', 'state',
Expand Down Expand Up @@ -331,9 +332,6 @@ def has_re2c():
objs += n.build(built('gtest-all' + objext), 'cxx', objs += n.build(built('gtest-all' + objext), 'cxx',
os.path.join(path, 'src', 'gtest-all.cc'), os.path.join(path, 'src', 'gtest-all.cc'),
variables=[('cflags', gtest_cflags)]) variables=[('cflags', gtest_cflags)])
objs += n.build(built('gtest_main' + objext), 'cxx',
os.path.join(path, 'src', 'gtest_main.cc'),
variables=[('cflags', gtest_cflags)])


test_cflags.append('-I%s' % os.path.join(path, 'include')) test_cflags.append('-I%s' % os.path.join(path, 'include'))
else: else:
Expand All @@ -353,6 +351,7 @@ def has_re2c():
'graph_test', 'graph_test',
'lexer_test', 'lexer_test',
'manifest_parser_test', 'manifest_parser_test',
'ninja_test',
'state_test', 'state_test',
'subprocess_test', 'subprocess_test',
'test', 'test',
Expand Down
111 changes: 12 additions & 99 deletions src/build.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <functional> #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) #if defined(__SVR4) && defined(__sun)
#include <sys/termios.h> #include <sys/termios.h>
#endif #endif
Expand Down Expand Up @@ -80,25 +72,12 @@ BuildStatus::BuildStatus(const BuildConfig& config)
: config_(config), : config_(config),
start_time_millis_(GetTimeMillis()), start_time_millis_(GetTimeMillis()),
started_edges_(0), finished_edges_(0), total_edges_(0), 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) { 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. // Don't do anything fancy in verbose mode.
if (config_.verbosity != BuildConfig::NORMAL) if (config_.verbosity != BuildConfig::NORMAL)
smart_terminal_ = false; printer_.set_smart_terminal(false);


progress_status_format_ = getenv("NINJA_STATUS"); progress_status_format_ = getenv("NINJA_STATUS");
if (!progress_status_format_) if (!progress_status_format_)
Expand Down Expand Up @@ -133,17 +112,14 @@ void BuildStatus::BuildEdgeFinished(Edge* edge,
if (config_.verbosity == BuildConfig::QUIET) if (config_.verbosity == BuildConfig::QUIET)
return; return;


if (smart_terminal_) if (printer_.is_smart_terminal())
PrintStatus(edge); PrintStatus(edge);


if (!success || !output.empty()) { // Print the command that is spewing before printing its output.
if (smart_terminal_) if (!success)
printf("\n"); printer_.PrintOnNewLine("FAILED: " + edge->EvaluateCommand() + "\n");

// Print the command that is spewing before printing its output.
if (!success)
printf("FAILED: %s\n", edge->EvaluateCommand().c_str());


if (!output.empty()) {
// ninja sets stdout and stderr of subprocesses to a pipe, to be able to // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
// check if the output is empty. Some compilers, e.g. clang, check // check if the output is empty. Some compilers, e.g. clang, check
// isatty(stderr) to decide if they should print colored output. // isatty(stderr) to decide if they should print colored output.
Expand All @@ -157,21 +133,16 @@ void BuildStatus::BuildEdgeFinished(Edge* edge,
// thousands of parallel compile commands.) // thousands of parallel compile commands.)
// TODO: There should be a flag to disable escape code stripping. // TODO: There should be a flag to disable escape code stripping.
string final_output; string final_output;
if (!smart_terminal_) if (!printer_.is_smart_terminal())
final_output = StripAnsiEscapeCodes(output); final_output = StripAnsiEscapeCodes(output);
else else
final_output = output; final_output = output;

printer_.PrintOnNewLine(final_output);
if (!final_output.empty())
printf("%s", final_output.c_str());

have_blank_line_ = true;
} }
} }


void BuildStatus::BuildFinished() { void BuildStatus::BuildFinished() {
if (smart_terminal_ && !have_blank_line_) printer_.PrintOnNewLine("");
printf("\n");
} }


string BuildStatus::FormatProgressStatus( string BuildStatus::FormatProgressStatus(
Expand Down Expand Up @@ -267,72 +238,14 @@ void BuildStatus::PrintStatus(Edge* edge) {
if (to_print.empty() || force_full_command) if (to_print.empty() || force_full_command)
to_print = edge->GetBinding("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) { if (finished_edges_ == 0) {
overall_rate_.Restart(); overall_rate_.Restart();
current_rate_.Restart(); current_rate_.Restart();
} }
to_print = FormatProgressStatus(progress_status_format_) + to_print; to_print = FormatProgressStatus(progress_status_format_) + to_print;


if (smart_terminal_ && !force_full_command) { printer_.Print(to_print,
#ifndef _WIN32 force_full_command ? LinePrinter::FULL : LinePrinter::SHORT);
// 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());
}
} }


Plan::Plan() : command_edges_(0), wanted_edges_(0) {} Plan::Plan() : command_edges_(0), wanted_edges_(0) {}
Expand Down
7 changes: 3 additions & 4 deletions src/build.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@


#include "graph.h" // XXX needed for DependencyScan; should rearrange. #include "graph.h" // XXX needed for DependencyScan; should rearrange.
#include "exit_status.h" #include "exit_status.h"
#include "line_printer.h"
#include "metrics.h" #include "metrics.h"
#include "util.h" // int64_t #include "util.h" // int64_t


Expand Down Expand Up @@ -198,14 +199,12 @@ struct BuildStatus {


int started_edges_, finished_edges_, total_edges_; int started_edges_, finished_edges_, total_edges_;


bool have_blank_line_;

/// Map of running edge to time the edge started running. /// Map of running edge to time the edge started running.
typedef map<Edge*, int> RunningEdgeMap; typedef map<Edge*, int> RunningEdgeMap;
RunningEdgeMap running_edges_; RunningEdgeMap running_edges_;


/// Whether we can do fancy terminal control codes. /// Prints progress output.
bool smart_terminal_; LinePrinter printer_;


/// The custom progress status format to use. /// The custom progress status format to use.
const char* progress_status_format_; const char* progress_status_format_;
Expand Down
107 changes: 107 additions & 0 deletions src/line_printer.cc
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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"

#include <stdio.h>
#include <stdlib.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) {
#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());
}
}

void LinePrinter::PrintOnNewLine(const string& to_print) {
if (!have_blank_line_)
printf("\n");
printf("%s", to_print.c_str());
have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n';
}
48 changes: 48 additions & 0 deletions src/line_printer.h
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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>

/// Prints lines of text, possibly overprinting previously printed lines
/// if the terminal supports it.
class LinePrinter {
public:
LinePrinter();

bool is_smart_terminal() const { return smart_terminal_; }
void set_smart_terminal(bool smart) { smart_terminal_ = smart; }

enum LineType {
FULL,
SHORT
};
/// Overprints the current line. If type is SHORT, elides to_print to fit on
/// one line.
void Print(std::string to_print, LineType type);

/// Prints a string on a new line, not overprinting previous output.
void PrintOnNewLine(const std::string& to_print);

private:
/// Whether we can do fancy terminal control codes.
bool smart_terminal_;

/// Whether the caret is at the beginning of a blank line.
bool have_blank_line_;
};

#endif // NINJA_LINE_PRINTER_H_
Loading

0 comments on commit 76c8b11

Please sign in to comment.