Skip to content

Commit

Permalink
fix(cli): Mirror cargo's output
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Oct 20, 2022
1 parent 684369f commit 151d39b
Show file tree
Hide file tree
Showing 33 changed files with 386 additions and 178 deletions.
20 changes: 19 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ semver = "1.0"
quick-error = "2.0"
regex = "1.6"
bstr = "1.0.1"
termcolor = "1.1"
termcolor = "1.1.3"
maplit = "1.0"
indexmap = "1.9"
time = { version = "0.3", features = ["formatting", "macros"] }
Expand All @@ -56,6 +56,7 @@ globset = { version = "0.4.9", default-features = false }
dunce = "1.0.3"
trycmd = "0.14.0"
anyhow = "1.0.65"
concolor-control = { version = "0.0.7", features = ["auto"] }

[dev-dependencies]
assert_fs = "1.0"
Expand Down
3 changes: 1 addition & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,9 @@ pub fn report(result: Result<(), CliError>) -> i32 {
Ok(()) => 0,
Err(err) => {
if let Some(error) = err.error {
use std::io::Write;
// At this point, we might be exiting due to a broken pipe, just do our best and
// move on.
let _ = writeln!(std::io::stderr(), "{}", error);
let _ = crate::ops::shell::error(error);
}
err.code
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
pub mod config;
pub mod error;
pub mod ops;
pub mod shell;
pub mod steps;
25 changes: 16 additions & 9 deletions src/ops/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ pub fn wait_for_publish(
}

if !logged {
log::info!("Waiting for publish to complete...");
let _ = crate::ops::shell::status(
"Waiting",
format!("on {name} to propagate to index"),
);
logged = true;
}
std::thread::sleep(sleep_time);
Expand Down Expand Up @@ -229,7 +232,10 @@ pub fn ensure_owners(

let missing = expected.difference(&current).copied().collect::<Vec<_>>();
if !missing.is_empty() {
log::info!("Adding owners for {}: {}", name, missing.join(", "));
let _ = crate::ops::shell::status(
"Adding",
format!("owners for {}: {}", name, missing.join(", ")),
);
if !dry_run {
let mut cmd = std::process::Command::new(&cargo);
cmd.arg("owner").arg(name).arg("--color=never");
Expand All @@ -244,11 +250,11 @@ pub fn ensure_owners(
if !output.status.success() {
// HACK: Can't error as the user might not have permission to set owners and we can't
// tell what the error was without parsing it
log::warn!(
let _ = crate::ops::shell::warn(format!(
"Failed to set owners for {}: {}",
name,
String::from_utf8_lossy(&output.stderr)
);
));
}
}
}
Expand Down Expand Up @@ -451,11 +457,12 @@ fn upgrade_req(
}
};

log::info!(
"Updating {}'s dependency from {} to {}",
manifest_name,
existing_req_str,
new_req,
let _ = crate::ops::shell::status(
"Updating",
format!(
"{}'s dependency from {} to {}",
manifest_name, existing_req_str, new_req
),
);
*version_value = toml_edit::value(new_req);
true
Expand Down
6 changes: 4 additions & 2 deletions src/ops/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ pub fn is_behind_remote(dir: &Path, remote: &str, branch: &str) -> CargoResult<b
base_id != remote_branch_id
}
Err(err) => {
log::warn!("Push target `{}` doesn't exist", remote_branch);
let _ =
crate::ops::shell::warn(format!("Push target `{}` doesn't exist", remote_branch));
log::trace!("Error {}", err);
false
}
Expand All @@ -63,7 +64,8 @@ pub fn is_local_unchanged(dir: &Path, remote: &str, branch: &str) -> CargoResult
base_id != branch_id
}
Err(err) => {
log::warn!("Push target `{}` doesn't exist", remote_branch);
let _ =
crate::ops::shell::warn(format!("Push target `{}` doesn't exist", remote_branch));
log::trace!("Error {}", err);
false
}
Expand Down
18 changes: 12 additions & 6 deletions src/ops/replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ pub fn do_file_replacements(

for (path, replaces) in by_file.into_iter() {
let file = cwd.join(&path);
log::info!("Applying replacements for {}", path.display());
if !file.exists() {
anyhow::bail!("Unable to find file {} to perform replace", file.display());
}
Expand Down Expand Up @@ -135,12 +134,19 @@ pub fn do_file_replacements(
"replaced",
0,
);
let level = if noisy {
log::Level::Info
if noisy {
let _ = crate::ops::shell::status(
"Replacing",
format!(
"in {}\n{}",
path.display(),
itertools::join(diff.into_iter(), "")
),
);
} else {
log::Level::Debug
};
log::log!(level, "Change:\n{}", itertools::join(diff.into_iter(), ""));
let _ =
crate::ops::shell::status("Replacing", format!("in {}", path.display()));
}
} else {
std::fs::write(&file, replaced)?;
}
Expand Down
96 changes: 89 additions & 7 deletions src/ops/shell.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
use std::io::{stdin, stdout, Write};

use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use anyhow::Context as _;
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};

pub use termcolor::Color;

use crate::error::CargoResult;

pub fn confirm(prompt: &str) -> bool {
let mut input = String::new();

console_println(&format!("{} [y/N] ", prompt), None, true);

stdout().flush().unwrap();
stdin().read_line(&mut input).expect("y/n required");

input.trim().to_lowercase() == "y"
}

fn console_println(text: &str, color: Option<Color>, bold: bool) {
let mut stdout = StandardStream::stdout(ColorChoice::Auto);
Expand All @@ -13,13 +29,79 @@ fn console_println(text: &str, color: Option<Color>, bold: bool) {
stdout.reset().unwrap();
}

pub fn confirm(prompt: &str) -> bool {
let mut input = String::new();
/// Whether to color logged output
fn colorize_stderr() -> ColorChoice {
if concolor_control::get(concolor_control::Stream::Stderr).color() {
ColorChoice::Always
} else {
ColorChoice::Never
}
}

console_println(&format!("{} [y/N] ", prompt), None, true);
/// Print a message with a colored title in the style of Cargo shell messages.
pub fn print(
status: &str,
message: impl std::fmt::Display,
color: Color,
justified: bool,
) -> CargoResult<()> {
let color_choice = colorize_stderr();
let mut output = StandardStream::stderr(color_choice);

stdout().flush().unwrap();
stdin().read_line(&mut input).expect("y/n required");
output.set_color(ColorSpec::new().set_fg(Some(color)).set_bold(true))?;
if justified {
write!(output, "{status:>12}")?;
} else {
write!(output, "{}", status)?;
output.set_color(ColorSpec::new().set_bold(true))?;
write!(output, ":")?;
}
output.reset()?;

input.trim().to_lowercase() == "y"
writeln!(output, " {message}").with_context(|| "Failed to write message")?;

Ok(())
}

/// Print a styled action message.
pub fn status(action: &str, message: impl std::fmt::Display) -> CargoResult<()> {
print(action, message, Color::Green, true)
}

/// Print a styled error message.
pub fn error(message: impl std::fmt::Display) -> CargoResult<()> {
print("error", message, Color::Red, false)
}

/// Print a styled warning message.
pub fn warn(message: impl std::fmt::Display) -> CargoResult<()> {
print("warning", message, Color::Yellow, false)
}

/// Print a styled warning message.
pub fn note(message: impl std::fmt::Display) -> CargoResult<()> {
print("note", message, Color::Cyan, false)
}

pub fn log(level: log::Level, message: impl std::fmt::Display) -> CargoResult<()> {
match level {
log::Level::Error => error(message),
log::Level::Warn => warn(message),
log::Level::Info => note(message),
_ => {
log::log!(level, "{}", message);
Ok(())
}
}
}

/// Print a part of a line with formatting
pub fn write_stderr(fragment: impl std::fmt::Display, spec: &ColorSpec) -> CargoResult<()> {
let color_choice = colorize_stderr();
let mut output = StandardStream::stderr(color_choice);

output.set_color(spec)?;
write!(output, "{}", fragment)?;
output.reset()?;
Ok(())
}
72 changes: 72 additions & 0 deletions src/shell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::io::Write;

use anyhow::Context as _;
pub use termcolor::{Color, ColorChoice};
use termcolor::{ColorSpec, StandardStream, WriteColor};

use crate::error::CargoResult;

/// Whether to color logged output
fn colorize_stderr() -> ColorChoice {
if concolor_control::get(concolor_control::Stream::Stderr).color() {
ColorChoice::Always
} else {
ColorChoice::Never
}
}

/// Print a message with a colored title in the style of Cargo shell messages.
pub fn print(
status: &str,
message: impl std::fmt::Display,
color: Color,
justified: bool,
) -> CargoResult<()> {
let color_choice = colorize_stderr();
let mut output = StandardStream::stderr(color_choice);

output.set_color(ColorSpec::new().set_fg(Some(color)).set_bold(true))?;
if justified {
write!(output, "{status:>12}")?;
} else {
write!(output, "{}", status)?;
output.set_color(ColorSpec::new().set_bold(true))?;
write!(output, ":")?;
}
output.reset()?;

writeln!(output, " {message}").with_context(|| "Failed to write message")?;

Ok(())
}

/// Print a styled action message.
pub fn status(action: &str, message: impl std::fmt::Display) -> CargoResult<()> {
print(action, message, Color::Green, true)
}

/// Print a styled error message.
pub fn error(message: impl std::fmt::Display) -> CargoResult<()> {
print("error", message, Color::Red, false)
}

/// Print a styled warning message.
pub fn warn(message: impl std::fmt::Display) -> CargoResult<()> {
print("warning", message, Color::Yellow, false)
}

/// Print a styled warning message.
pub fn note(message: impl std::fmt::Display) -> CargoResult<()> {
print("note", message, Color::Cyan, false)
}

/// Print a part of a line with formatting
pub fn write_stderr(fragment: impl std::fmt::Display, spec: &ColorSpec) -> CargoResult<()> {
let color_choice = colorize_stderr();
let mut output = StandardStream::stderr(color_choice);

output.set_color(spec)?;
write!(output, "{}", fragment)?;
output.reset()?;
Ok(())
}
2 changes: 1 addition & 1 deletion src/steps/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl CommitStep {
.map(|(_, pkg)| pkg)
.partition(|p| p.config.release());
if crate::ops::git::is_dirty(ws_meta.workspace_root.as_std_path())?.is_none() {
log::info!("Nothing to commit.");
let _ = crate::ops::shell::error("Nothing to commit");
return Err(2.into());
}

Expand Down
6 changes: 3 additions & 3 deletions src/steps/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl HookStep {
.map(|(_, pkg)| pkg)
.partition(|p| p.config.release());
if selected_pkgs.is_empty() {
log::info!("No packages selected.");
let _ = crate::ops::shell::error("No packages selected");
return Err(2.into());
}

Expand Down Expand Up @@ -189,10 +189,10 @@ pub fn hook(
// we use dry_run environmental variable to run the script
// so here we set dry_run=false and always execute the command.
if !cmd::call_with_env(pre_rel_hook, envs, cwd, false)? {
log::error!(
let _ = crate::ops::shell::error(format!(
"Release of {} aborted by non-zero return of prerelease hook.",
crate_name
);
));
return Err(101.into());
}
}
Expand Down
Loading

0 comments on commit 151d39b

Please sign in to comment.