From 77f539ab4918514706f986f77529c17a38650be0 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 8 Dec 2015 16:01:15 -0800 Subject: [PATCH] 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 --- adb/file_sync_client.cpp | 15 ++++---- adb/line_printer.cpp | 74 +++++++++++----------------------------- adb/line_printer.h | 33 ++++-------------- 3 files changed, 33 insertions(+), 89 deletions(-) diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp index 463c1c0d1..239aaf8c0 100644 --- a/adb/file_sync_client.cpp +++ b/adb/file_sync_client.cpp @@ -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& 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& srcs, const char* dst, } } - sc.Print("\n"); return success; } diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp index 4c57c7eba..e8fe6c97d 100644 --- a/adb/line_printer.cpp +++ b/adb/line_printer.cpp @@ -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"); } diff --git a/adb/line_printer.h b/adb/line_printer.h index 3d0a5bd73..42345e2d6 100644 --- a/adb/line_printer.h +++ b/adb/line_printer.h @@ -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_