Skip to content

Commit aac7ad5

Browse files
committed
[cargo-nextest] fail if --target wasn't understood
Currently, if nextest cannot parse a target triple it prints a warning, and instead just builds on the host platform. I think that isn't the right behavior, and instead nextest should loudly fail. Implement this change: fail with a clear error message. I consider the current behavior a bug, so I don't think this needs to go through the behavior change process. Also, hook up miette support to produce better error messages if deserializing custom JSON fails, and add tests to verify this behavior. For target runners, we continue to warn rather than fail.
1 parent 623b3ab commit aac7ad5

File tree

17 files changed

+318
-28
lines changed

17 files changed

+318
-28
lines changed

Cargo.lock

Lines changed: 81 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ clap = { version = "4.5.23", features = ["derive"] }
4747
console-subscriber = "0.4.1"
4848
cp_r = "0.5.2"
4949
crossterm = { version = "0.28.1", features = ["event-stream"] }
50+
datatest-stable = { version = "0.3.0", features = ["include-dir"] }
5051
dialoguer = "0.11.0"
5152
debug-ignore = "1.0.5"
5253
derive-where = "1.2.7"

cargo-nextest/src/cargo_cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub(crate) struct CargoOptions {
187187

188188
// NOTE: this does not conflict with reuse build opts (not part of the cargo-opts group) since
189189
// we let target.runner be specified this way
190-
/// Override a configuration value
190+
/// Override a Cargo configuration value
191191
#[arg(long, value_name = "KEY=VALUE", help_heading = "Other Cargo options")]
192192
pub(crate) config: Vec<String>,
193193

cargo-nextest/src/dispatch.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use nextest_runner::{
2121
ToolConfigFile, VersionOnlyConfig,
2222
},
2323
double_spawn::DoubleSpawnInfo,
24-
errors::WriteTestListError,
24+
errors::{TargetTripleError, WriteTestListError},
2525
input::InputHandlerKind,
2626
list::{
2727
BinaryList, OutputFormat, RustTestArtifact, SerializableFormat, TestExecuteContext,
@@ -1160,18 +1160,16 @@ impl BaseApp {
11601160
let host = HostPlatform::current(PlatformLibdir::from_rustc_stdout(
11611161
RustcCli::print_host_libdir().read(),
11621162
))?;
1163-
let target = if let Some(triple) = discover_target_triple(
1164-
&cargo_configs,
1165-
cargo_opts.target.as_deref(),
1166-
&output.stderr_styles(),
1167-
) {
1163+
1164+
let triple_info =
1165+
discover_target_triple(&cargo_configs, cargo_opts.target.as_deref())?;
1166+
let target = triple_info.map(|triple| {
11681167
let libdir = PlatformLibdir::from_rustc_stdout(
11691168
RustcCli::print_target_libdir(&triple).read(),
11701169
);
1171-
Some(TargetPlatform::new(triple, libdir))
1172-
} else {
1173-
None
1174-
};
1170+
TargetPlatform::new(triple, libdir)
1171+
});
1172+
11751173
BuildPlatforms { host, target }
11761174
}
11771175
};
@@ -2102,6 +2100,17 @@ enum DebugCommand {
21022100

21032101
/// Print the current executable path.
21042102
CurrentExe,
2103+
2104+
/// Show the target platform that nextest would use.
2105+
ShowTarget {
2106+
/// The target triple to use.
2107+
#[arg(long)]
2108+
target: Option<String>,
2109+
2110+
/// Override a Cargo configuration value.
2111+
#[arg(long, value_name = "KEY=VALUE")]
2112+
config: Vec<String>,
2113+
},
21052114
}
21062115

21072116
impl DebugCommand {
@@ -2162,6 +2171,15 @@ impl DebugCommand {
21622171
.map_err(|err| ExpectedError::GetCurrentExeFailed { err })?;
21632172
println!("{}", exe.display());
21642173
}
2174+
DebugCommand::ShowTarget { target, config } => {
2175+
let cargo_configs = CargoConfigs::new(&config).map_err(Box::new)?;
2176+
let target = discover_target_triple(&cargo_configs, target.as_deref())?;
2177+
if let Some(target) = target {
2178+
println!("{:#?}", target);
2179+
} else {
2180+
println!("no target triple found");
2181+
}
2182+
}
21652183
}
21662184

21672185
Ok(0)
@@ -2286,28 +2304,19 @@ fn acquire_graph_data(
22862304
fn discover_target_triple(
22872305
cargo_configs: &CargoConfigs,
22882306
target_cli_option: Option<&str>,
2289-
styles: &StderrStyles,
2290-
) -> Option<TargetTriple> {
2291-
match TargetTriple::find(cargo_configs, target_cli_option) {
2292-
Ok(Some(triple)) => {
2307+
) -> Result<Option<TargetTriple>, TargetTripleError> {
2308+
TargetTriple::find(cargo_configs, target_cli_option).inspect(|v| {
2309+
if let Some(triple) = v {
22932310
debug!(
22942311
"using target triple `{}` defined by `{}`; {}",
22952312
triple.platform.triple_str(),
22962313
triple.source,
22972314
triple.location,
22982315
);
2299-
Some(triple)
2300-
}
2301-
Ok(None) => {
2316+
} else {
23022317
debug!("no target triple found, assuming no cross-compilation");
2303-
2304-
None
2305-
}
2306-
Err(err) => {
2307-
warn_on_err("target triple", &err, styles);
2308-
None
23092318
}
2310-
}
2319+
})
23112320
}
23122321

23132322
fn runner_for_target(

cargo-nextest/src/errors.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,14 @@ impl ExpectedError {
657657
Some(err as &dyn Error)
658658
}
659659
Self::TargetTripleError { err } => {
660-
error!("{err}");
661-
err.source()
660+
if let Some(report) = err.source_report() {
661+
// Display the miette report if available.
662+
error!(target: "cargo_nextest::no_heading", "{report:?}");
663+
None
664+
} else {
665+
error!("{err}");
666+
err.source()
667+
}
662668
}
663669
Self::MetadataMaterializeError { arg_name, err } => {
664670
error!(

integration-tests/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ path = "test-helpers/build-seed-archive.rs"
1717
name = "custom-harness"
1818
harness = false
1919

20+
[[test]]
21+
name = "datatest"
22+
harness = false
23+
2024
[dependencies]
2125
camino.workspace = true
2226
camino-tempfile.workspace = true
@@ -44,6 +48,7 @@ whoami.workspace = true
4448
[dev-dependencies]
4549
cfg-if.workspace = true
4650
cp_r.workspace = true
51+
datatest-stable.workspace = true
4752
fixture-data.workspace = true
4853
insta.workspace = true
4954
itertools.workspace = true
@@ -52,6 +57,7 @@ nextest-metadata.workspace = true
5257
pathdiff.workspace = true
5358
regex.workspace = true
5459
target-spec.workspace = true
60+
target-spec-miette = { workspace = true, features = ["fixtures"] }
5561
tokio.workspace = true
5662

5763
# These platforms are supported by num_threads.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) The nextest Contributors
2+
// SPDX-License-Identifier: MIT OR Apache-2.0
3+
4+
use crate::helpers::bind_insta_settings;
5+
use camino::Utf8Path;
6+
use camino_tempfile::Utf8TempDir;
7+
use integration_tests::nextest_cli::CargoNextestCli;
8+
use nextest_metadata::NextestExitCode;
9+
10+
pub(crate) fn custom_invalid(path: &Utf8Path, contents: String) -> datatest_stable::Result<()> {
11+
let (_guard, insta_prefix) = bind_insta_settings(path, "snapshots/custom-invalid");
12+
13+
let dir = Utf8TempDir::with_prefix("nextest-custom-target-")?;
14+
let json_path = dir.path().join(path.file_name().unwrap());
15+
std::fs::write(&json_path, contents)?;
16+
17+
let output = CargoNextestCli::for_test()
18+
.args([
19+
// Use color in snapshots to ensure that it is correctly passed
20+
// through.
21+
//
22+
// It might be nice to use snapbox in the future, because it has
23+
// really nice color support.
24+
"--color",
25+
"always",
26+
"debug",
27+
"show-target",
28+
"--target",
29+
json_path.as_str(),
30+
])
31+
.unchecked(true)
32+
.output();
33+
34+
// We expect this to fail with a setup error.
35+
assert!(!output.exit_status.success());
36+
assert_eq!(
37+
output.exit_status.code(),
38+
Some(NextestExitCode::SETUP_ERROR),
39+
"exit code matches"
40+
);
41+
42+
// Print the output.
43+
insta::assert_snapshot!(format!("{insta_prefix}-stderr"), output.stderr_as_str());
44+
45+
Ok(())
46+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) The nextest Contributors
2+
// SPDX-License-Identifier: MIT OR Apache-2.0
3+
4+
use datatest_stable::Utf8Path;
5+
use insta::internals::SettingsBindDropGuard;
6+
7+
/// Binds insta settings for a test, and returns the prefix to use for snapshots.
8+
pub(crate) fn bind_insta_settings<'a>(
9+
path: &'a Utf8Path,
10+
snapshot_path: &str,
11+
) -> (SettingsBindDropGuard, &'a str) {
12+
let mut settings = insta::Settings::clone_current();
13+
// Make insta suitable for datatest-stable use.
14+
settings.set_input_file(path);
15+
settings.set_snapshot_path(snapshot_path);
16+
settings.set_prepend_module_to_snapshot(false);
17+
18+
let guard = settings.bind_to_scope();
19+
let insta_prefix = path.file_name().unwrap();
20+
21+
(guard, insta_prefix)
22+
}

0 commit comments

Comments
 (0)