Simplify adb LinePrinter newline handling.

We had mostly-working hacks before, but it's time to just modify LinePrinter
to suit our needs. If we tell LinePrinter what kind of output we're giving
it, it can manage things automatically.

This fixes the minor bug where we'd sometimes have a blank line after an
error message.

Change-Id: I07ff52437f2402de311e237dd1b2dd338d9b668a
This commit is contained in:
Elliott Hughes 2015-12-08 16:01:15 -08:00
parent 1631d36d95
commit 77f539ab49
3 changed files with 33 additions and 89 deletions

View File

@ -76,6 +76,8 @@ class SyncConnection {
ReadOrderlyShutdown(fd);
}
adb_close(fd);
line_printer_.KeepInfoLine();
}
bool IsValid() { return fd >= 0; }
@ -243,8 +245,7 @@ class SyncConnection {
}
void Print(const std::string& s) {
// TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
line_printer_.Print(s, LinePrinter::ELIDE);
line_printer_.Print(s, LinePrinter::INFO);
}
void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@ -265,7 +266,7 @@ class SyncConnection {
android::base::StringAppendV(&s, fmt, ap);
va_end(ap);
line_printer_.Print(s, LinePrinter::FULL);
line_printer_.Print(s, LinePrinter::ERROR);
}
void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@ -276,7 +277,7 @@ class SyncConnection {
android::base::StringAppendV(&s, fmt, ap);
va_end(ap);
line_printer_.Print(s, LinePrinter::FULL);
line_printer_.Print(s, LinePrinter::WARNING);
}
uint64_t total_bytes;
@ -664,7 +665,7 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
}
}
sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
pushed, (pushed == 1) ? "" : "s", skipped,
(skipped == 1) ? "" : "s", sc.TransferRate().c_str());
return true;
@ -739,7 +740,6 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
}
sc.Print("\n");
return success;
}
@ -858,7 +858,7 @@ static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
}
}
sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
pulled, (pulled == 1) ? "" : "s", skipped,
(skipped == 1) ? "" : "s", sc.TransferRate().c_str());
return true;
@ -967,7 +967,6 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
}
}
sc.Print("\n");
return success;
}

View File

@ -43,7 +43,7 @@ string ElideMiddle(const string& str, size_t width) {
return result;
}
LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) {
LinePrinter::LinePrinter() : have_blank_line_(true) {
#ifndef _WIN32
const char* term = getenv("TERM");
smart_terminal_ = unix_isatty(1) && term && string(term) != "dumb";
@ -59,20 +59,24 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) {
#endif
}
static void Out(const std::string& s) {
// Avoid printf and C strings, since the actual output might contain null
// bytes like UTF-16 does (yuck).
fwrite(s.data(), 1, s.size(), stdout);
}
void LinePrinter::Print(string to_print, LineType type) {
if (console_locked_) {
line_buffer_ = to_print;
line_type_ = type;
if (!smart_terminal_) {
Out(to_print);
return;
}
if (smart_terminal_) {
printf("\r"); // Print over previous line, if any.
// On Windows, calling a C library function writing to stdout also handles
// pausing the executable when the "Pause" key or Ctrl-S is pressed.
}
// Print over previous line, if any.
// On Windows, calling a C library function writing to stdout also handles
// pausing the executable when the "Pause" key or Ctrl-S is pressed.
printf("\r");
if (smart_terminal_ && type == ELIDE) {
if (type == INFO) {
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(console_, &csbi);
@ -105,57 +109,19 @@ void LinePrinter::Print(string to_print, LineType type) {
if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) {
to_print = ElideMiddle(to_print, size.ws_col);
}
printf("%s", to_print.c_str());
Out(to_print);
printf("\x1B[K"); // Clear to end of line.
fflush(stdout);
#endif
have_blank_line_ = false;
} else {
printf("%s\n", to_print.c_str());
Out(to_print);
Out("\n");
have_blank_line_ = true;
}
}
void LinePrinter::PrintOrBuffer(const char* data, size_t size) {
if (console_locked_) {
output_buffer_.append(data, size);
} else {
// Avoid printf and C strings, since the actual output might contain null
// bytes like UTF-16 does (yuck).
fwrite(data, 1, size, stdout);
}
}
void LinePrinter::PrintOnNewLine(const string& to_print) {
if (console_locked_ && !line_buffer_.empty()) {
output_buffer_.append(line_buffer_);
output_buffer_.append(1, '\n');
line_buffer_.clear();
}
if (!have_blank_line_) {
PrintOrBuffer("\n", 1);
}
if (!to_print.empty()) {
PrintOrBuffer(&to_print[0], to_print.size());
}
have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n';
}
void LinePrinter::SetConsoleLocked(bool locked) {
if (locked == console_locked_)
return;
if (locked)
PrintOnNewLine("");
console_locked_ = locked;
if (!locked) {
PrintOnNewLine(output_buffer_);
if (!line_buffer_.empty()) {
Print(line_buffer_, line_type_);
}
output_buffer_.clear();
line_buffer_.clear();
}
void LinePrinter::KeepInfoLine() {
if (!have_blank_line_) Out("\n");
}

View File

@ -26,20 +26,14 @@ struct LinePrinter {
bool is_smart_terminal() const { return smart_terminal_; }
void set_smart_terminal(bool smart) { smart_terminal_ = smart; }
enum LineType {
FULL,
ELIDE
};
/// Overprints the current line. If type is ELIDE, elides to_print to fit on
/// one line.
enum LineType { INFO, WARNING, ERROR };
/// Outputs the given line. INFO output will be overwritten.
/// WARNING and ERROR appear on a line to themselves.
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);
/// Lock or unlock the console. Any output sent to the LinePrinter while the
/// console is locked will not be printed until it is unlocked.
void SetConsoleLocked(bool locked);
/// If there's an INFO line, keep it. If not, do nothing.
void KeepInfoLine();
private:
/// Whether we can do fancy terminal control codes.
@ -48,24 +42,9 @@ struct LinePrinter {
/// Whether the caret is at the beginning of a blank line.
bool have_blank_line_;
/// Whether console is locked.
bool console_locked_;
/// Buffered current line while console is locked.
std::string line_buffer_;
/// Buffered line type while console is locked.
LineType line_type_;
/// Buffered console output while console is locked.
std::string output_buffer_;
#ifdef _WIN32
void* console_;
#endif
/// Print the given data to the console, or buffer it if it is locked.
void PrintOrBuffer(const char *data, size_t size);
};
#endif // NINJA_LINE_PRINTER_H_