From df0bc2f70cce898ca2f04171fafc3131b2eb7fbe Mon Sep 17 00:00:00 2001 From: mwrock Date: Fri, 22 Feb 2019 18:05:28 -0800 Subject: [PATCH 01/10] use console api instead of ansi codes on windows Signed-off-by: mwrock --- Cargo.lock | 21 +- components/common/Cargo.toml | 3 +- components/common/src/ui.rs | 445 ++++++------------ components/hab/Cargo.toml | 2 +- .../hab/src/command/bldr/job/promote.rs | 3 +- components/hab/src/command/pkg/binlink.rs | 3 +- components/hab/src/main.rs | 14 +- components/launcher/Cargo.toml | 1 - components/pkg-export-docker/Cargo.toml | 1 + components/pkg-export-docker/src/build.rs | 3 +- components/sup-client/Cargo.toml | 1 + components/sup-client/src/lib.rs | 10 + components/sup-protocol/protocols/ctl.proto | 3 +- .../sup-protocol/src/generated/sup.ctl.rs | 4 + components/sup/Cargo.toml | 2 +- components/sup/src/ctl_gateway/mod.rs | 58 +-- components/sup/src/main.rs | 9 +- 17 files changed, 229 insertions(+), 354 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94f8b39994..d23fee12bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -827,7 +827,6 @@ dependencies = [ name = "hab" version = "0.0.0" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -857,6 +856,7 @@ dependencies = [ "tabwriter 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,6 @@ dependencies = [ name = "habitat-launcher" version = "0.0.0" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "habitat-launcher-protocol 0.0.0", "habitat_core 0.0.0 (git+https://github.com/habitat-sh/core.git)", @@ -921,6 +920,7 @@ dependencies = [ "prost 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "protoc 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "protoc-rust 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1016,7 +1016,6 @@ dependencies = [ name = "habitat_common" version = "0.0.0" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "habitat_api_client 0.0.0", @@ -1037,7 +1036,7 @@ dependencies = [ "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.5.1 (git+https://github.com/habitat-sh/term)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1121,6 +1120,7 @@ dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1192,7 +1192,6 @@ version = "0.0.0" dependencies = [ "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "caps 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1232,6 +1231,7 @@ dependencies = [ "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2807,16 +2807,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "term" -version = "0.5.1" -source = "git+https://github.com/habitat-sh/term#1b646454f859178295e7fdf41c8205add8003131" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termcolor" version = "1.0.4" @@ -3850,7 +3840,6 @@ dependencies = [ "checksum tee 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c12559dba7383625faaff75be24becf35bfc885044375bcab931111799a3da" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" -"checksum term 0.5.1 (git+https://github.com/habitat-sh/term)" = "" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" diff --git a/components/common/Cargo.toml b/components/common/Cargo.toml index bb26f67aeb..1b3cf82966 100644 --- a/components/common/Cargo.toml +++ b/components/common/Cargo.toml @@ -7,7 +7,6 @@ build = "../build-habitat.rs" workspace = "../../" [dependencies] -ansi_term = "*" bimap = "*" glob = "*" # The handlebars crate has a few issues that require us to lock at 0.28.3 @@ -36,7 +35,7 @@ serde-transcode = "*" serde_yaml = "*" tempfile = "*" retry = "*" -term = { git = "https://github.com/habitat-sh/term" } +termcolor = "*" time = "*" toml = { version = "*", default-features = false } uuid = { version = "*", features = ["v4"] } diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index af91864174..a21ed972d3 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -27,11 +27,13 @@ use std::{env, use uuid::Uuid; use crate::api_client::DisplayProgress; -use ansi_term::Colour; use pbr; -use term::{terminfo::TermInfo, - Terminal, - TerminfoTerminal}; +use termcolor::{self, + Color, + ColorChoice, + ColorSpec, + StandardStream, + WriteColor}; use self::tty::StdStream; use crate::error::{Error, @@ -79,42 +81,42 @@ pub enum Status { } impl Status { - pub fn parts(&self) -> (char, String, Colour) { + pub fn parts(&self) -> (char, String, Color) { match *self { - Status::Applying => ('↑', "Applying".into(), Colour::Green), - Status::Added => ('↑', "Added".into(), Colour::Green), - Status::Adding => ('☛', "Adding".into(), Colour::Green), - Status::Canceled => ('✓', "Canceled".into(), Colour::Green), - Status::Canceling => ('☛', "Canceling".into(), Colour::Green), - Status::Cached => ('☑', "Cached".into(), Colour::Green), - Status::Created => ('✓', "Created".into(), Colour::Green), - Status::Creating => ('Ω', "Creating".into(), Colour::Green), - Status::Deleted => ('✓', "Deleted".into(), Colour::Green), - Status::Deleting => ('☒', "Deleting".into(), Colour::Green), - Status::Demoted => ('✓', "Demoted".into(), Colour::Green), - Status::Demoting => ('→', "Demoting".into(), Colour::Green), - Status::Determining => ('☁', "Determining".into(), Colour::Green), - Status::Downloading => ('↓', "Downloading".into(), Colour::Green), - Status::DryRunDeleting => ('☒', "Would be deleted (Dry run)".into(), Colour::Red), - Status::Encrypting => ('☛', "Encrypting".into(), Colour::Green), - Status::Encrypted => ('✓', "Encrypted".into(), Colour::Green), - Status::Executing => ('☛', "Executing".into(), Colour::Green), - Status::Found => ('→', "Found".into(), Colour::Cyan), - Status::Generated => ('→', "Generated".into(), Colour::Cyan), - Status::Generating => ('☛', "Generating".into(), Colour::Green), - Status::Installed => ('✓', "Installed".into(), Colour::Green), - Status::Missing => ('∵', "Missing".into(), Colour::Red), - Status::Promoted => ('✓', "Promoted".into(), Colour::Green), - Status::Promoting => ('→', "Promoting".into(), Colour::Green), - Status::Signed => ('✓', "Signed".into(), Colour::Cyan), - Status::Signing => ('☛', "Signing".into(), Colour::Cyan), - Status::Skipping => ('…', "Skipping".into(), Colour::Green), - Status::Uploaded => ('✓', "Uploaded".into(), Colour::Green), - Status::Uploading => ('↑', "Uploading".into(), Colour::Green), - Status::Using => ('→', "Using".into(), Colour::Green), - Status::Verified => ('✓', "Verified".into(), Colour::Green), - Status::Verifying => ('☛', "Verifying".into(), Colour::Green), - Status::Custom(c, ref s) => (c, s.to_string(), Colour::Green), + Status::Applying => ('↑', "Applying".into(), Color::Green), + Status::Added => ('↑', "Added".into(), Color::Green), + Status::Adding => ('☛', "Adding".into(), Color::Green), + Status::Canceled => ('✓', "Canceled".into(), Color::Green), + Status::Canceling => ('☛', "Canceling".into(), Color::Green), + Status::Cached => ('☑', "Cached".into(), Color::Green), + Status::Created => ('✓', "Created".into(), Color::Green), + Status::Creating => ('Ω', "Creating".into(), Color::Green), + Status::Deleted => ('✓', "Deleted".into(), Color::Green), + Status::Deleting => ('☒', "Deleting".into(), Color::Green), + Status::Demoted => ('✓', "Demoted".into(), Color::Green), + Status::Demoting => ('→', "Demoting".into(), Color::Green), + Status::Determining => ('☁', "Determining".into(), Color::Green), + Status::Downloading => ('↓', "Downloading".into(), Color::Green), + Status::DryRunDeleting => ('☒', "Would be deleted (Dry run)".into(), Color::Red), + Status::Encrypting => ('☛', "Encrypting".into(), Color::Green), + Status::Encrypted => ('✓', "Encrypted".into(), Color::Green), + Status::Executing => ('☛', "Executing".into(), Color::Green), + Status::Found => ('→', "Found".into(), Color::Cyan), + Status::Generated => ('→', "Generated".into(), Color::Cyan), + Status::Generating => ('☛', "Generating".into(), Color::Green), + Status::Installed => ('✓', "Installed".into(), Color::Green), + Status::Missing => ('∵', "Missing".into(), Color::Red), + Status::Promoted => ('✓', "Promoted".into(), Color::Green), + Status::Promoting => ('→', "Promoting".into(), Color::Green), + Status::Signed => ('✓', "Signed".into(), Color::Cyan), + Status::Signing => ('☛', "Signing".into(), Color::Cyan), + Status::Skipping => ('…', "Skipping".into(), Color::Green), + Status::Uploaded => ('✓', "Uploaded".into(), Color::Green), + Status::Uploading => ('↑', "Uploading".into(), Color::Green), + Status::Using => ('→', "Using".into(), Color::Green), + Status::Verified => ('✓', "Verified".into(), Color::Green), + Status::Verifying => ('☛', "Verifying".into(), Color::Green), + Status::Custom(c, ref s) => (c, s.to_string(), Color::Green), } } } @@ -130,18 +132,18 @@ pub trait UIReader { fn prompt_yes_no(&mut self, question: &str, default: Option) -> Result; } +pub trait ColorPrinter { + fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()>; +} + /// Functions applied to an IO stream for sending information to a UI. pub trait UIWriter { type ProgressBar: DisplayProgress; /// IO Stream for sending error messages to. - fn err(&mut self) -> &mut dyn io::Write; + fn err(&mut self) -> &mut dyn ColorPrinter; /// IO Stream for sending normal or informational messages to. - fn out(&mut self) -> &mut dyn io::Write; - /// Messages sent to the normal or informational IO stream will be formatted in color if true. - fn is_out_colored(&self) -> bool; - /// Messages sent to the error IO stream will be formatted in color if true. - fn is_err_colored(&self) -> bool; + fn out(&mut self) -> &mut dyn ColorPrinter; /// Messages sent to the normal or informational IO stream will be formatted for a terminal if /// true. fn is_out_a_terminal(&self) -> bool; @@ -156,18 +158,11 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '»'; - let formatted = if self.is_out_colored() { - format!( - "{}\n", - Colour::Yellow - .bold() - .paint(format!("{} {}", symbol, message)) - ) - } else { - format!("{} {}\n", symbol, message) - }; - self.out().write_all(formatted.as_bytes())?; - self.out().flush() + self.out().print( + format!("{} {}\n", symbol, message).as_bytes(), + Some(Color::Yellow), + true, + ) } /// Write a message formatted with `end`. @@ -176,16 +171,8 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '★'; - let formatted = if self.is_out_colored() { - format!( - "{}\n", - Colour::Blue.bold().paint(format!("{} {}", symbol, message)) - ) - } else { - format!("{} {}\n", symbol, message) - }; - self.out().write_all(formatted.as_bytes())?; - self.out().flush() + self.out() + .print(format!("{} {}\n", symbol, message).as_bytes(), Some(Color::Magenta), true) } /// Write a message formatted with `status`. @@ -194,17 +181,9 @@ pub trait UIWriter { T: fmt::Display, { let (symbol, status_str, color) = status.parts(); - let formatted = if self.is_out_colored() { - format!( - "{} {}\n", - color.bold().paint(format!("{} {}", symbol, status_str)), - message - ) - } else { - format!("{} {} {}\n", symbol, status_str, message) - }; - self.out().write_all(formatted.as_bytes())?; - self.out().flush() + self.out() + .print(format!("{} {}", symbol, status_str).as_bytes(), Some(color), true)?; + self.out().print(format!(" {}\n", message).as_bytes(), None, false) } /// Write a message formatted with `info`. @@ -212,8 +191,7 @@ pub trait UIWriter { where T: fmt::Display, { - self.out().write_all(format!("{}\n", text).as_bytes())?; - self.out().flush() + self.out().print(format!("{}\n", text).as_bytes(), None, false) } /// Write a message formatted with `warn`. @@ -221,16 +199,8 @@ pub trait UIWriter { where T: fmt::Display, { - let formatted = if self.is_err_colored() { - format!( - "{}\n", - Colour::Yellow.bold().paint(format!("∅ {}", message)) - ) - } else { - format!("∅ {}\n", message) - }; - self.err().write_all(formatted.as_bytes())?; - self.err().flush() + self.err() + .print(format!("∅ {}\n", message).as_bytes(), Some(Color::Yellow), true) } /// Write a message formatted with `fatal`. @@ -238,27 +208,12 @@ pub trait UIWriter { where T: fmt::Display, { - let color = Colour::Red; - let formatted = if self.is_err_colored() { - let mut buf = format!("{}\n", color.bold().paint("✗✗✗")); - for line in message.to_string().lines() { - buf.push_str(&format!( - "{}\n", - color.bold().paint(format!("✗✗✗ {}", line)) - )); - } - buf.push_str(&format!("{}\n", color.bold().paint("✗✗✗"))); - buf - } else { - let mut buf = "✗✗✗\n".to_string(); - for line in message.to_string().lines() { - buf.push_str(&format!("✗✗✗ {}\n", line)); - } - buf.push_str("✗✗✗\n"); - buf - }; - self.err().write_all(formatted.as_bytes())?; - self.err().flush() + self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true)?; + for line in message.to_string().lines() { + self.err() + .print(format!("✗✗✗ {}\n", line).as_bytes(), Some(Color::Red), true)?; + } + self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true) } /// Write a message formatted with `title`. @@ -266,26 +221,16 @@ pub trait UIWriter { where T: AsRef, { - if self.is_out_colored() { - writeln!(self.out(), "{}", Colour::Green.bold().paint(text.as_ref()))?; - write!( - self.out(), - "{}\n\n", - Colour::Green.bold().paint(format!( - "{:=, { - let formatted = if self.is_out_colored() { - format!("{}\n\n", Colour::Green.bold().paint(text.as_ref())) - } else { - format!("{}\n\n", text.as_ref()) - }; - self.out().write_all(formatted.as_bytes())?; - self.out().flush() + self.out() + .print(format!("{}\n\n", text.as_ref()).as_bytes(), Some(Color::Green), true) } /// Write a message formatted with `para`. @@ -307,8 +247,7 @@ pub trait UIWriter { /// Write a line break message`. fn br(&mut self) -> io::Result<()> { - self.out().write_all(b"\n")?; - self.out().flush() + self.out().print(b"\n", None, false) } } @@ -323,7 +262,7 @@ impl UI { pub fn new(shell: Shell) -> Self { UI { shell } } /// Creates a new default `UI` with a coloring strategy and tty hinting. - pub fn default_with(coloring: Coloring, isatty: Option) -> Self { + pub fn default_with(coloring: ColorChoice, isatty: Option) -> Self { Self::new(Shell::default_with(coloring, isatty)) } @@ -342,9 +281,9 @@ impl UI { .map(|val| val == "1" || val == "true") .unwrap_or(false) { - Coloring::Never + ColorChoice::Never } else { - Coloring::Auto + ColorChoice::Auto }; let ui = UI::default_with(coloring, isatty); @@ -360,7 +299,7 @@ impl UI { stdin: Box, stdout_fn: O, stderr_fn: E, - coloring: Coloring, + coloring: ColorChoice, isatty: bool, ) -> Self where @@ -369,8 +308,8 @@ impl UI { { Self::new(Shell::new( InputStream::new(stdin, isatty), - OutputStream::new(WriteStream::create(stdout_fn), coloring, isatty), - OutputStream::new(WriteStream::create(stderr_fn), coloring, isatty), + OutputStream::new(WriteStream::from_write(stdout_fn), coloring, isatty), + OutputStream::new(WriteStream::from_write(stderr_fn), coloring, isatty), )) } @@ -381,26 +320,22 @@ impl UI { Box::new(io::empty()), || Box::new(io::sink()), || Box::new(io::sink()), - Coloring::Never, + ColorChoice::Never, false, ) } } impl Default for UI { - fn default() -> Self { UI::default_with(Coloring::Auto, None) } + fn default() -> Self { UI::default_with(ColorChoice::Auto, None) } } impl UIWriter for UI { type ProgressBar = ConsoleProgressBar; - fn out(&mut self) -> &mut dyn io::Write { &mut self.shell.out } + fn out(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.out } - fn err(&mut self) -> &mut dyn io::Write { &mut self.shell.err } - - fn is_out_colored(&self) -> bool { self.shell.out.is_colored() } - - fn is_err_colored(&self) -> bool { self.shell.err.is_colored() } + fn err(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.err } fn is_out_a_terminal(&self) -> bool { self.shell.out.is_a_terminal() } @@ -422,32 +357,16 @@ impl UIReader for UI { fn prompt_yes_no(&mut self, question: &str, default: Option) -> Result { let stream = &mut self.shell.out; - let choice = { - let (prefix, default_text, suffix) = match default { - Some(true) => ("[", "Yes", "/no/quit]"), - Some(false) => ("[yes/", "No", "/quit]"), - None => ("[yes/no/quit]", "", ""), - }; - if stream.is_colored() { - format!( - "{}{}{}", - Colour::White.paint(prefix), - Colour::White.bold().paint(default_text), - Colour::White.paint(suffix) - ) - } else { - format!("{}{}{}", prefix, default_text, suffix) - } - }; - let question = if stream.is_colored() { - Colour::Cyan.paint(question).to_string() - } else { - question.to_string() + let (prefix, default_text, suffix) = match default { + Some(true) => ("[", "Yes", "/no/quit]"), + Some(false) => ("[yes/", "No", "/quit]"), + None => ("[yes/no/quit]", "", ""), }; loop { - stream.flush()?; - write!(stream, "{} {} ", question, choice)?; - stream.flush()?; + stream.print(question.as_bytes(), Some(Color::Cyan), false)?; + stream.print(format!(" {}", prefix).as_bytes(), Some(Color::White), false)?; + stream.print(default_text.as_bytes(), Some(Color::White), true)?; + stream.print(format!("{} ", suffix).as_bytes(), Some(Color::White), false)?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -468,25 +387,15 @@ impl UIReader for UI { fn prompt_ask(&mut self, question: &str, default: Option<&str>) -> Result { let stream = &mut self.shell.out; - let choice = match default { - Some(d) if stream.is_colored() => format!( - "{}{}{}", - Colour::White.paint("[default: "), - Colour::White.bold().paint(d), - Colour::White.paint("]") - ), - Some(d) => format!("[default: {}]", d), - None => "".to_string(), - }; - let question = if stream.is_colored() { - Colour::Cyan.paint(question).to_string() - } else { - question.to_string() - }; loop { - stream.flush()?; - write!(stream, "{}: {} ", question, choice)?; - stream.flush()?; + stream.print(question.as_bytes(), Some(Color::Cyan), false)?; + stream.print(b": ", None, false)?; + if let Some(d) = default { + stream.print(b"[default: ", Some(Color::White), false)?; + stream.print(d.as_bytes(), Some(Color::White), true)?; + stream.print(b"]", Some(Color::White), false)?; + } + stream.print(b" ", None, false)?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -550,7 +459,7 @@ impl Shell { Shell { input, out, err } } - pub fn default_with(coloring: Coloring, isatty: Option) -> Self { + pub fn default_with(coloring: ColorChoice, isatty: Option) -> Self { let stdin = InputStream::from_stdin(isatty); let stdout = OutputStream::from_stdout(coloring, isatty); let stderr = OutputStream::from_stderr(coloring, isatty); @@ -565,14 +474,7 @@ impl Shell { } impl Default for Shell { - fn default() -> Self { Shell::default_with(Coloring::Auto, None) } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Coloring { - Auto, - Always, - Never, + fn default() -> Self { Shell::default_with(ColorChoice::Auto, None) } } pub struct InputStream { @@ -608,12 +510,12 @@ impl fmt::Debug for InputStream { pub struct OutputStream { inner: WriteStream, - coloring: Coloring, + coloring: ColorChoice, isatty: bool, } impl OutputStream { - pub fn new(inner: WriteStream, coloring: Coloring, isatty: bool) -> Self { + pub fn new(inner: WriteStream, coloring: ColorChoice, isatty: bool) -> Self { OutputStream { inner, coloring, @@ -621,9 +523,9 @@ impl OutputStream { } } - pub fn from_stdout(coloring: Coloring, isatty: Option) -> Self { + pub fn from_stdout(coloring: ColorChoice, isatty: Option) -> Self { Self::new( - WriteStream::create(|| Box::new(io::stdout())), + WriteStream::from_stdout(coloring), coloring, match isatty { Some(val) => val, @@ -632,9 +534,9 @@ impl OutputStream { ) } - pub fn from_stderr(coloring: Coloring, isatty: Option) -> Self { + pub fn from_stderr(coloring: ColorChoice, isatty: Option) -> Self { Self::new( - WriteStream::create(|| Box::new(io::stderr())), + WriteStream::from_stderr(coloring), coloring, match isatty { Some(val) => val, @@ -643,33 +545,24 @@ impl OutputStream { ) } - pub fn supports_color(&self) -> bool { - match self.inner { - WriteStream::Color(_) => true, - WriteStream::NoColor(_) => false, - } - } - - pub fn is_colored(&self) -> bool { - self.supports_color() - && (Coloring::Auto == self.coloring || Coloring::Always == self.coloring) - } - pub fn is_a_terminal(&self) -> bool { self.isatty } } -impl Write for OutputStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.inner { - WriteStream::Color(ref mut io) => io.write(buf), - WriteStream::NoColor(ref mut io) => io.write(buf), - } - } - - fn flush(&mut self) -> io::Result<()> { +impl ColorPrinter for OutputStream { + fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> + { match self.inner { - WriteStream::Color(ref mut io) => io.flush(), - WriteStream::NoColor(ref mut io) => io.flush(), + WriteStream::Stream(ref mut stream) => { + stream.reset()?; + stream.set_color(ColorSpec::new().set_bold(bold).set_fg(color))?; + stream.write_all(buf)?; + stream.flush()?; + stream.reset() + } + WriteStream::Write(ref mut w) => { + w.write(buf)?; + w.flush() + } } } } @@ -678,70 +571,35 @@ impl fmt::Debug for OutputStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "OutputStream {{ coloring: {:?}, isatty: {}, is_colored(): {}, supports_color(): {} }}", - self.coloring, - self.isatty, - self.is_colored(), - self.supports_color(), + "OutputStream {{ coloring: {:?}, isatty: {} }}", + self.coloring, self.isatty, ) } } pub enum WriteStream { - NoColor(Box), - Color(Box> + Send>), + /// A plain write object without color support + Write(Box), + /// Color-enabled stdio, with information on whether color should be used + Stream(StandardStream), } impl WriteStream { // Implementation heavily inspired and based on the Cargo `shell.rs` implementation. Source: - // https://github.com/rust-lang/cargo/blob/d05ba53afec82308edcfeb778446010bf18e71ae/ + // https://github.com/rust-lang/cargo/blob/5c6aa46e6f28661270979696e7b4c2f0dff8628f/ // src/cargo/core/shell.rs - pub fn create Box>(mut writable_fn: T) -> Self { - match Self::get_term(writable_fn()) { - Ok(t) => t, - Err(_) => WriteStream::NoColor(writable_fn()), - } + pub fn from_stdout(coloring: ColorChoice) -> Self { + WriteStream::Stream(StandardStream::stdout(coloring)) } - #[cfg(any(windows))] - fn get_term(writeable: Box) -> Result { - // Check if the creation of a console will succeed - if ::term::WinConsole::new(vec![0u8; 0]).is_ok() { - let term = ::term::WinConsole::new(writeable)?; - if !term.supports_color() { - Ok(WriteStream::NoColor(Box::new(term))) - } else { - Ok(WriteStream::Color(Box::new(term))) - } - } else { - // If we fail to get a windows console, we try to get a `TermInfo` one - Ok(Self::get_terminfo_term(writeable)) - } + pub fn from_stderr(coloring: ColorChoice) -> Self { + WriteStream::Stream(StandardStream::stderr(coloring)) } - #[cfg(any(unix))] - fn get_term(writeable: Box) -> Result { - Ok(Self::get_terminfo_term(writeable)) - } - - fn get_terminfo_term(writeable: Box) -> Self { - // Use `TermInfo::from_env()` and `TerminfoTerminal::supports_color()` to determine if - // creation of a TerminfoTerminal is possible regardless of the tty status. --color options - // are parsed after Shell creation so always try to create a terminal that supports color - // output. Fall back to a no-color terminal regardless of whether or not a tty is present - // and if color output is not possible. - match TermInfo::from_env() { - Ok(info) => { - let term = TerminfoTerminal::new_with_terminfo(writeable, info); - if !term.supports_color() { - WriteStream::NoColor(term.into_inner()) - } else { - WriteStream::Color(Box::new(term)) - } - } - Err(_) => WriteStream::NoColor(writeable), - } + /// Create a shell from a plain writable object, with no color, and max verbosity. + pub fn from_write Box>(mut writable_fn: T) -> Self { + WriteStream::Write(writable_fn()) } } @@ -838,14 +696,13 @@ impl Write for ConsoleProgressBar { fn flush(&mut self) -> io::Result<()> { self.bar.flush() } } -pub fn print_wrapped( - mut stream: T, +pub fn print_wrapped( + stream: &mut dyn ColorPrinter, text: U, wrap_width: usize, left_indent: usize, ) -> io::Result<()> where - T: io::Write, U: AsRef, { for line in text.as_ref().split("\n\n") { @@ -854,7 +711,11 @@ where for word in line.split_whitespace() { let wl = word.chars().count(); if (width + wl + 1) > (wrap_width - left_indent) { - writeln!(stream, "{: result::Result<(), SrvClientError> { let m = reply .parse::() .map_err(SrvClientError::Decode)?; - print!("{}", m); + let c = match m.color { + Some(color) => Some(Color::from_str(&color)?), + None => None, + }; + UI::default_with_env().out().print(m.line.as_bytes(), c, m.bold)?; } "NetProgress" => { let m = reply @@ -1771,9 +1775,9 @@ fn user_param_or_env(m: &ArgMatches<'_>) -> Option { // the scope of change contained. fn ui() -> UI { let coloring = if hcore::output::is_color() { - Coloring::Auto + ColorChoice::Auto } else { - Coloring::Never + ColorChoice::Never }; let isatty = if env::var(NONINTERACTIVE_ENVVAR) .map(|val| val == "1" || val == "true") diff --git a/components/launcher/Cargo.toml b/components/launcher/Cargo.toml index 814d946990..12160a04f6 100644 --- a/components/launcher/Cargo.toml +++ b/components/launcher/Cargo.toml @@ -11,7 +11,6 @@ path = "src/main.rs" doc = false [dependencies] -ansi_term = "*" env_logger = "*" # JW TODO: core has external deps that we don't want, libarchive/libsodium. We should either # put these things behind a feature flag so we can statically compile the launcher. diff --git a/components/pkg-export-docker/Cargo.toml b/components/pkg-export-docker/Cargo.toml index f78cbd097d..ac3273b71d 100644 --- a/components/pkg-export-docker/Cargo.toml +++ b/components/pkg-export-docker/Cargo.toml @@ -32,6 +32,7 @@ rusoto_ecr = "*" serde = { version = "*", features = ["rc"] } serde_json = "*" tempfile = "*" +termcolor = "*" url = "*" failure = "*" failure_derive = "*" diff --git a/components/pkg-export-docker/src/build.rs b/components/pkg-export-docker/src/build.rs index 12ed5fdf7e..dd4dd4aaef 100644 --- a/components/pkg-export-docker/src/build.rs +++ b/components/pkg-export-docker/src/build.rs @@ -912,6 +912,7 @@ mod test { Write}, sync::{Arc, RwLock}}; + use termcolor::ColorChoice; use crate::{common::ui::{Coloring, UI}, @@ -1003,7 +1004,7 @@ mod test { Box::new(io::empty()), || Box::new(stdout_buf.clone()), || Box::new(stderr_buf.clone()), - Coloring::Never, + ColorChoice::Never, false, ); diff --git a/components/sup-client/Cargo.toml b/components/sup-client/Cargo.toml index 0c01347455..c5872c58f4 100644 --- a/components/sup-client/Cargo.toml +++ b/components/sup-client/Cargo.toml @@ -11,6 +11,7 @@ habitat-sup-protocol = { path = "../sup-protocol", default-features = false } habitat_common = { path = "../common" } log = "*" prost = "*" +termcolor = "*" tokio = "*" tokio-core = "*" tokio-codec = "*" diff --git a/components/sup-client/src/lib.rs b/components/sup-client/src/lib.rs index 8907692819..40c25902cc 100644 --- a/components/sup-client/src/lib.rs +++ b/components/sup-client/src/lib.rs @@ -74,6 +74,8 @@ pub enum SrvClientError { Io(io::Error), /// An RPC call to the remote was received but failed. NetErr(NetErr), + /// A parse error from an Invalid Color string + ParseColor(termcolor::ParseColorError), } impl error::Error for SrvClientError { @@ -84,6 +86,7 @@ impl error::Error for SrvClientError { SrvClientError::Decode(ref err) => err.description(), SrvClientError::Io(ref err) => err.description(), SrvClientError::NetErr(ref err) => err.description(), + SrvClientError::ParseColor(ref err) => err.description(), } } } @@ -107,6 +110,7 @@ impl fmt::Display for SrvClientError { err ), SrvClientError::NetErr(ref err) => format!("{}", err), + SrvClientError::ParseColor(ref err) => format!("{}", err), }; write!(f, "{}", content) } @@ -124,6 +128,12 @@ impl From for SrvClientError { fn from(err: prost::DecodeError) -> Self { SrvClientError::Decode(err) } } +impl From for SrvClientError { + fn from(err: termcolor::ParseColorError) -> Self { + SrvClientError::ParseColor(err) + } +} + /// Client for connecting and communicating with a server listener which speaks SrvProtocol. /// /// See module doc for usage. diff --git a/components/sup-protocol/protocols/ctl.proto b/components/sup-protocol/protocols/ctl.proto index 9017336db2..3acc21a528 100644 --- a/components/sup-protocol/protocols/ctl.proto +++ b/components/sup-protocol/protocols/ctl.proto @@ -126,5 +126,6 @@ message SvcStatus { // A reply to various requests which contains a pre-formatted console line. message ConsoleLine { required string line = 1; + optional string color = 2; + required bool bold = 3; } - diff --git a/components/sup-protocol/src/generated/sup.ctl.rs b/components/sup-protocol/src/generated/sup.ctl.rs index f071caadd8..4702b74630 100644 --- a/components/sup-protocol/src/generated/sup.ctl.rs +++ b/components/sup-protocol/src/generated/sup.ctl.rs @@ -190,4 +190,8 @@ pub struct SvcStatus { pub struct ConsoleLine { #[prost(string, required, tag="1")] pub line: String, + #[prost(string, optional, tag="2")] + pub color: ::std::option::Option, + #[prost(bool, required, tag="3")] + pub bold: bool, } diff --git a/components/sup/Cargo.toml b/components/sup/Cargo.toml index e7b9dd3e22..b0189dc867 100644 --- a/components/sup/Cargo.toml +++ b/components/sup/Cargo.toml @@ -17,7 +17,6 @@ doc = false [dependencies] actix = "*" actix-web = { version = "*", default-features = false, features = [ "rust-tls" ] } -ansi_term = "*" bitflags = "*" byteorder = "*" clap = { version = "*", features = [ "suggestions", "color", "unstable" ] } @@ -50,6 +49,7 @@ serde_json = "*" serde_yaml = "*" serde-transcode = "*" tempfile = "*" +termcolor = "*" time = "*" toml = { version = "*", default-features = false } tokio = "*" diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index a27422d7ca..9aee35ae7e 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -31,9 +31,11 @@ use std::{borrow::Cow, path::Path}; use regex::Regex; +use termcolor::{Buffer, Color, ColorSpec, WriteColor}; use crate::{api_client::DisplayProgress, - common::ui::UIWriter, + common::ui::{ColorPrinter, + UIWriter}, hcore::{self, output}, protocol}; @@ -127,27 +129,9 @@ impl CtlRequest { impl UIWriter for CtlRequest { type ProgressBar = NetProgressBar; - fn out(&mut self) -> &mut dyn io::Write { self } + fn out(&mut self) -> &mut dyn ColorPrinter { self } - fn err(&mut self) -> &mut dyn io::Write { self } - - // Whether output is colored, or the output is a terminal is, - // technically, a bit more complicated than simply `true`, since - // output from the CtlRequest ends up being streamed back to the - // client (which may or may not be an interactive terminal, by the - // way), as well as being rendered into the Supervisor's output - // streams, which have their own, possibly opposing, formatting - // constraints. - // - // For the time being, this is mostly addressed manually down in - // the `io::Write` implementation. Furthermore, this is currently - // the only implementation of UIWriter subject to these - // constraints, so it's not clear that adding additional - // complexity at the type / trait modeling level is worthwhile. - - fn is_out_colored(&self) -> bool { true } - - fn is_err_colored(&self) -> bool { true } + fn err(&mut self) -> &mut dyn ColorPrinter { self } fn is_out_a_terminal(&self) -> bool { true } @@ -162,16 +146,16 @@ impl UIWriter for CtlRequest { } } -impl io::Write for CtlRequest { - fn write(&mut self, buf: &[u8]) -> io::Result { - let line = String::from_utf8_lossy(buf).into_owned(); - +impl ColorPrinter for CtlRequest { + fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> { // The protocol reply is destined for the client, so (for now, - // at least), we'll retain any colored output. + // at least), we'll apply colored output. // // `line` will also have a newline character at the end, FYI. let mut msg = protocol::ctl::ConsoleLine::default(); - msg.line = line.clone(); + msg.line = String::from_utf8_lossy(buf).to_string(); + msg.color = color_to_string(color); + msg.bold = bold; self.reply_partial(msg); // Down here, however, we're doing double-duty by *also* @@ -185,6 +169,17 @@ impl io::Write for CtlRequest { // be nice to find a cleaner way to model this, but the fact // that CtlRequest is sending output to two destinations with // different formatting requirements complicates things a bit. + // + // TODO (MW): For `han sup run` scenarios, it would be nice to + // support color on older versions of Windows. We could refactor + // outputln! to support a cross platform ColorWriter similar to + // what we use in common::UI. + let mut ansi_buffer = Buffer::ansi(); + ansi_buffer.set_color(ColorSpec::new().set_bold(bold).set_fg(color))?; + ansi_buffer.write_all(buf)?; + ansi_buffer.flush()?; + let line = String::from_utf8_lossy(ansi_buffer.as_slice()).to_string(); + let maybe_stripped = if output::is_json() || !output::is_color() { STRIP_ANSI_CODES.replace_all(&line, "") } else { @@ -194,10 +189,15 @@ impl io::Write for CtlRequest { // the macro outputln!("{}", maybe_stripped.trim_right_matches('\n')); - Ok(buf.len()) + Ok(()) } +} - fn flush(&mut self) -> io::Result<()> { Ok(()) } +fn color_to_string(color: Option) -> Option { + match color { + Some(c) => Some(format!("{:?}", c).to_string()), + None => None, + } } /// A wrapper around a [`protocol.ctl.NetProgress`] and [`CtlRequest`]. This type implements diff --git a/components/sup/src/main.rs b/components/sup/src/main.rs index c8f9af1047..37846f2e98 100644 --- a/components/sup/src/main.rs +++ b/components/sup/src/main.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate ansi_term; extern crate clap; extern crate env_logger; extern crate hab; @@ -48,11 +47,11 @@ use std::{env, process, str::{self, FromStr}}; +use termcolor::ColorChoice; use crate::{common::{cli_defaults::GOSSIP_DEFAULT_PORT, command::package::install::InstallSource, - ui::{Coloring, - NONINTERACTIVE_ENVVAR, + ui::{NONINTERACTIVE_ENVVAR, UI}}, hcore::{crypto::{self, default_cache_key_path, @@ -491,9 +490,9 @@ fn set_supervisor_logging_options(m: &ArgMatches) { // the scope of change contained. fn ui() -> UI { let coloring = if hcore::output::is_color() { - Coloring::Auto + ColorChoice::Auto } else { - Coloring::Never + ColorChoice::Never }; let isatty = if env::var(NONINTERACTIVE_ENVVAR) .map(|val| val == "1" || val == "true") From 1fe19f7b01dedcf8d4b236eb602d476c764b0571 Mon Sep 17 00:00:00 2001 From: mwrock Date: Mon, 25 Feb 2019 10:45:20 -0800 Subject: [PATCH 02/10] run rustfmt Signed-off-by: mwrock --- components/common/src/ui.rs | 147 ++++++++++++++++---------- components/hab/src/main.rs | 119 +++++++++------------ components/sup-client/src/lib.rs | 23 ++-- components/sup/src/ctl_gateway/mod.rs | 57 ++++++---- 4 files changed, 191 insertions(+), 155 deletions(-) diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index a21ed972d3..85bdcf6011 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -12,32 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{env, - fmt, - fs::{self, - File}, - io::{self, - BufRead, - BufReader, - Read, - Stdout, - Write}, - process::{self, - Command}}; +use std::{ + env, fmt, + fs::{self, File}, + io::{self, BufRead, BufReader, Read, Stdout, Write}, + process::{self, Command}, +}; use uuid::Uuid; use crate::api_client::DisplayProgress; use pbr; -use termcolor::{self, - Color, - ColorChoice, - ColorSpec, - StandardStream, - WriteColor}; +use termcolor::{self, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use self::tty::StdStream; -use crate::error::{Error, - Result}; +use crate::error::{Error, Result}; pub const NONINTERACTIVE_ENVVAR: &str = "HAB_NONINTERACTIVE"; @@ -171,8 +159,11 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '★'; - self.out() - .print(format!("{} {}\n", symbol, message).as_bytes(), Some(Color::Magenta), true) + self.out().print( + format!("{} {}\n", symbol, message).as_bytes(), + Some(Color::Magenta), + true, + ) } /// Write a message formatted with `status`. @@ -181,9 +172,13 @@ pub trait UIWriter { T: fmt::Display, { let (symbol, status_str, color) = status.parts(); + self.out().print( + format!("{} {}", symbol, status_str).as_bytes(), + Some(color), + true, + )?; self.out() - .print(format!("{} {}", symbol, status_str).as_bytes(), Some(color), true)?; - self.out().print(format!(" {}\n", message).as_bytes(), None, false) + .print(format!(" {}\n", message).as_bytes(), None, false) } /// Write a message formatted with `info`. @@ -191,7 +186,8 @@ pub trait UIWriter { where T: fmt::Display, { - self.out().print(format!("{}\n", text).as_bytes(), None, false) + self.out() + .print(format!("{}\n", text).as_bytes(), None, false) } /// Write a message formatted with `warn`. @@ -199,8 +195,11 @@ pub trait UIWriter { where T: fmt::Display, { - self.err() - .print(format!("∅ {}\n", message).as_bytes(), Some(Color::Yellow), true) + self.err().print( + format!("∅ {}\n", message).as_bytes(), + Some(Color::Yellow), + true, + ) } /// Write a message formatted with `fatal`. @@ -208,12 +207,17 @@ pub trait UIWriter { where T: fmt::Display, { - self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true)?; + self.err() + .print("✗✗✗\n".as_bytes(), Some(Color::Red), true)?; for line in message.to_string().lines() { - self.err() - .print(format!("✗✗✗ {}\n", line).as_bytes(), Some(Color::Red), true)?; + self.err().print( + format!("✗✗✗ {}\n", line).as_bytes(), + Some(Color::Red), + true, + )?; } - self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true) + self.err() + .print("✗✗✗\n".as_bytes(), Some(Color::Red), true) } /// Write a message formatted with `title`. @@ -227,7 +231,8 @@ pub trait UIWriter { text.as_ref(), "", width = text.as_ref().chars().count() - ).as_bytes(), + ) + .as_bytes(), Some(Color::Green), true, ) @@ -238,12 +243,17 @@ pub trait UIWriter { where T: AsRef, { - self.out() - .print(format!("{}\n\n", text.as_ref()).as_bytes(), Some(Color::Green), true) + self.out().print( + format!("{}\n\n", text.as_ref()).as_bytes(), + Some(Color::Green), + true, + ) } /// Write a message formatted with `para`. - fn para(&mut self, text: &str) -> io::Result<()> { print_wrapped(self.out(), text, 75, 2) } + fn para(&mut self, text: &str) -> io::Result<()> { + print_wrapped(self.out(), text, 75, 2) + } /// Write a line break message`. fn br(&mut self) -> io::Result<()> { @@ -259,7 +269,9 @@ pub struct UI { impl UI { /// Creates a new `UI` from a `Shell`. - pub fn new(shell: Shell) -> Self { UI { shell } } + pub fn new(shell: Shell) -> Self { + UI { shell } + } /// Creates a new default `UI` with a coloring strategy and tty hinting. pub fn default_with(coloring: ColorChoice, isatty: Option) -> Self { @@ -327,19 +339,29 @@ impl UI { } impl Default for UI { - fn default() -> Self { UI::default_with(ColorChoice::Auto, None) } + fn default() -> Self { + UI::default_with(ColorChoice::Auto, None) + } } impl UIWriter for UI { type ProgressBar = ConsoleProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.out } + fn out(&mut self) -> &mut dyn ColorPrinter { + &mut self.shell.out + } - fn err(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.err } + fn err(&mut self) -> &mut dyn ColorPrinter { + &mut self.shell.err + } - fn is_out_a_terminal(&self) -> bool { self.shell.out.is_a_terminal() } + fn is_out_a_terminal(&self) -> bool { + self.shell.out.is_a_terminal() + } - fn is_err_a_terminal(&self) -> bool { self.shell.err.is_a_terminal() } + fn is_err_a_terminal(&self) -> bool { + self.shell.err.is_a_terminal() + } fn progress(&self) -> Option { if self.is_out_a_terminal() { @@ -466,15 +488,23 @@ impl Shell { Shell::new(stdin, stdout, stderr) } - pub fn input(&mut self) -> &mut InputStream { &mut self.input } + pub fn input(&mut self) -> &mut InputStream { + &mut self.input + } - pub fn out(&mut self) -> &mut OutputStream { &mut self.out } + pub fn out(&mut self) -> &mut OutputStream { + &mut self.out + } - pub fn err(&mut self) -> &mut OutputStream { &mut self.err } + pub fn err(&mut self) -> &mut OutputStream { + &mut self.err + } } impl Default for Shell { - fn default() -> Self { Shell::default_with(ColorChoice::Auto, None) } + fn default() -> Self { + Shell::default_with(ColorChoice::Auto, None) + } } pub struct InputStream { @@ -483,7 +513,9 @@ pub struct InputStream { } impl InputStream { - pub fn new(inner: Box, isatty: bool) -> Self { InputStream { inner, isatty } } + pub fn new(inner: Box, isatty: bool) -> Self { + InputStream { inner, isatty } + } pub fn from_stdin(isatty: Option) -> Self { Self::new( @@ -495,11 +527,15 @@ impl InputStream { ) } - pub fn is_a_terminal(&self) -> bool { self.isatty } + pub fn is_a_terminal(&self) -> bool { + self.isatty + } } impl Read for InputStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } } impl fmt::Debug for InputStream { @@ -545,12 +581,13 @@ impl OutputStream { ) } - pub fn is_a_terminal(&self) -> bool { self.isatty } + pub fn is_a_terminal(&self) -> bool { + self.isatty + } } impl ColorPrinter for OutputStream { - fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> - { + fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> { match self.inner { WriteStream::Stream(ref mut stream) => { stream.reset()?; @@ -624,9 +661,7 @@ mod tty { } #[cfg(windows)] pub fn isatty(output: StdStream) -> bool { - use winapi::um::{consoleapi, - processenv, - winbase}; + use winapi::um::{consoleapi, processenv, winbase}; let handle = match output { StdStream::Stdin => winbase::STD_INPUT_HANDLE, @@ -693,7 +728,9 @@ impl Write for ConsoleProgressBar { } } - fn flush(&mut self) -> io::Result<()> { self.bar.flush() } + fn flush(&mut self) -> io::Result<()> { + self.bar.flush() + } } pub fn print_wrapped( diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 66c5c56438..63411fc368 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -29,79 +29,60 @@ extern crate lazy_static; extern crate log; use pbr; -use std::{env, - ffi::OsString, - fs::File, - io::{self, - prelude::*, - Read}, - net::ToSocketAddrs, - path::{Path, - PathBuf}, - process, - result, - str::FromStr, - thread}; +use std::{ + env, + ffi::OsString, + fs::File, + io::{self, prelude::*, Read}, + net::ToSocketAddrs, + path::{Path, PathBuf}, + process, result, + str::FromStr, + thread, +}; use termcolor::{self, Color, ColorChoice}; #[cfg(windows)] use crate::hcore::crypto::dpapi::encrypt; -use crate::{common::{command::package::install::{InstallHookMode, - InstallMode, - InstallSource, - LocalPackageUsage}, - types::ListenCtlAddr, - ui::{Status, - UIWriter, - NONINTERACTIVE_ENVVAR, - UI}}, - hcore::{binlink::default_binlink_dir, - crypto::{default_cache_key_path, - init, - keys::PairType, - BoxKeyPair, - SigKeyPair}, - env as henv, - env::Config as EnvConfig, - fs::{cache_analytics_path, - cache_artifact_path, - cache_key_path, - launcher_root_path}, - package::{PackageIdent, - PackageTarget}, - ChannelIdent}}; -use clap::{ArgMatches, - Shell}; +use crate::{ + common::{ + command::package::install::{ + InstallHookMode, InstallMode, InstallSource, LocalPackageUsage, + }, + types::ListenCtlAddr, + ui::{Status, UIWriter, NONINTERACTIVE_ENVVAR, UI}, + }, + hcore::{ + binlink::default_binlink_dir, + crypto::{default_cache_key_path, init, keys::PairType, BoxKeyPair, SigKeyPair}, + env as henv, + env::Config as EnvConfig, + fs::{cache_analytics_path, cache_artifact_path, cache_key_path, launcher_root_path}, + package::{PackageIdent, PackageTarget}, + ChannelIdent, + }, +}; +use clap::{ArgMatches, Shell}; use futures::prelude::*; -use crate::{hcore::{service::{HealthCheckInterval, - ServiceGroup}, - url::{bldr_url_from_env, - default_bldr_url}}, - protocol::{codec::*, - ctl::ServiceBindList, - net::ErrCode, - types::*}, - sup_client::{SrvClient, - SrvClientError}}; +use crate::{ + hcore::{ + service::{HealthCheckInterval, ServiceGroup}, + url::{bldr_url_from_env, default_bldr_url}, + }, + protocol::{codec::*, ctl::ServiceBindList, net::ErrCode, types::*}, + sup_client::{SrvClient, SrvClientError}, +}; use tabwriter::TabWriter; -use hab::{analytics, - cli, - command::{self, - pkg::list::ListingType}, - config::{self, - Config}, - error::{Error, - Result}, - feat, - scaffolding, - AUTH_TOKEN_ENVVAR, - BLDR_URL_ENVVAR, - CTL_SECRET_ENVVAR, - ORIGIN_ENVVAR, - PRODUCT, - VERSION}; +use hab::{ + analytics, cli, + command::{self, pkg::list::ListingType}, + config::{self, Config}, + error::{Error, Result}, + feat, scaffolding, AUTH_TOKEN_ENVVAR, BLDR_URL_ENVVAR, CTL_SECRET_ENVVAR, ORIGIN_ENVVAR, + PRODUCT, VERSION, +}; /// Makes the --org CLI param optional when this env var is set const HABITAT_ORG_ENVVAR: &str = "HAB_ORG"; @@ -1511,7 +1492,9 @@ fn handle_ctl_reply(reply: SrvMessage) -> result::Result<(), SrvClientError> { Some(color) => Some(Color::from_str(&color)?), None => None, }; - UI::default_with_env().out().print(m.line.as_bytes(), c, m.bold)?; + UI::default_with_env() + .out() + .print(m.line.as_bytes(), c, m.bold)?; } "NetProgress" => { let m = reply @@ -1713,7 +1696,9 @@ fn get_password_from_input(m: &ArgMatches) -> Result> { } #[cfg(any(target_os = "linux", target_os = "macos"))] -fn get_password_from_input(_m: &ArgMatches<'_>) -> Result> { Ok(None) } +fn get_password_from_input(_m: &ArgMatches<'_>) -> Result> { + Ok(None) +} fn get_topology_from_input(m: &ArgMatches<'_>) -> Option { m.value_of("TOPOLOGY") diff --git a/components/sup-client/src/lib.rs b/components/sup-client/src/lib.rs index 40c25902cc..08f806202f 100644 --- a/components/sup-client/src/lib.rs +++ b/components/sup-client/src/lib.rs @@ -45,15 +45,10 @@ use habitat_sup_protocol as protocol; extern crate log; use habitat_common as common; -use std::{error, - fmt, - io, - path::PathBuf}; +use std::{error, fmt, io, path::PathBuf}; -use crate::protocol::{codec::*, - net::NetErr}; -use futures::{prelude::*, - sink}; +use crate::protocol::{codec::*, net::NetErr}; +use futures::{prelude::*, sink}; use tokio::net::TcpStream; use tokio_codec::Framed; @@ -117,15 +112,21 @@ impl fmt::Display for SrvClientError { } impl From for SrvClientError { - fn from(err: NetErr) -> Self { SrvClientError::NetErr(err) } + fn from(err: NetErr) -> Self { + SrvClientError::NetErr(err) + } } impl From for SrvClientError { - fn from(err: io::Error) -> Self { SrvClientError::Io(err) } + fn from(err: io::Error) -> Self { + SrvClientError::Io(err) + } } impl From for SrvClientError { - fn from(err: prost::DecodeError) -> Self { SrvClientError::Decode(err) } + fn from(err: prost::DecodeError) -> Self { + SrvClientError::Decode(err) + } } impl From for SrvClientError { diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index 9aee35ae7e..e4a9fc0933 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -22,27 +22,26 @@ pub mod server; -use std::{borrow::Cow, - fmt, - fs::{self, - File}, - io::{self, - Write}, - path::Path}; +use std::{ + borrow::Cow, + fmt, + fs::{self, File}, + io::{self, Write}, + path::Path, +}; use regex::Regex; use termcolor::{Buffer, Color, ColorSpec, WriteColor}; -use crate::{api_client::DisplayProgress, - common::ui::{ColorPrinter, - UIWriter}, - hcore::{self, - output}, - protocol}; +use crate::{ + api_client::DisplayProgress, + common::ui::{ColorPrinter, UIWriter}, + hcore::{self, output}, + protocol, +}; use futures::prelude::*; -use crate::error::{Error, - Result}; +use crate::error::{Error, Result}; lazy_static! { /// Shamelessly stolen from https://github.com/chalk/ansi-regex/blob/master/index.js @@ -107,7 +106,9 @@ impl CtlRequest { } /// Returns true if the request is transactional and false if not. - pub fn transactional(&self) -> bool { self.transaction.is_some() && self.tx.is_some() } + pub fn transactional(&self) -> bool { + self.transaction.is_some() && self.tx.is_some() + } fn send_msg(&mut self, msg: T, complete: bool) where @@ -129,13 +130,21 @@ impl CtlRequest { impl UIWriter for CtlRequest { type ProgressBar = NetProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { self } + fn out(&mut self) -> &mut dyn ColorPrinter { + self + } - fn err(&mut self) -> &mut dyn ColorPrinter { self } + fn err(&mut self) -> &mut dyn ColorPrinter { + self + } - fn is_out_a_terminal(&self) -> bool { true } + fn is_out_a_terminal(&self) -> bool { + true + } - fn is_err_a_terminal(&self) -> bool { true } + fn is_err_a_terminal(&self) -> bool { + true + } fn progress(&self) -> Option { if self.is_out_a_terminal() { @@ -218,7 +227,9 @@ impl NetProgressBar { } impl DisplayProgress for NetProgressBar { - fn size(&mut self, size: u64) { self.inner.total = size; } + fn size(&mut self, size: u64) { + self.inner.total = size; + } fn finish(&mut self) {} } @@ -230,7 +241,9 @@ impl io::Write for NetProgressBar { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } /// First attempts to read the secret key used to authenticate with the `CtlGateway` from disk From 7c0c6ec897e8b04b4b68943f33cf4937ac86cd85 Mon Sep 17 00:00:00 2001 From: mwrock Date: Mon, 25 Feb 2019 11:10:13 -0800 Subject: [PATCH 03/10] run rustfmt with feeling Signed-off-by: mwrock --- components/common/src/ui.rs | 103 +++++++++------------- components/hab/src/main.rs | 119 +++++++++++++++----------- components/sup-client/src/lib.rs | 27 +++--- components/sup/src/ctl_gateway/mod.rs | 64 ++++++-------- 4 files changed, 149 insertions(+), 164 deletions(-) diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index 85bdcf6011..cbb2b056e0 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -12,20 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{ - env, fmt, - fs::{self, File}, - io::{self, BufRead, BufReader, Read, Stdout, Write}, - process::{self, Command}, -}; +use std::{env, + fmt, + fs::{self, + File}, + io::{self, + BufRead, + BufReader, + Read, + Stdout, + Write}, + process::{self, + Command}}; use uuid::Uuid; use crate::api_client::DisplayProgress; use pbr; -use termcolor::{self, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; +use termcolor::{self, + Color, + ColorChoice, + ColorSpec, + StandardStream, + WriteColor}; use self::tty::StdStream; -use crate::error::{Error, Result}; +use crate::error::{Error, + Result}; pub const NONINTERACTIVE_ENVVAR: &str = "HAB_NONINTERACTIVE"; @@ -216,8 +228,7 @@ pub trait UIWriter { true, )?; } - self.err() - .print("✗✗✗\n".as_bytes(), Some(Color::Red), true) + self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true) } /// Write a message formatted with `title`. @@ -251,14 +262,10 @@ pub trait UIWriter { } /// Write a message formatted with `para`. - fn para(&mut self, text: &str) -> io::Result<()> { - print_wrapped(self.out(), text, 75, 2) - } + fn para(&mut self, text: &str) -> io::Result<()> { print_wrapped(self.out(), text, 75, 2) } /// Write a line break message`. - fn br(&mut self) -> io::Result<()> { - self.out().print(b"\n", None, false) - } + fn br(&mut self) -> io::Result<()> { self.out().print(b"\n", None, false) } } /// Console (shell) backed UI. @@ -269,9 +276,7 @@ pub struct UI { impl UI { /// Creates a new `UI` from a `Shell`. - pub fn new(shell: Shell) -> Self { - UI { shell } - } + pub fn new(shell: Shell) -> Self { UI { shell } } /// Creates a new default `UI` with a coloring strategy and tty hinting. pub fn default_with(coloring: ColorChoice, isatty: Option) -> Self { @@ -339,29 +344,19 @@ impl UI { } impl Default for UI { - fn default() -> Self { - UI::default_with(ColorChoice::Auto, None) - } + fn default() -> Self { UI::default_with(ColorChoice::Auto, None) } } impl UIWriter for UI { type ProgressBar = ConsoleProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { - &mut self.shell.out - } + fn out(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.out } - fn err(&mut self) -> &mut dyn ColorPrinter { - &mut self.shell.err - } + fn err(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.err } - fn is_out_a_terminal(&self) -> bool { - self.shell.out.is_a_terminal() - } + fn is_out_a_terminal(&self) -> bool { self.shell.out.is_a_terminal() } - fn is_err_a_terminal(&self) -> bool { - self.shell.err.is_a_terminal() - } + fn is_err_a_terminal(&self) -> bool { self.shell.err.is_a_terminal() } fn progress(&self) -> Option { if self.is_out_a_terminal() { @@ -488,23 +483,15 @@ impl Shell { Shell::new(stdin, stdout, stderr) } - pub fn input(&mut self) -> &mut InputStream { - &mut self.input - } + pub fn input(&mut self) -> &mut InputStream { &mut self.input } - pub fn out(&mut self) -> &mut OutputStream { - &mut self.out - } + pub fn out(&mut self) -> &mut OutputStream { &mut self.out } - pub fn err(&mut self) -> &mut OutputStream { - &mut self.err - } + pub fn err(&mut self) -> &mut OutputStream { &mut self.err } } impl Default for Shell { - fn default() -> Self { - Shell::default_with(ColorChoice::Auto, None) - } + fn default() -> Self { Shell::default_with(ColorChoice::Auto, None) } } pub struct InputStream { @@ -513,9 +500,7 @@ pub struct InputStream { } impl InputStream { - pub fn new(inner: Box, isatty: bool) -> Self { - InputStream { inner, isatty } - } + pub fn new(inner: Box, isatty: bool) -> Self { InputStream { inner, isatty } } pub fn from_stdin(isatty: Option) -> Self { Self::new( @@ -527,15 +512,11 @@ impl InputStream { ) } - pub fn is_a_terminal(&self) -> bool { - self.isatty - } + pub fn is_a_terminal(&self) -> bool { self.isatty } } impl Read for InputStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl fmt::Debug for InputStream { @@ -581,9 +562,7 @@ impl OutputStream { ) } - pub fn is_a_terminal(&self) -> bool { - self.isatty - } + pub fn is_a_terminal(&self) -> bool { self.isatty } } impl ColorPrinter for OutputStream { @@ -661,7 +640,9 @@ mod tty { } #[cfg(windows)] pub fn isatty(output: StdStream) -> bool { - use winapi::um::{consoleapi, processenv, winbase}; + use winapi::um::{consoleapi, + processenv, + winbase}; let handle = match output { StdStream::Stdin => winbase::STD_INPUT_HANDLE, @@ -728,9 +709,7 @@ impl Write for ConsoleProgressBar { } } - fn flush(&mut self) -> io::Result<()> { - self.bar.flush() - } + fn flush(&mut self) -> io::Result<()> { self.bar.flush() } } pub fn print_wrapped( diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 63411fc368..27df03ff59 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -29,60 +29,81 @@ extern crate lazy_static; extern crate log; use pbr; -use std::{ - env, - ffi::OsString, - fs::File, - io::{self, prelude::*, Read}, - net::ToSocketAddrs, - path::{Path, PathBuf}, - process, result, - str::FromStr, - thread, -}; -use termcolor::{self, Color, ColorChoice}; +use std::{env, + ffi::OsString, + fs::File, + io::{self, + prelude::*, + Read}, + net::ToSocketAddrs, + path::{Path, + PathBuf}, + process, + result, + str::FromStr, + thread}; +use termcolor::{self, + Color, + ColorChoice}; #[cfg(windows)] use crate::hcore::crypto::dpapi::encrypt; -use crate::{ - common::{ - command::package::install::{ - InstallHookMode, InstallMode, InstallSource, LocalPackageUsage, - }, - types::ListenCtlAddr, - ui::{Status, UIWriter, NONINTERACTIVE_ENVVAR, UI}, - }, - hcore::{ - binlink::default_binlink_dir, - crypto::{default_cache_key_path, init, keys::PairType, BoxKeyPair, SigKeyPair}, - env as henv, - env::Config as EnvConfig, - fs::{cache_analytics_path, cache_artifact_path, cache_key_path, launcher_root_path}, - package::{PackageIdent, PackageTarget}, - ChannelIdent, - }, -}; -use clap::{ArgMatches, Shell}; +use crate::{common::{command::package::install::{InstallHookMode, + InstallMode, + InstallSource, + LocalPackageUsage}, + types::ListenCtlAddr, + ui::{Status, + UIWriter, + NONINTERACTIVE_ENVVAR, + UI}}, + hcore::{binlink::default_binlink_dir, + crypto::{default_cache_key_path, + init, + keys::PairType, + BoxKeyPair, + SigKeyPair}, + env as henv, + env::Config as EnvConfig, + fs::{cache_analytics_path, + cache_artifact_path, + cache_key_path, + launcher_root_path}, + package::{PackageIdent, + PackageTarget}, + ChannelIdent}}; +use clap::{ArgMatches, + Shell}; use futures::prelude::*; -use crate::{ - hcore::{ - service::{HealthCheckInterval, ServiceGroup}, - url::{bldr_url_from_env, default_bldr_url}, - }, - protocol::{codec::*, ctl::ServiceBindList, net::ErrCode, types::*}, - sup_client::{SrvClient, SrvClientError}, -}; +use crate::{hcore::{service::{HealthCheckInterval, + ServiceGroup}, + url::{bldr_url_from_env, + default_bldr_url}}, + protocol::{codec::*, + ctl::ServiceBindList, + net::ErrCode, + types::*}, + sup_client::{SrvClient, + SrvClientError}}; use tabwriter::TabWriter; -use hab::{ - analytics, cli, - command::{self, pkg::list::ListingType}, - config::{self, Config}, - error::{Error, Result}, - feat, scaffolding, AUTH_TOKEN_ENVVAR, BLDR_URL_ENVVAR, CTL_SECRET_ENVVAR, ORIGIN_ENVVAR, - PRODUCT, VERSION, -}; +use hab::{analytics, + cli, + command::{self, + pkg::list::ListingType}, + config::{self, + Config}, + error::{Error, + Result}, + feat, + scaffolding, + AUTH_TOKEN_ENVVAR, + BLDR_URL_ENVVAR, + CTL_SECRET_ENVVAR, + ORIGIN_ENVVAR, + PRODUCT, + VERSION}; /// Makes the --org CLI param optional when this env var is set const HABITAT_ORG_ENVVAR: &str = "HAB_ORG"; @@ -1696,9 +1717,7 @@ fn get_password_from_input(m: &ArgMatches) -> Result> { } #[cfg(any(target_os = "linux", target_os = "macos"))] -fn get_password_from_input(_m: &ArgMatches<'_>) -> Result> { - Ok(None) -} +fn get_password_from_input(_m: &ArgMatches<'_>) -> Result> { Ok(None) } fn get_topology_from_input(m: &ArgMatches<'_>) -> Option { m.value_of("TOPOLOGY") diff --git a/components/sup-client/src/lib.rs b/components/sup-client/src/lib.rs index 08f806202f..7027d44261 100644 --- a/components/sup-client/src/lib.rs +++ b/components/sup-client/src/lib.rs @@ -45,10 +45,15 @@ use habitat_sup_protocol as protocol; extern crate log; use habitat_common as common; -use std::{error, fmt, io, path::PathBuf}; +use std::{error, + fmt, + io, + path::PathBuf}; -use crate::protocol::{codec::*, net::NetErr}; -use futures::{prelude::*, sink}; +use crate::protocol::{codec::*, + net::NetErr}; +use futures::{prelude::*, + sink}; use tokio::net::TcpStream; use tokio_codec::Framed; @@ -112,27 +117,19 @@ impl fmt::Display for SrvClientError { } impl From for SrvClientError { - fn from(err: NetErr) -> Self { - SrvClientError::NetErr(err) - } + fn from(err: NetErr) -> Self { SrvClientError::NetErr(err) } } impl From for SrvClientError { - fn from(err: io::Error) -> Self { - SrvClientError::Io(err) - } + fn from(err: io::Error) -> Self { SrvClientError::Io(err) } } impl From for SrvClientError { - fn from(err: prost::DecodeError) -> Self { - SrvClientError::Decode(err) - } + fn from(err: prost::DecodeError) -> Self { SrvClientError::Decode(err) } } impl From for SrvClientError { - fn from(err: termcolor::ParseColorError) -> Self { - SrvClientError::ParseColor(err) - } + fn from(err: termcolor::ParseColorError) -> Self { SrvClientError::ParseColor(err) } } /// Client for connecting and communicating with a server listener which speaks SrvProtocol. diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index e4a9fc0933..9cbae03a50 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -22,26 +22,30 @@ pub mod server; -use std::{ - borrow::Cow, - fmt, - fs::{self, File}, - io::{self, Write}, - path::Path, -}; +use std::{borrow::Cow, + fmt, + fs::{self, + File}, + io::{self, + Write}, + path::Path}; use regex::Regex; -use termcolor::{Buffer, Color, ColorSpec, WriteColor}; - -use crate::{ - api_client::DisplayProgress, - common::ui::{ColorPrinter, UIWriter}, - hcore::{self, output}, - protocol, -}; +use termcolor::{Buffer, + Color, + ColorSpec, + WriteColor}; + +use crate::{api_client::DisplayProgress, + common::ui::{ColorPrinter, + UIWriter}, + hcore::{self, + output}, + protocol}; use futures::prelude::*; -use crate::error::{Error, Result}; +use crate::error::{Error, + Result}; lazy_static! { /// Shamelessly stolen from https://github.com/chalk/ansi-regex/blob/master/index.js @@ -106,9 +110,7 @@ impl CtlRequest { } /// Returns true if the request is transactional and false if not. - pub fn transactional(&self) -> bool { - self.transaction.is_some() && self.tx.is_some() - } + pub fn transactional(&self) -> bool { self.transaction.is_some() && self.tx.is_some() } fn send_msg(&mut self, msg: T, complete: bool) where @@ -130,21 +132,13 @@ impl CtlRequest { impl UIWriter for CtlRequest { type ProgressBar = NetProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { - self - } + fn out(&mut self) -> &mut dyn ColorPrinter { self } - fn err(&mut self) -> &mut dyn ColorPrinter { - self - } + fn err(&mut self) -> &mut dyn ColorPrinter { self } - fn is_out_a_terminal(&self) -> bool { - true - } + fn is_out_a_terminal(&self) -> bool { true } - fn is_err_a_terminal(&self) -> bool { - true - } + fn is_err_a_terminal(&self) -> bool { true } fn progress(&self) -> Option { if self.is_out_a_terminal() { @@ -227,9 +221,7 @@ impl NetProgressBar { } impl DisplayProgress for NetProgressBar { - fn size(&mut self, size: u64) { - self.inner.total = size; - } + fn size(&mut self, size: u64) { self.inner.total = size; } fn finish(&mut self) {} } @@ -241,9 +233,7 @@ impl io::Write for NetProgressBar { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } /// First attempts to read the secret key used to authenticate with the `CtlGateway` from disk From 0a87d9d4d066d98378d96d91d20d65e2241a71c0 Mon Sep 17 00:00:00 2001 From: mwrock Date: Mon, 25 Feb 2019 11:22:56 -0800 Subject: [PATCH 04/10] fix some test uses Signed-off-by: mwrock --- components/hab/src/command/bldr/job/promote.rs | 3 +-- components/hab/src/command/pkg/binlink.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/hab/src/command/bldr/job/promote.rs b/components/hab/src/command/bldr/job/promote.rs index 9f71a4d3b0..36e1872540 100644 --- a/components/hab/src/command/bldr/job/promote.rs +++ b/components/hab/src/command/bldr/job/promote.rs @@ -188,8 +188,7 @@ mod test { use super::get_ident_list; use crate::{api_client::{Project, SchedulerResponse}, - common::ui::{Coloring, - UI}}; + common::ui::UI}; fn sample_project_list() -> Vec { let project1 = Project { diff --git a/components/hab/src/command/pkg/binlink.rs b/components/hab/src/command/pkg/binlink.rs index 23b6ef8456..876ef70da3 100644 --- a/components/hab/src/command/pkg/binlink.rs +++ b/components/hab/src/command/pkg/binlink.rs @@ -279,8 +279,7 @@ mod test { RwLock}}; use termcolor::ColorChoice; - use crate::{common::ui::{Coloring, - UI}, + use crate::{common::ui::UI, hcore::{self, package::{PackageIdent, PackageTarget}}}; From cf063440190891d7f9c1c7fac69a510082fcc497 Mon Sep 17 00:00:00 2001 From: mwrock Date: Mon, 25 Feb 2019 11:32:03 -0800 Subject: [PATCH 05/10] fix more test uses Signed-off-by: mwrock --- components/pkg-export-docker/src/build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/pkg-export-docker/src/build.rs b/components/pkg-export-docker/src/build.rs index dd4dd4aaef..1783bedb78 100644 --- a/components/pkg-export-docker/src/build.rs +++ b/components/pkg-export-docker/src/build.rs @@ -914,8 +914,7 @@ mod test { RwLock}}; use termcolor::ColorChoice; - use crate::{common::ui::{Coloring, - UI}, + use crate::{common::ui::UI, hcore}; use tempfile::TempDir; From 2e312b8a1bf24fb7cff869186817d8b14189e4da Mon Sep 17 00:00:00 2001 From: mwrock Date: Mon, 25 Feb 2019 12:02:31 -0800 Subject: [PATCH 06/10] fix typo in comment Signed-off-by: mwrock --- components/sup/src/ctl_gateway/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index 9cbae03a50..11ce1e0c79 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -173,7 +173,7 @@ impl ColorPrinter for CtlRequest { // that CtlRequest is sending output to two destinations with // different formatting requirements complicates things a bit. // - // TODO (MW): For `han sup run` scenarios, it would be nice to + // TODO (MW): For `hab sup run` scenarios, it would be nice to // support color on older versions of Windows. We could refactor // outputln! to support a cross platform ColorWriter similar to // what we use in common::UI. From f9123b3502880c19f355eea7d1cebe4abc873431 Mon Sep 17 00:00:00 2001 From: mwrock Date: Tue, 26 Feb 2019 16:42:04 -0800 Subject: [PATCH 07/10] leverage WriteColor trait instead of ColorPrinter Signed-off-by: mwrock --- components/common/src/error.rs | 5 + components/common/src/ui.rs | 220 +++++++++++++----- components/hab/src/main.rs | 10 +- components/sup-client/src/lib.rs | 8 + components/sup-protocol/protocols/ctl.proto | 8 +- .../sup-protocol/src/generated/sup.ctl.rs | 12 +- components/sup/src/ctl_gateway/mod.rs | 59 ++++- 7 files changed, 245 insertions(+), 77 deletions(-) diff --git a/components/common/src/error.rs b/components/common/src/error.rs index dc85a6d31e..eda64aa599 100644 --- a/components/common/src/error.rs +++ b/components/common/src/error.rs @@ -35,6 +35,7 @@ pub enum Error { ArtifactIdentMismatch((String, String, String)), /// Occurs when there is no valid toml of json in the environment variable BadEnvConfig(String), + BadWeight(String), CantUploadGossipToml, ChannelNotFound, CryptoKeyError(String), @@ -94,6 +95,9 @@ impl fmt::Display for Error { Error::BadEnvConfig(ref varname) => { format!("Unable to find valid TOML or JSON in {} ENVVAR", varname) } + Error::BadWeight(ref varname) => { + format!("Unable to parse Weight value from {}", varname) + } Error::CantUploadGossipToml => { "Can't upload gossip.toml, it's a reserved file name".to_string() } @@ -161,6 +165,7 @@ impl error::Error for Error { Error::APIClient(ref err) => err.description(), Error::ArtifactIdentMismatch((..)) => "Artifact ident does not match expected ident", Error::BadEnvConfig(_) => "Unknown syntax in Env Configuration", + Error::BadWeight(_) => "Unable to parse Weight value", Error::CantUploadGossipToml => "Can't upload gossip.toml, it's a reserved filename", Error::ChannelNotFound => "Channel not found", Error::CryptoKeyError(_) => "Missing or invalid key", diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index cbb2b056e0..f3b6409cda 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -132,18 +132,15 @@ pub trait UIReader { fn prompt_yes_no(&mut self, question: &str, default: Option) -> Result; } -pub trait ColorPrinter { - fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()>; -} - /// Functions applied to an IO stream for sending information to a UI. pub trait UIWriter { type ProgressBar: DisplayProgress; /// IO Stream for sending error messages to. - fn err(&mut self) -> &mut dyn ColorPrinter; + fn err(&mut self) -> &mut dyn WriteColor; /// IO Stream for sending normal or informational messages to. - fn out(&mut self) -> &mut dyn ColorPrinter; + fn out(&mut self) -> &mut dyn WriteColor; + /// Messages sent to the normal or informational IO stream will be formatted for a terminal if /// true. fn is_out_a_terminal(&self) -> bool; @@ -158,10 +155,11 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '»'; - self.out().print( + print( + self.out(), format!("{} {}\n", symbol, message).as_bytes(), Some(Color::Yellow), - true, + Weight::Bold, ) } @@ -171,10 +169,11 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '★'; - self.out().print( + print( + self.out(), format!("{} {}\n", symbol, message).as_bytes(), Some(Color::Magenta), - true, + Weight::Bold, ) } @@ -184,13 +183,18 @@ pub trait UIWriter { T: fmt::Display, { let (symbol, status_str, color) = status.parts(); - self.out().print( + print( + self.out(), format!("{} {}", symbol, status_str).as_bytes(), Some(color), - true, + Weight::Bold, )?; - self.out() - .print(format!(" {}\n", message).as_bytes(), None, false) + print( + self.out(), + format!(" {}\n", message).as_bytes(), + None, + Weight::Normal, + ) } /// Write a message formatted with `info`. @@ -198,8 +202,12 @@ pub trait UIWriter { where T: fmt::Display, { - self.out() - .print(format!("{}\n", text).as_bytes(), None, false) + print( + self.out(), + format!("{}\n", text).as_bytes(), + None, + Weight::Normal, + ) } /// Write a message formatted with `warn`. @@ -207,10 +215,11 @@ pub trait UIWriter { where T: fmt::Display, { - self.err().print( + print( + self.err(), format!("∅ {}\n", message).as_bytes(), Some(Color::Yellow), - true, + Weight::Bold, ) } @@ -219,16 +228,26 @@ pub trait UIWriter { where T: fmt::Display, { - self.err() - .print("✗✗✗\n".as_bytes(), Some(Color::Red), true)?; + print( + self.err(), + "✗✗✗\n".as_bytes(), + Some(Color::Red), + Weight::Bold, + )?; for line in message.to_string().lines() { - self.err().print( + print( + self.err(), format!("✗✗✗ {}\n", line).as_bytes(), Some(Color::Red), - true, + Weight::Bold, )?; } - self.err().print("✗✗✗\n".as_bytes(), Some(Color::Red), true) + print( + self.err(), + "✗✗✗\n".as_bytes(), + Some(Color::Red), + Weight::Bold, + ) } /// Write a message formatted with `title`. @@ -236,7 +255,8 @@ pub trait UIWriter { where T: AsRef, { - self.out().print( + print( + self.out(), format!( "{}\n{:=, { - self.out().print( + print( + self.out(), format!("{}\n\n", text.as_ref()).as_bytes(), Some(Color::Green), - true, + Weight::Bold, ) } @@ -265,7 +286,7 @@ pub trait UIWriter { fn para(&mut self, text: &str) -> io::Result<()> { print_wrapped(self.out(), text, 75, 2) } /// Write a line break message`. - fn br(&mut self) -> io::Result<()> { self.out().print(b"\n", None, false) } + fn br(&mut self) -> io::Result<()> { print(self.out(), b"\n", None, Weight::Normal) } } /// Console (shell) backed UI. @@ -350,9 +371,9 @@ impl Default for UI { impl UIWriter for UI { type ProgressBar = ConsoleProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.out } + fn out(&mut self) -> &mut dyn WriteColor { &mut self.shell.out } - fn err(&mut self) -> &mut dyn ColorPrinter { &mut self.shell.err } + fn err(&mut self) -> &mut dyn WriteColor { &mut self.shell.err } fn is_out_a_terminal(&self) -> bool { self.shell.out.is_a_terminal() } @@ -380,10 +401,30 @@ impl UIReader for UI { None => ("[yes/no/quit]", "", ""), }; loop { - stream.print(question.as_bytes(), Some(Color::Cyan), false)?; - stream.print(format!(" {}", prefix).as_bytes(), Some(Color::White), false)?; - stream.print(default_text.as_bytes(), Some(Color::White), true)?; - stream.print(format!("{} ", suffix).as_bytes(), Some(Color::White), false)?; + print( + stream, + question.as_bytes(), + Some(Color::Cyan), + Weight::Normal, + )?; + print( + stream, + format!(" {}", prefix).as_bytes(), + Some(Color::White), + Weight::Normal, + )?; + print( + stream, + default_text.as_bytes(), + Some(Color::White), + Weight::Bold, + )?; + print( + stream, + format!("{} ", suffix).as_bytes(), + Some(Color::White), + Weight::Normal, + )?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -405,14 +446,19 @@ impl UIReader for UI { fn prompt_ask(&mut self, question: &str, default: Option<&str>) -> Result { let stream = &mut self.shell.out; loop { - stream.print(question.as_bytes(), Some(Color::Cyan), false)?; - stream.print(b": ", None, false)?; + print( + stream, + question.as_bytes(), + Some(Color::Cyan), + Weight::Normal, + )?; + print(stream, b": ", None, Weight::Normal)?; if let Some(d) = default { - stream.print(b"[default: ", Some(Color::White), false)?; - stream.print(d.as_bytes(), Some(Color::White), true)?; - stream.print(b"]", Some(Color::White), false)?; + print(stream, b"[default: ", Some(Color::White), Weight::Normal)?; + print(stream, d.as_bytes(), Some(Color::White), Weight::Bold)?; + print(stream, b"]", Some(Color::White), Weight::Normal)?; } - stream.print(b" ", None, false)?; + print(stream, b" ", None, Weight::Normal)?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -494,6 +540,22 @@ impl Default for Shell { fn default() -> Self { Shell::default_with(ColorChoice::Auto, None) } } +#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum Weight { + Normal, + Bold, +} + +impl Weight { + pub fn from_i32(value: i32) -> Result { + match value { + 0 => Ok(Weight::Normal), + 1 => Ok(Weight::Bold), + _ => Err(Error::BadWeight(value.to_string())), + } + } +} + pub struct InputStream { inner: Box, isatty: bool, @@ -565,20 +627,41 @@ impl OutputStream { pub fn is_a_terminal(&self) -> bool { self.isatty } } -impl ColorPrinter for OutputStream { - fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> { +impl WriteColor for OutputStream { + fn supports_color(&self) -> bool { match self.inner { - WriteStream::Stream(ref mut stream) => { - stream.reset()?; - stream.set_color(ColorSpec::new().set_bold(bold).set_fg(color))?; - stream.write_all(buf)?; - stream.flush()?; - stream.reset() - } - WriteStream::Write(ref mut w) => { - w.write(buf)?; - w.flush() - } + WriteStream::Stream(ref stream) => stream.supports_color(), + _ => false, + } + } + + fn reset(&mut self) -> io::Result<()> { + match self.inner { + WriteStream::Stream(ref mut stream) => stream.reset(), + _ => Ok(()), + } + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + match self.inner { + WriteStream::Stream(ref mut stream) => stream.set_color(spec), + _ => Ok(()), + } + } +} + +impl Write for OutputStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + match self.inner { + WriteStream::Stream(ref mut stream) => stream.write(buf), + WriteStream::Write(ref mut w) => w.write(buf), + } + } + + fn flush(&mut self) -> io::Result<()> { + match self.inner { + WriteStream::Stream(ref mut stream) => stream.flush(), + WriteStream::Write(ref mut w) => w.flush(), } } } @@ -713,7 +796,7 @@ impl Write for ConsoleProgressBar { } pub fn print_wrapped( - stream: &mut dyn ColorPrinter, + stream: &mut dyn WriteColor, text: U, wrap_width: usize, left_indent: usize, @@ -727,10 +810,11 @@ where for word in line.split_whitespace() { let wl = word.chars().count(); if (width + wl + 1) > (wrap_width - left_indent) { - stream.print( + print( + stream, format!("{:, + weight: Weight, +) -> io::Result<()> { + writer.reset()?; + writer.set_color( + ColorSpec::new() + .set_bold(weight == Weight::Bold) + .set_fg(color), + )?; + writer.write_all(buf)?; + writer.flush()?; + writer.reset() +} diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 27df03ff59..de5d042244 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -55,6 +55,7 @@ use crate::{common::{command::package::install::{InstallHookMode, types::ListenCtlAddr, ui::{Status, UIWriter, + Weight, NONINTERACTIVE_ENVVAR, UI}}, hcore::{binlink::default_binlink_dir, @@ -1513,9 +1514,12 @@ fn handle_ctl_reply(reply: SrvMessage) -> result::Result<(), SrvClientError> { Some(color) => Some(Color::from_str(&color)?), None => None, }; - UI::default_with_env() - .out() - .print(m.line.as_bytes(), c, m.bold)?; + common::ui::print( + UI::default_with_env().out(), + m.line.as_bytes(), + c, + Weight::from_i32(m.weight)?, + )?; } "NetProgress" => { let m = reply diff --git a/components/sup-client/src/lib.rs b/components/sup-client/src/lib.rs index 7027d44261..486ec875a4 100644 --- a/components/sup-client/src/lib.rs +++ b/components/sup-client/src/lib.rs @@ -64,6 +64,8 @@ pub type SrvSend = sink::Send; /// Error types returned by a [`SrvClient`]. #[derive(Debug)] pub enum SrvClientError { + // An error from the common crate + CommonError(habitat_common::error::Error), /// The remote server unexpectedly closed the connection. ConnectionClosed, /// Unable to locate a secret key on disk. @@ -81,6 +83,7 @@ pub enum SrvClientError { impl error::Error for SrvClientError { fn description(&self) -> &str { match *self { + SrvClientError::CommonError(ref err) => err.description(), SrvClientError::ConnectionClosed => "Connection closed", SrvClientError::CtlSecretNotFound(_) => "Ctl secret key not found", SrvClientError::Decode(ref err) => err.description(), @@ -94,6 +97,7 @@ impl error::Error for SrvClientError { impl fmt::Display for SrvClientError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let content = match *self { + SrvClientError::CommonError(ref err) => format!("{}", err), SrvClientError::ConnectionClosed => "Connection closed".to_string(), SrvClientError::CtlSecretNotFound(ref path) => format!( "No Supervisor CtlGateway secret set in `cli.toml` or found at {}. Run `hab \ @@ -132,6 +136,10 @@ impl From for SrvClientError { fn from(err: termcolor::ParseColorError) -> Self { SrvClientError::ParseColor(err) } } +impl From for SrvClientError { + fn from(err: habitat_common::error::Error) -> Self { SrvClientError::CommonError(err) } +} + /// Client for connecting and communicating with a server listener which speaks SrvProtocol. /// /// See module doc for usage. diff --git a/components/sup-protocol/protocols/ctl.proto b/components/sup-protocol/protocols/ctl.proto index 3acc21a528..ea73726a8f 100644 --- a/components/sup-protocol/protocols/ctl.proto +++ b/components/sup-protocol/protocols/ctl.proto @@ -123,9 +123,15 @@ message SvcStatus { optional sup.types.PackageIdent ident = 1; } +enum Weight { + // The weight of rendered text + Normal = 0; + Bold = 1; +} + // A reply to various requests which contains a pre-formatted console line. message ConsoleLine { required string line = 1; optional string color = 2; - required bool bold = 3; + required Weight weight = 3; } diff --git a/components/sup-protocol/src/generated/sup.ctl.rs b/components/sup-protocol/src/generated/sup.ctl.rs index 4702b74630..f78dc94bb7 100644 --- a/components/sup-protocol/src/generated/sup.ctl.rs +++ b/components/sup-protocol/src/generated/sup.ctl.rs @@ -192,6 +192,14 @@ pub struct ConsoleLine { pub line: String, #[prost(string, optional, tag="2")] pub color: ::std::option::Option, - #[prost(bool, required, tag="3")] - pub bold: bool, + #[prost(enumeration="Weight", required, tag="3")] + pub weight: i32, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Enumeration)] +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Weight { + /// The weight of rendered text + Normal = 0, + Bold = 1, } diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index 11ce1e0c79..0770c6e7ec 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -37,8 +37,8 @@ use termcolor::{Buffer, WriteColor}; use crate::{api_client::DisplayProgress, - common::ui::{ColorPrinter, - UIWriter}, + common::ui::{UIWriter, + Weight}, hcore::{self, output}, protocol}; @@ -79,6 +79,7 @@ pub struct CtlRequest { tx: Option, /// Transaction for the given request. transaction: Option, + current_color_spec: Option, } impl CtlRequest { @@ -88,7 +89,11 @@ impl CtlRequest { tx: Option, transaction: Option, ) -> Self { - CtlRequest { tx, transaction } + CtlRequest { + tx, + transaction, + current_color_spec: None, + } } /// Reply to the transaction with the given message but indicate to the receiver that this is @@ -132,9 +137,9 @@ impl CtlRequest { impl UIWriter for CtlRequest { type ProgressBar = NetProgressBar; - fn out(&mut self) -> &mut dyn ColorPrinter { self } + fn out(&mut self) -> &mut dyn WriteColor { self } - fn err(&mut self) -> &mut dyn ColorPrinter { self } + fn err(&mut self) -> &mut dyn WriteColor { self } fn is_out_a_terminal(&self) -> bool { true } @@ -149,16 +154,43 @@ impl UIWriter for CtlRequest { } } -impl ColorPrinter for CtlRequest { - fn print(&mut self, buf: &[u8], color: Option, bold: bool) -> io::Result<()> { +impl WriteColor for CtlRequest { + fn supports_color(&self) -> bool { true } + + fn reset(&mut self) -> io::Result<()> { + self.current_color_spec = None; + Ok(()) + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.current_color_spec = Some(spec.clone()); + Ok(()) + } +} + +impl Write for CtlRequest { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { // The protocol reply is destined for the client, so (for now, // at least), we'll apply colored output. // // `line` will also have a newline character at the end, FYI. let mut msg = protocol::ctl::ConsoleLine::default(); msg.line = String::from_utf8_lossy(buf).to_string(); - msg.color = color_to_string(color); - msg.bold = bold; + match self.current_color_spec { + Some(ref spec) => { + msg.color = color_to_string(spec.fg()); + msg.weight = match spec.bold() { + true => Weight::Bold as i32, + false => Weight::Normal as i32, + } + } + None => { + msg.color = None; + msg.weight = Weight::Normal as i32; + } + } self.reply_partial(msg); // Down here, however, we're doing double-duty by *also* @@ -178,7 +210,9 @@ impl ColorPrinter for CtlRequest { // outputln! to support a cross platform ColorWriter similar to // what we use in common::UI. let mut ansi_buffer = Buffer::ansi(); - ansi_buffer.set_color(ColorSpec::new().set_bold(bold).set_fg(color))?; + if let Some(spec) = &self.current_color_spec { + ansi_buffer.set_color(&spec)?; + } ansi_buffer.write_all(buf)?; ansi_buffer.flush()?; let line = String::from_utf8_lossy(ansi_buffer.as_slice()).to_string(); @@ -192,11 +226,12 @@ impl ColorPrinter for CtlRequest { // the macro outputln!("{}", maybe_stripped.trim_right_matches('\n')); - Ok(()) + self.reset()?; + Ok(buf.len()) } } -fn color_to_string(color: Option) -> Option { +fn color_to_string(color: Option<&Color>) -> Option { match color { Some(c) => Some(format!("{:?}", c).to_string()), None => None, From 4b9ea178cd5e70c7ef25f9d99a0c91965f640e04 Mon Sep 17 00:00:00 2001 From: mwrock Date: Tue, 26 Feb 2019 17:49:44 -0800 Subject: [PATCH 08/10] use ColorSpec for print Signed-off-by: mwrock --- components/common/src/ui.rs | 105 ++++++------------ components/hab/src/main.rs | 20 ++-- components/sup-client/src/lib.rs | 8 -- components/sup-protocol/protocols/ctl.proto | 8 +- .../sup-protocol/src/generated/sup.ctl.rs | 12 +- components/sup/src/ctl_gateway/mod.rs | 10 +- 6 files changed, 50 insertions(+), 113 deletions(-) diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index f3b6409cda..90fb7ba628 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -158,8 +158,7 @@ pub trait UIWriter { print( self.out(), format!("{} {}\n", symbol, message).as_bytes(), - Some(Color::Yellow), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true), ) } @@ -172,8 +171,7 @@ pub trait UIWriter { print( self.out(), format!("{} {}\n", symbol, message).as_bytes(), - Some(Color::Magenta), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Magenta)).set_bold(true), ) } @@ -186,14 +184,12 @@ pub trait UIWriter { print( self.out(), format!("{} {}", symbol, status_str).as_bytes(), - Some(color), - Weight::Bold, + ColorSpec::new().set_fg(Some(color)).set_bold(true), )?; print( self.out(), format!(" {}\n", message).as_bytes(), - None, - Weight::Normal, + &ColorSpec::new(), ) } @@ -205,8 +201,7 @@ pub trait UIWriter { print( self.out(), format!("{}\n", text).as_bytes(), - None, - Weight::Normal, + &ColorSpec::new(), ) } @@ -218,8 +213,7 @@ pub trait UIWriter { print( self.err(), format!("∅ {}\n", message).as_bytes(), - Some(Color::Yellow), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true), ) } @@ -231,22 +225,19 @@ pub trait UIWriter { print( self.err(), "✗✗✗\n".as_bytes(), - Some(Color::Red), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), )?; for line in message.to_string().lines() { print( self.err(), format!("✗✗✗ {}\n", line).as_bytes(), - Some(Color::Red), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), )?; } print( self.err(), "✗✗✗\n".as_bytes(), - Some(Color::Red), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), ) } @@ -264,8 +255,7 @@ pub trait UIWriter { width = text.as_ref().chars().count() ) .as_bytes(), - Some(Color::Green), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true), ) } @@ -277,8 +267,7 @@ pub trait UIWriter { print( self.out(), format!("{}\n\n", text.as_ref()).as_bytes(), - Some(Color::Green), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true), ) } @@ -286,7 +275,7 @@ pub trait UIWriter { fn para(&mut self, text: &str) -> io::Result<()> { print_wrapped(self.out(), text, 75, 2) } /// Write a line break message`. - fn br(&mut self) -> io::Result<()> { print(self.out(), b"\n", None, Weight::Normal) } + fn br(&mut self) -> io::Result<()> { print(self.out(), b"\n", &ColorSpec::new()) } } /// Console (shell) backed UI. @@ -404,26 +393,22 @@ impl UIReader for UI { print( stream, question.as_bytes(), - Some(Color::Cyan), - Weight::Normal, + ColorSpec::new().set_fg(Some(Color::Cyan)), )?; print( stream, format!(" {}", prefix).as_bytes(), - Some(Color::White), - Weight::Normal, + ColorSpec::new().set_fg(Some(Color::White)), )?; print( stream, default_text.as_bytes(), - Some(Color::White), - Weight::Bold, + ColorSpec::new().set_fg(Some(Color::White)).set_bold(true), )?; print( stream, format!("{} ", suffix).as_bytes(), - Some(Color::White), - Weight::Normal, + ColorSpec::new().set_fg(Some(Color::White)), )?; let mut response = String::new(); { @@ -449,16 +434,23 @@ impl UIReader for UI { print( stream, question.as_bytes(), - Some(Color::Cyan), - Weight::Normal, + ColorSpec::new().set_fg(Some(Color::Cyan)), )?; - print(stream, b": ", None, Weight::Normal)?; + print(stream, b": ", &ColorSpec::new())?; if let Some(d) = default { - print(stream, b"[default: ", Some(Color::White), Weight::Normal)?; - print(stream, d.as_bytes(), Some(Color::White), Weight::Bold)?; - print(stream, b"]", Some(Color::White), Weight::Normal)?; + print( + stream, + b"[default: ", + ColorSpec::new().set_fg(Some(Color::White)), + )?; + print( + stream, + d.as_bytes(), + ColorSpec::new().set_fg(Some(Color::White)).set_bold(true), + )?; + print(stream, b"]", ColorSpec::new().set_fg(Some(Color::White)))?; } - print(stream, b" ", None, Weight::Normal)?; + print(stream, b" ", &ColorSpec::new())?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -540,22 +532,6 @@ impl Default for Shell { fn default() -> Self { Shell::default_with(ColorChoice::Auto, None) } } -#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub enum Weight { - Normal, - Bold, -} - -impl Weight { - pub fn from_i32(value: i32) -> Result { - match value { - 0 => Ok(Weight::Normal), - 1 => Ok(Weight::Bold), - _ => Err(Error::BadWeight(value.to_string())), - } - } -} - pub struct InputStream { inner: Box, isatty: bool, @@ -813,8 +789,7 @@ where print( stream, format!("{:, - weight: Weight, -) -> io::Result<()> { +pub fn print(writer: &mut WriteColor, buf: &[u8], color_spec: &ColorSpec) -> io::Result<()> { writer.reset()?; - writer.set_color( - ColorSpec::new() - .set_bold(weight == Weight::Bold) - .set_fg(color), - )?; + writer.set_color(color_spec)?; writer.write_all(buf)?; writer.flush()?; writer.reset() diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index de5d042244..4b786760bb 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -44,7 +44,8 @@ use std::{env, thread}; use termcolor::{self, Color, - ColorChoice}; + ColorChoice, + ColorSpec}; #[cfg(windows)] use crate::hcore::crypto::dpapi::encrypt; @@ -55,7 +56,6 @@ use crate::{common::{command::package::install::{InstallHookMode, types::ListenCtlAddr, ui::{Status, UIWriter, - Weight, NONINTERACTIVE_ENVVAR, UI}}, hcore::{binlink::default_binlink_dir, @@ -1510,16 +1510,14 @@ fn handle_ctl_reply(reply: SrvMessage) -> result::Result<(), SrvClientError> { let m = reply .parse::() .map_err(SrvClientError::Decode)?; - let c = match m.color { - Some(color) => Some(Color::from_str(&color)?), - None => None, + let mut new_spec = ColorSpec::new(); + let msg_spec = match m.color { + Some(color) => new_spec + .set_fg(Some(Color::from_str(&color)?)) + .set_bold(m.bold), + None => new_spec.set_bold(m.bold), }; - common::ui::print( - UI::default_with_env().out(), - m.line.as_bytes(), - c, - Weight::from_i32(m.weight)?, - )?; + common::ui::print(UI::default_with_env().out(), m.line.as_bytes(), msg_spec)?; } "NetProgress" => { let m = reply diff --git a/components/sup-client/src/lib.rs b/components/sup-client/src/lib.rs index 486ec875a4..7027d44261 100644 --- a/components/sup-client/src/lib.rs +++ b/components/sup-client/src/lib.rs @@ -64,8 +64,6 @@ pub type SrvSend = sink::Send; /// Error types returned by a [`SrvClient`]. #[derive(Debug)] pub enum SrvClientError { - // An error from the common crate - CommonError(habitat_common::error::Error), /// The remote server unexpectedly closed the connection. ConnectionClosed, /// Unable to locate a secret key on disk. @@ -83,7 +81,6 @@ pub enum SrvClientError { impl error::Error for SrvClientError { fn description(&self) -> &str { match *self { - SrvClientError::CommonError(ref err) => err.description(), SrvClientError::ConnectionClosed => "Connection closed", SrvClientError::CtlSecretNotFound(_) => "Ctl secret key not found", SrvClientError::Decode(ref err) => err.description(), @@ -97,7 +94,6 @@ impl error::Error for SrvClientError { impl fmt::Display for SrvClientError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let content = match *self { - SrvClientError::CommonError(ref err) => format!("{}", err), SrvClientError::ConnectionClosed => "Connection closed".to_string(), SrvClientError::CtlSecretNotFound(ref path) => format!( "No Supervisor CtlGateway secret set in `cli.toml` or found at {}. Run `hab \ @@ -136,10 +132,6 @@ impl From for SrvClientError { fn from(err: termcolor::ParseColorError) -> Self { SrvClientError::ParseColor(err) } } -impl From for SrvClientError { - fn from(err: habitat_common::error::Error) -> Self { SrvClientError::CommonError(err) } -} - /// Client for connecting and communicating with a server listener which speaks SrvProtocol. /// /// See module doc for usage. diff --git a/components/sup-protocol/protocols/ctl.proto b/components/sup-protocol/protocols/ctl.proto index ea73726a8f..3acc21a528 100644 --- a/components/sup-protocol/protocols/ctl.proto +++ b/components/sup-protocol/protocols/ctl.proto @@ -123,15 +123,9 @@ message SvcStatus { optional sup.types.PackageIdent ident = 1; } -enum Weight { - // The weight of rendered text - Normal = 0; - Bold = 1; -} - // A reply to various requests which contains a pre-formatted console line. message ConsoleLine { required string line = 1; optional string color = 2; - required Weight weight = 3; + required bool bold = 3; } diff --git a/components/sup-protocol/src/generated/sup.ctl.rs b/components/sup-protocol/src/generated/sup.ctl.rs index f78dc94bb7..4702b74630 100644 --- a/components/sup-protocol/src/generated/sup.ctl.rs +++ b/components/sup-protocol/src/generated/sup.ctl.rs @@ -192,14 +192,6 @@ pub struct ConsoleLine { pub line: String, #[prost(string, optional, tag="2")] pub color: ::std::option::Option, - #[prost(enumeration="Weight", required, tag="3")] - pub weight: i32, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Enumeration)] -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum Weight { - /// The weight of rendered text - Normal = 0, - Bold = 1, + #[prost(bool, required, tag="3")] + pub bold: bool, } diff --git a/components/sup/src/ctl_gateway/mod.rs b/components/sup/src/ctl_gateway/mod.rs index 0770c6e7ec..e4202183ee 100644 --- a/components/sup/src/ctl_gateway/mod.rs +++ b/components/sup/src/ctl_gateway/mod.rs @@ -37,8 +37,7 @@ use termcolor::{Buffer, WriteColor}; use crate::{api_client::DisplayProgress, - common::ui::{UIWriter, - Weight}, + common::ui::UIWriter, hcore::{self, output}, protocol}; @@ -181,14 +180,11 @@ impl Write for CtlRequest { match self.current_color_spec { Some(ref spec) => { msg.color = color_to_string(spec.fg()); - msg.weight = match spec.bold() { - true => Weight::Bold as i32, - false => Weight::Normal as i32, - } + msg.bold = spec.bold(); } None => { msg.color = None; - msg.weight = Weight::Normal as i32; + msg.bold = false; } } self.reply_partial(msg); From 10411d818b074a0e2847e8b9de95687a2c8df819 Mon Sep 17 00:00:00 2001 From: mwrock Date: Tue, 26 Feb 2019 18:36:07 -0800 Subject: [PATCH 09/10] add println Signed-off-by: mwrock --- components/common/src/ui.rs | 76 ++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index 90fb7ba628..30a89e79b1 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -155,9 +155,9 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '»'; - print( + println( self.out(), - format!("{} {}\n", symbol, message).as_bytes(), + format!("{} {}", symbol, message).as_bytes(), ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true), ) } @@ -168,9 +168,9 @@ pub trait UIWriter { T: fmt::Display, { let symbol = '★'; - print( + println( self.out(), - format!("{} {}\n", symbol, message).as_bytes(), + format!("{} {}", symbol, message).as_bytes(), ColorSpec::new().set_fg(Some(Color::Magenta)).set_bold(true), ) } @@ -186,11 +186,8 @@ pub trait UIWriter { format!("{} {}", symbol, status_str).as_bytes(), ColorSpec::new().set_fg(Some(color)).set_bold(true), )?; - print( - self.out(), - format!(" {}\n", message).as_bytes(), - &ColorSpec::new(), - ) + self.out().write(format!(" {}\n", message).as_bytes())?; + self.out().flush() } /// Write a message formatted with `info`. @@ -198,11 +195,8 @@ pub trait UIWriter { where T: fmt::Display, { - print( - self.out(), - format!("{}\n", text).as_bytes(), - &ColorSpec::new(), - ) + self.out().write(format!("{}\n", text).as_bytes())?; + self.out().flush() } /// Write a message formatted with `warn`. @@ -210,9 +204,9 @@ pub trait UIWriter { where T: fmt::Display, { - print( + println( self.err(), - format!("∅ {}\n", message).as_bytes(), + format!("∅ {}", message).as_bytes(), ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true), ) } @@ -222,21 +216,21 @@ pub trait UIWriter { where T: fmt::Display, { - print( + println( self.err(), - "✗✗✗\n".as_bytes(), + "✗✗✗".as_bytes(), ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), )?; for line in message.to_string().lines() { - print( + println( self.err(), - format!("✗✗✗ {}\n", line).as_bytes(), + format!("✗✗✗ {}", line).as_bytes(), ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), )?; } - print( + println( self.err(), - "✗✗✗\n".as_bytes(), + "✗✗✗".as_bytes(), ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true), ) } @@ -246,10 +240,10 @@ pub trait UIWriter { where T: AsRef, { - print( + println( self.out(), format!( - "{}\n{:=, { - print( + println( self.out(), - format!("{}\n\n", text.as_ref()).as_bytes(), + format!("{}\n", text.as_ref()).as_bytes(), ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true), ) } @@ -275,7 +269,10 @@ pub trait UIWriter { fn para(&mut self, text: &str) -> io::Result<()> { print_wrapped(self.out(), text, 75, 2) } /// Write a line break message`. - fn br(&mut self) -> io::Result<()> { print(self.out(), b"\n", &ColorSpec::new()) } + fn br(&mut self) -> io::Result<()> { + self.out().write(b"\n")?; + self.out().flush() + } } /// Console (shell) backed UI. @@ -436,7 +433,7 @@ impl UIReader for UI { question.as_bytes(), ColorSpec::new().set_fg(Some(Color::Cyan)), )?; - print(stream, b": ", &ColorSpec::new())?; + stream.write(b": ")?; if let Some(d) = default { print( stream, @@ -450,7 +447,8 @@ impl UIReader for UI { )?; print(stream, b"]", ColorSpec::new().set_fg(Some(Color::White)))?; } - print(stream, b" ", &ColorSpec::new())?; + stream.write(b" ")?; + stream.flush()?; let mut response = String::new(); { let reference = self.shell.input.by_ref(); @@ -786,10 +784,8 @@ where for word in line.split_whitespace() { let wl = word.chars().count(); if (width + wl + 1) > (wrap_width - left_indent) { - print( - stream, + stream.write( format!("{: io::Result<()> { @@ -817,3 +809,9 @@ pub fn print(writer: &mut WriteColor, buf: &[u8], color_spec: &ColorSpec) -> io: writer.flush()?; writer.reset() } + +pub fn println(writer: &mut WriteColor, buf: &[u8], color_spec: &ColorSpec) -> io::Result<()> { + print(writer, buf, color_spec)?; + writer.write(b"\n")?; + writer.flush() +} From 25e4ee2c677fd357d2a1a986f530ab22db2c0e73 Mon Sep 17 00:00:00 2001 From: mwrock Date: Tue, 26 Feb 2019 18:49:41 -0800 Subject: [PATCH 10/10] remove BadWeight and use write_all Signed-off-by: mwrock --- components/common/src/error.rs | 5 ----- components/common/src/ui.rs | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/components/common/src/error.rs b/components/common/src/error.rs index eda64aa599..dc85a6d31e 100644 --- a/components/common/src/error.rs +++ b/components/common/src/error.rs @@ -35,7 +35,6 @@ pub enum Error { ArtifactIdentMismatch((String, String, String)), /// Occurs when there is no valid toml of json in the environment variable BadEnvConfig(String), - BadWeight(String), CantUploadGossipToml, ChannelNotFound, CryptoKeyError(String), @@ -95,9 +94,6 @@ impl fmt::Display for Error { Error::BadEnvConfig(ref varname) => { format!("Unable to find valid TOML or JSON in {} ENVVAR", varname) } - Error::BadWeight(ref varname) => { - format!("Unable to parse Weight value from {}", varname) - } Error::CantUploadGossipToml => { "Can't upload gossip.toml, it's a reserved file name".to_string() } @@ -165,7 +161,6 @@ impl error::Error for Error { Error::APIClient(ref err) => err.description(), Error::ArtifactIdentMismatch((..)) => "Artifact ident does not match expected ident", Error::BadEnvConfig(_) => "Unknown syntax in Env Configuration", - Error::BadWeight(_) => "Unable to parse Weight value", Error::CantUploadGossipToml => "Can't upload gossip.toml, it's a reserved filename", Error::ChannelNotFound => "Channel not found", Error::CryptoKeyError(_) => "Missing or invalid key", diff --git a/components/common/src/ui.rs b/components/common/src/ui.rs index 30a89e79b1..489fc5f663 100644 --- a/components/common/src/ui.rs +++ b/components/common/src/ui.rs @@ -186,7 +186,7 @@ pub trait UIWriter { format!("{} {}", symbol, status_str).as_bytes(), ColorSpec::new().set_fg(Some(color)).set_bold(true), )?; - self.out().write(format!(" {}\n", message).as_bytes())?; + self.out().write_all(format!(" {}\n", message).as_bytes())?; self.out().flush() } @@ -195,7 +195,7 @@ pub trait UIWriter { where T: fmt::Display, { - self.out().write(format!("{}\n", text).as_bytes())?; + self.out().write_all(format!("{}\n", text).as_bytes())?; self.out().flush() } @@ -270,7 +270,7 @@ pub trait UIWriter { /// Write a line break message`. fn br(&mut self) -> io::Result<()> { - self.out().write(b"\n")?; + self.out().write_all(b"\n")?; self.out().flush() } } @@ -433,7 +433,7 @@ impl UIReader for UI { question.as_bytes(), ColorSpec::new().set_fg(Some(Color::Cyan)), )?; - stream.write(b": ")?; + stream.write_all(b": ")?; if let Some(d) = default { print( stream, @@ -447,7 +447,7 @@ impl UIReader for UI { )?; print(stream, b"]", ColorSpec::new().set_fg(Some(Color::White)))?; } - stream.write(b" ")?; + stream.write_all(b" ")?; stream.flush()?; let mut response = String::new(); { @@ -784,7 +784,7 @@ where for word in line.split_whitespace() { let wl = word.chars().count(); if (width + wl + 1) > (wrap_width - left_indent) { - stream.write( + stream.write_all( format!("{: io: pub fn println(writer: &mut WriteColor, buf: &[u8], color_spec: &ColorSpec) -> io::Result<()> { print(writer, buf, color_spec)?; - writer.write(b"\n")?; + writer.write_all(b"\n")?; writer.flush() }