cargo-outdated
cargo-outdated copied to clipboard
Error running in project with custom target file
Problem
cargo outdated fails to run when a project specifies a custom target file:
error: target path "/tmp/cargo-outdated2acTI1/x86_64-custom.json" is not a valid file
Caused by:
No such file or directory (os error 2)
I assume that the custom target file is not copied over to the temporary copy of the project,
so cargo cannot find it and fails to run.
Reproduction
Here's a script to reproduce a MWE:
#!/bin/env bash
# repro.sh
set -e
PROJECT=$1
echo ":: Creating new project $PROJECT"
cargo new $PROJECT
cd $PROJECT
mkdir .cargo
TARGET="x86_64-custom.json"
echo ":: Creating custom target .json"
rustc +nightly -Z unstable-options \
--print target-spec-json \
--target x86_64-unknown-linux-gnu \
| jq 'del(.["is-builtin"])' \
| tee $TARGET \
| jq
echo ":: Creating Cargo config file:"
tee .cargo/config.toml <<EOF
[build]
target = "$TARGET"
EOF
echo ":: Trying to run cargo outdated:"
cargo outdated
The first argument is the name of the project directory:
$ bash repro.sh $(mktemp -u mwe-XXXX)
Fix
There might be two ways to solve this problem:
- also copy over the custom target
.json - delete
build.targetfrom.cargo/config{,.toml}
I tried my hands at a (crude) implementation of 2., that seems to work:
diff --git a/src/cargo_ops/temp_project.rs b/src/cargo_ops/temp_project.rs
index 695d56b..1dc16f0 100644
--- a/src/cargo_ops/temp_project.rs
+++ b/src/cargo_ops/temp_project.rs
@@ -129,26 +129,46 @@ impl<'tmp> TempProject<'tmp> {
}
}
+ let copy_cargo_config = |name: &str| -> CargoResult<()> {
+ let config_path = workspace_root.join(".cargo").join(name);
+ if config_path.is_file() {
+ let mut config: ::toml::Value = {
+ let mut buf = String::new();
+ let mut file = File::open(&config_path)?;
+ file.read_to_string(&mut buf)?;
+ ::toml::from_str(&buf)?
+ };
+
+ if let Some(::toml::Value::Table(build)) = config.get_mut("build") {
+ let _ = build.remove("target");
+ }
+
+ fs::create_dir_all(temp_dir.path().join(".cargo"))?;
+
+ let dest = temp_dir.path().join(".cargo").join(name);
+
+ let config_serialized = ::toml::to_string(&config)
+ .expect("Cannot format cargo config file as toml file");
+ let mut config_toml = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(&dest)?;
+ write!(config_toml, "{}", config_serialized)?;
+ }
+
+ Ok(())
+ };
+
//.cargo/config.toml
// this is the preferred way
// https://doc.rust-lang.org/cargo/reference/config.html
- if workspace_root.join(".cargo/config.toml").is_file() {
- fs::create_dir_all(temp_dir.path().join(".cargo"))?;
- fs::copy(
- &workspace_root.join(".cargo/config.toml"),
- temp_dir.path().join(".cargo/config.toml"),
- )?;
- }
+ copy_cargo_config("config.toml")?;
//.cargo/config
// this is legacy support for config files without the `.toml` extension
- if workspace_root.join(".cargo/config").is_file() {
- fs::create_dir_all(temp_dir.path().join(".cargo"))?;
- fs::copy(
- &workspace_root.join(".cargo/config"),
- temp_dir.path().join(".cargo/config"),
- )?;
- }
+ copy_cargo_config("config")?;
let relative_manifest = String::from(&orig_manifest[workspace_root_str.len() + 1..]);
let config = Self::generate_config(temp_dir.path(), &relative_manifest, options)?;