Skip to content

Commit

Permalink
store stdout and stderr in config
Browse files Browse the repository at this point in the history
  • Loading branch information
suaviloquence committed Apr 11, 2024
1 parent b21b96f commit 8448aed
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 66 deletions.
66 changes: 42 additions & 24 deletions src/check_release.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write as _;
use std::{collections::BTreeMap, sync::Arc, time::Instant};

use anstream::{eprintln, println};
use anstyle::{AnsiColor, Color, Reset, Style};

use anyhow::Context;
Expand Down Expand Up @@ -158,13 +158,14 @@ pub(super) fn run_check_release(
let mut results_with_errors = vec![];
for (semver_query, time_to_decide, results) in all_results {
config
.log_verbose(|_| {
.log_verbose(|config| {
let category = match semver_query.required_update {
RequiredSemverUpdate::Major => "major",
RequiredSemverUpdate::Minor => "minor",
};
if results.is_empty() {
eprintln!(
writeln!(
config.stderr(),
"{}{:>12}{} [{:8.3}s] {:^18} {}",
Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::Green)))
Expand All @@ -174,9 +175,10 @@ pub(super) fn run_check_release(
time_to_decide.as_secs_f32(),
category,
semver_query.id
);
)?;
} else {
eprintln!(
writeln!(
config.stderr(),
"{}{:>12}{} [{:>8.3}s] {:^18} {}",
Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::Red)))
Expand All @@ -186,7 +188,7 @@ pub(super) fn run_check_release(
time_to_decide.as_secs_f32(),
category,
semver_query.id
);
)?;
}
Ok(())
})
Expand Down Expand Up @@ -218,18 +220,20 @@ pub(super) fn run_check_release(
for (semver_query, results) in results_with_errors {
required_versions.push(semver_query.required_update);
config
.log_info(|_| {
println!(
.log_info(|config| {
writeln!(
config.stdout(),
"\n--- failure {}: {} ---\n",
&semver_query.id, &semver_query.human_readable_name
);
&semver_query.id,
&semver_query.human_readable_name
)?;
Ok(())
})
.expect("print failed");

if let Some(ref_link) = semver_query.reference_link.as_deref() {
config.log_info(|_| {
println!("{}Description:{}\n{}\n{:>12} {}\n{:>12} {}\n",
config.log_info(|config| {
writeln!(config.stdout(), "{}Description:{}\n{}\n{:>12} {}\n{:>12} {}\n",
Style::new().bold(), Reset,
&semver_query.error_message,
"ref:",
Expand All @@ -240,13 +244,14 @@ pub(super) fn run_check_release(
crate_version!(),
semver_query.id,
)
);
)?;
Ok(())
})
.expect("print failed");
} else {
config.log_info(|_| {
println!(
config.log_info(|config| {
writeln!(
config.stdout(),
"{}Description:{}\n{}\n{:>12} {}\n",
Style::new().bold(),
Reset,
Expand All @@ -257,15 +262,20 @@ pub(super) fn run_check_release(
crate_version!(),
semver_query.id,
)
);
)?;
Ok(())
})
.expect("print failed");
}

config
.log_info(|_| {
println!("{}Failed in:{}", Style::new().bold(), Reset);
.log_info(|config| {
writeln!(
config.stdout(),
"{}Failed in:{}",
Style::new().bold(),
Reset
)?;
Ok(())
})
.expect("print failed");
Expand All @@ -283,28 +293,36 @@ pub(super) fn run_check_release(
.context("Error instantiating semver query template.")
.expect("could not materialize template");
config
.log_info(|_| {
println!(" {}", message);
.log_info(|config| {
writeln!(config.stdout(), " {}", message)?;
Ok(())
})
.expect("print failed");

config
.log_extra_verbose(|_| {
.log_extra_verbose(|config| {
let serde_pretty =
serde_json::to_string_pretty(&pretty_result).expect("serde failed");
let indented_serde = serde_pretty
.split('\n')
.map(|line| format!(" {line}"))
.join("\n");
println!("\tlint rule output values:\n{}", indented_serde);
writeln!(
config.stdout(),
"\tlint rule output values:\n{}",
indented_serde
)?;
Ok(())
})
.expect("print failed");
} else {
config
.log_info(|_| {
println!("{}\n", serde_json::to_string_pretty(&pretty_result)?);
.log_info(|config| {
writeln!(
config.stdout(),
"{}\n",
serde_json::to_string_pretty(&pretty_result)?
)?;
Ok(())
})
.expect("print failed");
Expand Down
107 changes: 102 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use anstream::{eprint, eprintln};
use anstream::AutoStream;
use anstyle::{AnsiColor, Color, Reset, Style};
use std::io::Write;

use crate::templating::make_handlebars_registry;

// re-export this so users don't have to add the `anstream` crate directly
// just to set color choice
pub use anstream::ColorChoice;

#[allow(dead_code)]
pub struct GlobalConfig {
level: Option<log::Level>,
Expand All @@ -11,6 +16,8 @@ pub struct GlobalConfig {
///
/// This will be used to print an error if the user's rustc version is not high enough.
minimum_rustc_version: semver::Version,
stdout: AutoStream<Box<dyn Write + 'static>>,
stderr: AutoStream<Box<dyn Write + 'static>>,
}

impl Default for GlobalConfig {
Expand All @@ -21,10 +28,15 @@ impl Default for GlobalConfig {

impl GlobalConfig {
pub fn new() -> Self {
let stdout_choice = anstream::stdout().current_choice();
let stderr_choice = anstream::stdout().current_choice();

Self {
level: None,
handlebars: make_handlebars_registry(),
minimum_rustc_version: semver::Version::new(1, 74, 0),
stdout: AutoStream::new(Box::new(std::io::stdout()), stdout_choice),
stderr: AutoStream::new(Box::new(std::io::stderr()), stderr_choice),
}
}

Expand Down Expand Up @@ -106,14 +118,14 @@ impl GlobalConfig {
justified: bool,
) -> anyhow::Result<()> {
if self.is_info() {
eprint!("{}", Style::new().fg_color(Some(color)).bold());
write!(self.stderr, "{}", Style::new().fg_color(Some(color)).bold())?;
if justified {
eprint!("{status:>12}");
write!(self.stderr, "{status:>12}")?;
} else {
eprint!("{status}{}{}:", Reset, Style::new().bold());
write!(self.stderr, "{status}{}{}:", Reset, Style::new().bold())?;
}

eprintln!("{} {message}", Reset);
writeln!(self.stderr, "{Reset} {message}")?;
}

Ok(())
Expand All @@ -135,6 +147,91 @@ impl GlobalConfig {
pub fn shell_warn(&mut self, message: impl std::fmt::Display) -> anyhow::Result<()> {
self.shell_print("warning", message, Color::Ansi(AnsiColor::Yellow), false)
}

/// Gets the color-supporting `stdout` that the crate will use.
///
/// See [`GlobalConfig::set_stdout`] and [`GlobalConfig::set_out_color_choice`] to
/// configure this stream
#[must_use]
#[inline]
pub fn stdout(&mut self) -> impl Write + '_ {
&mut self.stdout
}

/// Gets the color-supporting `stderr` that the crate will use.
///
/// See [`GlobalConfig::set_stderr`] and [`GlobalConfig::set_err_color_choice`] to
/// configure this stream
#[must_use]
#[inline]
pub fn stderr(&mut self) -> impl Write + '_ {
&mut self.stderr
}

/// Sets the stderr output stream
///
/// Defaults to the global color choice setting in [`ColorChoice::global`].
/// Call [`GlobalConfig::set_err_color_choice`] to customize the color choice
pub fn set_stderr(&mut self, err: Box<dyn Write + 'static>) {
self.stderr = AutoStream::new(err, ColorChoice::global());
}

/// Sets the stderr output stream
///
/// Defaults to the global color choice setting in [`ColorChoice::global`].
/// Call [`GlobalConfig::set_err_color_choice`] to customize the color choice
pub fn set_stdout(&mut self, out: Box<dyn Write + 'static>) {
self.stdout = AutoStream::new(out, ColorChoice::global());
}

/// Individually set the color choice setting for [`GlobalConfig::stderr`]
///
/// Defaults to the global color choice in [`ColorChoice::global`], which can be set
/// in [`ColorChoice::write_global`] if you are using the `anstream` crate.
///
/// See also [`GlobalConfig::set_out_color_choice`] and [`GlobalConfig::set_color_choice`]
pub fn set_err_color_choice(&mut self, choice: ColorChoice) {
// TODO - `anstream` doesn't have a good mechanism to set color choice (on one stream)
// without making a new object, so we have to make a new autostream, but since we need
// to move the `RawStream` inner, we temporarily replace it with /dev/null
let stderr = std::mem::replace(
&mut self.stderr,
AutoStream::never(Box::new(std::io::sink())),
);
self.stderr = AutoStream::new(stderr.into_inner(), choice);
}

/// Individually set the color choice setting for [`GlobalConfig::stdout`]
///
/// Defaults to the global color choice in [`ColorChoice::global`], which can be set
/// in [`ColorChoice::write_global`] if you are using the `anstream` crate.
///
/// See also [`GlobalConfig::set_err_color_choice`] and [`GlobalConfig::set_color_choice`]
pub fn set_out_color_choice(&mut self, choice: ColorChoice) {
// TODO - `anstream` doesn't have a good mechanism to set color choice (on one stream)
// without making a new object, so we have to make a new autostream, but since we need
// to move the `RawStream` inner, we temporarily replace it with /dev/null
let stdout = std::mem::replace(
&mut self.stdout,
AutoStream::never(Box::new(std::io::sink())),
);
self.stdout = AutoStream::new(stdout.into_inner(), choice);
}

/// Sets the color choice for both [`GlobalConfig::stderr`] and [`GlobalConfig::stdout`]
///
/// Defaults to the global color choice in [`ColorChoice::global`], which can be set
/// in [`ColorChoice::write_global`] if you are using the `anstream` crate.
///
/// Prefer to use [`ColorChoice::write_global`] to avoid creating new stream objects if you
/// don't need to configure `cargo-semver-checks` colors differently than other crates
/// that use `anstream` for outputting colors.
///
/// See also [`GlobalConfig::set_err_color_choice`] and [`GlobalConfig::set_out_color_choice`]
pub fn set_color_choice(&mut self, choice: ColorChoice) {
self.set_err_color_choice(choice);
self.set_out_color_choice(choice);
}
}

#[cfg(test)]
Expand Down
15 changes: 6 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn main() {

let Cargo::SemverChecks(args) = Cargo::parse();

args.check_release.color_choice.write_global();
args.color_choice.write_global();

if args.bugreport {
use bugreport::{bugreport, collector::*, format::Markdown};
Expand Down Expand Up @@ -134,6 +134,10 @@ struct SemverChecks {

#[command(subcommand)]
command: Option<SemverChecksCommands>,

// docstring for help is on the `colorchoice_clap::Color` struct itself
#[command(flatten)]
color_choice: colorchoice_clap::Color,
}

/// Check your crate for semver violations.
Expand Down Expand Up @@ -284,16 +288,9 @@ struct CheckRelease {
#[arg(long = "target")]
build_target: Option<String>,

// docstring for help is on the `clap_verbosity_flag::Verbosity` struct itself
#[command(flatten)]
verbosity: clap_verbosity_flag::Verbosity<clap_verbosity_flag::InfoLevel>,

/// Whether to print colors to the terminal:
/// always, always-ansi (always use only ANSI color codes),
/// auto (based on whether output is a tty), and never
///
/// Default is auto (use colors if output is a TTY, otherwise don't use colors)
#[command(flatten)]
color_choice: colorchoice_clap::Color,
}

impl From<CheckRelease> for cargo_semver_checks::Check {
Expand Down
Loading

0 comments on commit 8448aed

Please sign in to comment.