diff --git a/CHANGELOG.md b/CHANGELOG.md index 0feedaaf5d..0d78b8d766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,17 +3,17 @@ From 2019 onwards, all notable changes to tarpaulin will be documented in this file. -## [Unreleased] -### Changed -- For `LD_LIBRARY_PATH` get all link paths from build script outputs -- Use `PATH` on windows and `DYLIB_LIBRARY_PATH` for mac instead of `LD_LIBRARY_PATH` - -## [0.31.3] 2024-10-10 +## [0.31.3] 2024-11-29 ### Added - The `CARGO_TARPAULIN_CONFIG_FILE` environment variable may be used to set the path to the configuration file. The command line argument has precedence, but this environment variable has precedence over `tarpaulin.toml` and `.tarpaulin.toml`. +### Changed +- For `LD_LIBRARY_PATH` get all link paths from build script outputs +- Use `PATH` on windows and `DYLIB_LIBRARY_PATH` for mac instead of `LD_LIBRARY_PATH` +- Add `--stderr` flag to print tarpaulin logs to stderr + ## [0.31.2] 2024-08-20 ### Changed - Removed debug printout of function map diff --git a/Cargo.lock b/Cargo.lock index 5ea3b52504..8d08b8e8dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,7 +179,7 @@ dependencies = [ [[package]] name = "cargo-tarpaulin" -version = "0.31.2" +version = "0.31.3" dependencies = [ "cargo_metadata", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 890a5797ad..4376eb150f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-tarpaulin" -version = "0.31.2" +version = "0.31.3" authors = ["Daniel McKenna "] description = "Cargo-Tarpaulin is a tool to determine code coverage achieved via tests" repository = "https://github.com/xd009642/tarpaulin" diff --git a/README.md b/README.md index 9870e8e12c..a3887fbcea 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Options: --debug Show debug output - this is used for diagnosing issues with tarpaulin -v, --verbose Show extra output --dump-traces Log tracing events and save to a json file. Also, enabled when --debug is used + --stderr Print tarpaulin logs to stderr instead - test output will still be printed to stdout --run-types Type of the coverage run [possible values: Tests, Doctests, Benchmarks, Examples, Lib, Bins, AllTargets] --benches Test all benches --doc Test only this library's documentation diff --git a/src/args.rs b/src/args.rs index 7f9505911f..03b438db90 100644 --- a/src/args.rs +++ b/src/args.rs @@ -226,6 +226,9 @@ pub struct LoggingArgs { /// Log tracing events and save to a json file. Also, enabled when --debug is used #[arg(long)] pub dump_traces: bool, + /// Print tarpaulin logs to stderr instead - test output will still be printed to stdout + #[arg(long)] + pub stderr: bool, } #[derive(Debug, Clone, Copy, Args)] diff --git a/src/config/mod.rs b/src/config/mod.rs index beb271e115..f04d870dc7 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -190,6 +190,8 @@ pub struct Config { profraw_folder: PathBuf, /// Option to fail immediately after a single test fails pub fail_immediately: bool, + /// Log to stderr instead + pub stderr: bool, } fn default_test_timeout() -> Duration { @@ -264,6 +266,7 @@ impl Default for Config { objects: vec![], profraw_folder: PathBuf::from("profraws"), fail_immediately: false, + stderr: false, } } } @@ -351,6 +354,7 @@ impl From for ConfigWrapper { objects: canonicalize_paths(args.objects), profraw_folder: PathBuf::from("profraws"), fail_immediately: args.fail_immediately, + stderr: args.logging.stderr, }; if args.ignore_config { Self(vec![args_config]) @@ -614,6 +618,7 @@ impl Config { self.branch_coverage |= other.branch_coverage; self.dump_traces |= other.dump_traces; self.offline |= other.offline; + self.stderr |= other.stderr; if self.manifest != other.manifest && self.manifest == default_manifest() { self.manifest = other.manifest.clone(); } diff --git a/src/lib.rs b/src/lib.rs index 3c13c8ed36..b7296649a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ use crate::test_loader::*; use crate::traces::*; use std::ffi::OsString; use std::fs::{create_dir_all, remove_dir_all}; +use std::io; use tracing::{debug, error, info, warn}; use tracing_subscriber::{filter::LevelFilter, EnvFilter}; @@ -29,7 +30,7 @@ pub mod traces; const RUST_LOG_ENV: &str = "RUST_LOG"; #[cfg(not(tarpaulin_include))] -pub fn setup_logging(color: Color, debug: bool, verbose: bool) { +pub fn setup_logging(color: Color, debug: bool, verbose: bool, stderr: bool) { //By default, we set tarpaulin to info,debug,trace while all dependencies stay at INFO let base_exceptions = |env: EnvFilter| { if debug { @@ -66,11 +67,16 @@ pub fn setup_logging(color: Color, debug: bool, verbose: bool) { let with_ansi = color != Color::Never; - let res = tracing_subscriber::FmtSubscriber::builder() + let builder = tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::ERROR) .with_env_filter(filter) - .with_ansi(with_ansi) - .try_init(); + .with_ansi(with_ansi); + + let res = if stderr { + builder.with_writer(io::stderr).try_init() + } else { + builder.try_init() + }; if let Err(e) = res { eprintln!("Logging may be misconfigured: {e}"); diff --git a/src/main.rs b/src/main.rs index 0050956a33..f60f6149f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ fn main() -> Result<(), String> { logging_args.color.unwrap_or(Color::Auto), logging_args.debug, logging_args.verbose, + logging_args.stderr, ); let config = ConfigWrapper::from(args.config); diff --git a/src/report/mod.rs b/src/report/mod.rs index 682ed9b142..3e3ebff0f6 100644 --- a/src/report/mod.rs +++ b/src/report/mod.rs @@ -6,7 +6,7 @@ use crate::traces::*; use cargo_metadata::Metadata; use serde::Serialize; use std::fs::{create_dir_all, File}; -use std::io::BufReader; +use std::io::{self, BufReader, Write}; use tracing::{error, info}; pub mod cobertura; @@ -108,7 +108,12 @@ fn generate_requested_reports(config: &Config, result: &TraceMap) -> Result<(), } fn print_missing_lines(config: &Config, result: &TraceMap) { - println!("|| Uncovered Lines:"); + let mut w: Box = if config.stderr { + Box::new(io::stderr().lock()) + } else { + Box::new(io::stdout().lock()) + }; + writeln!(w, "|| Uncovered Lines:").unwrap(); for (key, value) in result.iter() { let path = config.strip_base_dir(key); let mut uncovered_lines = vec![]; @@ -123,7 +128,7 @@ fn print_missing_lines(config: &Config, result: &TraceMap) { .fold((vec![], vec![]), accumulate_lines); let (groups, _) = accumulate_lines((groups, last_group), u64::max_value()); if !groups.is_empty() { - println!("|| {}: {}", path.display(), groups.join(", ")); + writeln!(w, "|| {}: {}", path.display(), groups.join(", ")).unwrap(); } } } @@ -147,11 +152,17 @@ fn get_previous_result(config: &Config) -> Option { } fn print_summary(config: &Config, result: &TraceMap) { + let mut w: Box = if config.stderr { + Box::new(io::stderr().lock()) + } else { + Box::new(io::stdout().lock()) + }; let last = match get_previous_result(config) { Some(l) => l, None => TraceMap::new(), }; - println!("|| Tested/Total Lines:"); + // All the `writeln` unwraps are fine, it's basically what the `println` macro does + writeln!(w, "|| Tested/Total Lines:").unwrap(); for file in result.files() { if result.coverable_in_path(file) == 0 { continue; @@ -161,41 +172,49 @@ fn print_summary(config: &Config, result: &TraceMap) { let last_percent = coverage_percentage(last.get_child_traces(file)); let current_percent = coverage_percentage(result.get_child_traces(file)); let delta = 100.0f64 * (current_percent - last_percent); - println!( + writeln!( + w, "|| {}: {}/{} {:+.2}%", path.display(), result.covered_in_path(file), result.coverable_in_path(file), delta - ); + ) + .unwrap(); } else { - println!( + writeln!( + w, "|| {}: {}/{}", path.display(), result.covered_in_path(file), result.coverable_in_path(file) - ); + ) + .unwrap(); } } let percent = result.coverage_percentage() * 100.0f64; if result.total_coverable() == 0 { - println!("No coverable lines found"); + writeln!(w, "No coverable lines found").unwrap(); } else if last.is_empty() { - println!( + writeln!( + w, "|| \n{:.2}% coverage, {}/{} lines covered", percent, result.total_covered(), result.total_coverable() - ); + ) + .unwrap(); } else { let delta = percent - 100.0f64 * last.coverage_percentage(); - println!( + writeln!( + w, "|| \n{:.2}% coverage, {}/{} lines covered, {:+.2}% change in coverage", percent, result.total_covered(), result.total_coverable(), delta - ); + ) + .unwrap(); } } diff --git a/tests/mod.rs b/tests/mod.rs index 6e9472b55a..dd87674005 100755 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -91,7 +91,7 @@ pub fn check_percentage_with_config( // Note to contributors. If an integration test fails, uncomment this to be able to see the // tarpaulin logs - //cargo_tarpaulin::setup_logging(true, true); + //cargo_tarpaulin::setup_logging(true, true, false); let event_log = if config.dump_traces { let mut paths = HashSet::new(); paths.insert(config.manifest());