diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 081b71d4..94774f80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,6 +82,9 @@ jobs: cargo llvm-cov nextest --text --fail-under-lines 50 --profile default --cargo-profile dev cargo llvm-cov nextest --text --fail-under-lines 50 --profile ci cargo llvm-cov nextest --text --fail-under-lines 50 --profile ci --cargo-profile dev + cd ../real1 + cargo llvm-cov nextest-archive --archive-file a.tar.zst + cargo llvm-cov nextest --archive-file a.tar.zst --text --fail-under-lines 70 working-directory: tests/fixtures/crates/bin_crate - run: | set -eEuxo pipefail diff --git a/docs/cargo-llvm-cov-nextest-archive.txt b/docs/cargo-llvm-cov-nextest-archive.txt new file mode 100644 index 00000000..77c8d72a --- /dev/null +++ b/docs/cargo-llvm-cov-nextest-archive.txt @@ -0,0 +1,10 @@ +cargo-llvm-cov-nextest-archive +Build and archive tests with cargo nextest +This internally calls `cargo nextest archive`. + +USAGE: + cargo llvm-cov nextest-archive [OPTIONS] [NEXTEST_OPTIONS] + +ARGS: + [OPTIONS] Options for cargo-llvm-cov; For more information try `cargo llvm-cov --help` + [NEXTEST_OPTIONS] Options for cargo-nextest; For more information try `cargo nextest archive --help` diff --git a/src/cargo.rs b/src/cargo.rs index 67ba1df7..d700a927 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -7,7 +7,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use cargo_config2::Config; use crate::{ - cli::{ManifestOptions, Subcommand}, + cli::{Args, ManifestOptions, Subcommand}, context::Context, env, metadata::Metadata, @@ -217,8 +217,7 @@ pub(crate) fn test_or_run_args(cx: &Context, cmd: &mut ProcessBuilder) { cmd.arg("--manifest-path"); cmd.arg(&cx.ws.current_manifest); - cmd.arg("--target-dir"); - cmd.arg(&cx.ws.target_dir); + add_target_dir(&cx.args, cmd, &cx.ws.target_dir); for cargo_arg in &cx.args.cargo_args { cmd.arg(cargo_arg); @@ -252,7 +251,7 @@ pub(crate) fn clean_args(cx: &Context, cmd: &mut ProcessBuilder) { cmd.arg(&cx.ws.current_manifest); cmd.arg("--target-dir"); - cmd.arg(&cx.ws.target_dir); + cmd.arg(cx.ws.target_dir.as_str()); cx.args.manifest.cargo_args(cmd); @@ -261,3 +260,15 @@ pub(crate) fn clean_args(cx: &Context, cmd: &mut ProcessBuilder) { cmd.arg(format!("-{}", "v".repeat(usize::from(cx.args.verbose) - 1))); } } + +// https://github.com/taiki-e/cargo-llvm-cov/issues/265 +fn add_target_dir(args: &Args, cmd: &mut ProcessBuilder, target_dir: &Utf8Path) { + if args.subcommand == Subcommand::Nextest + && args.cargo_args.contains(&"--archive-file".to_string()) + { + cmd.arg("--extract-to"); + } else { + cmd.arg("--target-dir"); + } + cmd.arg(target_dir.as_str()); +} diff --git a/src/cli.rs b/src/cli.rs index 4def3b17..d3c49172 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -368,10 +368,10 @@ impl Args { // build options Short('r') | Long("release") => parse_flag_passthrough!(release), - Long("profile") if subcommand != Subcommand::Nextest => { + Long("profile") if !subcommand.is_nextest_based() => { parse_opt_passthrough!(profile); } - Long("cargo-profile") if subcommand == Subcommand::Nextest => { + Long("cargo-profile") if subcommand.is_nextest_based() => { parse_opt_passthrough!(profile); } Long("target") => parse_opt_passthrough!(target), @@ -444,7 +444,11 @@ impl Args { Short('F' | 'j') | Long("features" | "jobs") if matches!( subcommand, - Subcommand::None | Subcommand::Test | Subcommand::Run | Subcommand::Nextest + Subcommand::None + | Subcommand::Test + | Subcommand::Run + | Subcommand::Nextest + | Subcommand::NextestArchive ) => { parse_opt_passthrough!(()); @@ -457,7 +461,11 @@ impl Args { | "--ignore-rust-version", ) if matches!( subcommand, - Subcommand::None | Subcommand::Test | Subcommand::Run | Subcommand::Nextest + Subcommand::None + | Subcommand::Test + | Subcommand::Run + | Subcommand::Nextest + | Subcommand::NextestArchive ) => { passthrough!(); @@ -520,12 +528,14 @@ impl Args { match subcommand { Subcommand::None | Subcommand::Test => {} Subcommand::ShowEnv | Subcommand::Report if doctests => {} - Subcommand::Nextest => bail!("doctest is not supported for nextest"), + Subcommand::Nextest | Subcommand::NextestArchive => { + bail!("doctest is not supported for nextest") + } _ => unexpected(flag, subcommand)?, } } match subcommand { - Subcommand::None | Subcommand::Nextest => {} + Subcommand::None | Subcommand::Nextest | Subcommand::NextestArchive => {} Subcommand::Test => { if no_run { unexpected("--no-run", subcommand)?; @@ -571,7 +581,11 @@ impl Args { } } match subcommand { - Subcommand::None | Subcommand::Test | Subcommand::Run | Subcommand::Nextest => {} + Subcommand::None + | Subcommand::Test + | Subcommand::Run + | Subcommand::Nextest + | Subcommand::NextestArchive => {} _ => { if !bin.is_empty() { unexpected("--bin", subcommand)?; @@ -600,7 +614,11 @@ impl Args { } } match subcommand { - Subcommand::None | Subcommand::Test | Subcommand::Nextest | Subcommand::Clean => {} + Subcommand::None + | Subcommand::Test + | Subcommand::Nextest + | Subcommand::NextestArchive + | Subcommand::Clean => {} _ => { if workspace { unexpected("--workspace", subcommand)?; @@ -891,6 +909,9 @@ pub(crate) enum Subcommand { /// Run tests with cargo nextest Nextest, + /// Build and archive tests with cargo nextest + NextestArchive, + // internal (unstable) Demangle, } @@ -902,10 +923,12 @@ static CARGO_LLVM_COV_REPORT_USAGE: &str = include_str!("../docs/cargo-llvm-cov- static CARGO_LLVM_COV_CLEAN_USAGE: &str = include_str!("../docs/cargo-llvm-cov-clean.txt"); static CARGO_LLVM_COV_SHOW_ENV_USAGE: &str = include_str!("../docs/cargo-llvm-cov-show-env.txt"); static CARGO_LLVM_COV_NEXTEST_USAGE: &str = include_str!("../docs/cargo-llvm-cov-nextest.txt"); +static CARGO_LLVM_COV_NEXTEST_ARCHIVE_USAGE: &str = + include_str!("../docs/cargo-llvm-cov-nextest-archive.txt"); impl Subcommand { fn can_passthrough(subcommand: Self) -> bool { - matches!(subcommand, Self::Test | Self::Run | Self::Nextest) + matches!(subcommand, Self::Test | Self::Run | Self::Nextest | Self::NextestArchive) } fn help_text(subcommand: Self) -> &'static str { @@ -917,6 +940,7 @@ impl Subcommand { Self::Clean => CARGO_LLVM_COV_CLEAN_USAGE, Self::ShowEnv => CARGO_LLVM_COV_SHOW_ENV_USAGE, Self::Nextest => CARGO_LLVM_COV_NEXTEST_USAGE, + Self::NextestArchive => CARGO_LLVM_COV_NEXTEST_ARCHIVE_USAGE, Self::Demangle => "", // internal API } } @@ -930,9 +954,14 @@ impl Subcommand { Self::Clean => "clean", Self::ShowEnv => "show-env", Self::Nextest => "nextest", + Self::NextestArchive => "nextest-archive", Self::Demangle => "demangle", } } + + pub(crate) fn is_nextest_based(self) -> bool { + matches!(self, Self::Nextest | Self::NextestArchive) + } } impl FromStr for Subcommand { @@ -946,6 +975,7 @@ impl FromStr for Subcommand { "clean" => Ok(Self::Clean), "show-env" => Ok(Self::ShowEnv), "nextest" => Ok(Self::Nextest), + "nextest-archive" => Ok(Self::NextestArchive), "demangle" => Ok(Self::Demangle), _ => bail!("unrecognized subcommand {s}"), } diff --git a/src/context.rs b/src/context.rs index a636257a..b6a5e9a9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -105,7 +105,7 @@ impl Context { "cargo-llvm-cov subcommands other than report and clean may not work correctly \ in context where environment variables are set by show-env; consider using \ normal {} commands", - if args.subcommand == Subcommand::Nextest { "cargo-nextest" } else { "cargo" } + if args.subcommand.is_nextest_based() { "cargo-nextest" } else { "cargo" } ); } diff --git a/src/main.rs b/src/main.rs index f1422d2e..199a416b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -100,6 +100,12 @@ fn try_main() -> Result<()> { generate_report(cx)?; } } + Subcommand::NextestArchive => { + let cx = &Context::new(args)?; + clean::clean_partial(cx)?; + create_dirs(cx)?; + archive_nextest(cx)?; + } Subcommand::None | Subcommand::Test => { let cx = &Context::new(args)?; clean::clean_partial(cx)?; @@ -382,6 +388,23 @@ fn run_test(cx: &Context) -> Result<()> { Ok(()) } +fn archive_nextest(cx: &Context) -> Result<()> { + let mut cargo = cx.cargo(); + + set_env(cx, &mut cargo, IsNextest(true))?; + + cargo.arg("nextest").arg("archive"); + + cargo::test_or_run_args(cx, &mut cargo); + if term::verbose() { + status!("Running", "{cargo}"); + } + stdout_to_stderr(cx, &mut cargo); + cargo.run()?; + + Ok(()) +} + fn run_nextest(cx: &Context) -> Result<()> { let mut cargo = cx.cargo(); @@ -697,6 +720,11 @@ fn object_files(cx: &Context) -> Result> { // This is not the ideal way, but the way unstable book says it is cannot support them. // https://doc.rust-lang.org/nightly/rustc/instrument-coverage.html#tips-for-listing-the-binaries-automatically let mut target_dir = cx.ws.target_dir.clone(); + if cx.args.subcommand == Subcommand::Nextest + && cx.args.cargo_args.iter().any(|a| a == "--archive-file") + { + target_dir.push("target"); + } // https://doc.rust-lang.org/nightly/cargo/guide/build-cache.html if let Some(target) = &cx.args.target { target_dir.push(target);