cargo/tests/testsuite/install_upgrade.rs
Alex Crichton 9115b2c326 Extract support directory to its own crate
Extract out all our test support code to its own standalone crate so it
can be shared between multiple test suites if necessary.
2019-09-16 11:47:09 -07:00

848 lines
28 KiB
Rust

use cargo::core::PackageId;
use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use cargo_test_support::install::{cargo_home, exe};
use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::registry::Package;
use cargo_test_support::{
basic_manifest, cargo_process, cross_compile, execs, git, process, project, Execs,
};
// Helper for publishing a package.
fn pkg(name: &str, vers: &str) {
Package::new(name, vers)
.file(
"src/main.rs",
r#"fn main() { println!("{}", env!("CARGO_PKG_VERSION")) }"#,
)
.publish();
}
fn v1_path() -> PathBuf {
cargo_home().join(".crates.toml")
}
fn v2_path() -> PathBuf {
cargo_home().join(".crates2.json")
}
fn load_crates1() -> toml::Value {
toml::from_str(&fs::read_to_string(v1_path()).unwrap()).unwrap()
}
fn load_crates2() -> serde_json::Value {
serde_json::from_str(&fs::read_to_string(v2_path()).unwrap()).unwrap()
}
fn installed_exe(name: &str) -> PathBuf {
cargo_home().join("bin").join(exe(name))
}
/// Helper for executing binaries installed by cargo.
fn installed_process(name: &str) -> Execs {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
thread_local!(static UNIQUE_ID: usize = NEXT_ID.fetch_add(1, Ordering::SeqCst));
// This copies the executable to a unique name so that it may be safely
// replaced on Windows. See Project::rename_run for details.
let src = installed_exe(name);
let dst = installed_exe(&UNIQUE_ID.with(|my_id| format!("{}-{}", name, my_id)));
// Note: Cannot use copy. On Linux, file descriptors may be left open to
// the executable as other tests in other threads are constantly spawning
// new processes (see https://github.com/rust-lang/cargo/pull/5557 for
// more).
fs::rename(&src, &dst)
.unwrap_or_else(|e| panic!("Failed to rename `{:?}` to `{:?}`: {}", src, dst, e));
// Leave behind a fake file so that reinstall duplicate check works.
fs::write(src, "").unwrap();
let p = process(dst);
execs().with_process_builder(p)
}
/// Check that the given package name/version has the following bins listed in
/// the trackers. Also verifies that both trackers are in sync and valid.
/// Pass in an empty `bins` list to assert that the package is *not* installed.
fn validate_trackers(name: &str, version: &str, bins: &[&str]) {
let v1 = load_crates1();
let v1_table = v1.get("v1").unwrap().as_table().unwrap();
let v2 = load_crates2();
let v2_table = v2["installs"].as_object().unwrap();
assert_eq!(v1_table.len(), v2_table.len());
// Convert `bins` to a BTreeSet.
let bins: BTreeSet<String> = bins
.iter()
.map(|b| format!("{}{}", b, env::consts::EXE_SUFFIX))
.collect();
// Check every entry matches between v1 and v2.
for (pkg_id_str, v1_bins) in v1_table {
let pkg_id: PackageId = toml::Value::from(pkg_id_str.to_string())
.try_into()
.unwrap();
let v1_bins: BTreeSet<String> = v1_bins
.as_array()
.unwrap()
.iter()
.map(|b| b.as_str().unwrap().to_string())
.collect();
if pkg_id.name().as_str() == name && pkg_id.version().to_string() == version {
if bins.is_empty() {
panic!(
"Expected {} to not be installed, but found: {:?}",
name, v1_bins
);
} else {
assert_eq!(bins, v1_bins);
}
}
let pkg_id_value = serde_json::to_value(&pkg_id).unwrap();
let pkg_id_str = pkg_id_value.as_str().unwrap();
let v2_info = v2_table
.get(pkg_id_str)
.expect("v2 missing v1 pkg")
.as_object()
.unwrap();
let v2_bins = v2_info["bins"].as_array().unwrap();
let v2_bins: BTreeSet<String> = v2_bins
.iter()
.map(|b| b.as_str().unwrap().to_string())
.collect();
assert_eq!(v1_bins, v2_bins);
}
}
#[cargo_test]
fn registry_upgrade() {
// Installing and upgrading from a registry.
pkg("foo", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.0.0 (registry [..])
[INSTALLING] foo v1.0.0
[COMPILING] foo v1.0.0
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`)
[WARNING] be sure to add [..]
",
)
.run();
installed_process("foo").with_stdout("1.0.0").run();
validate_trackers("foo", "1.0.0", &["foo"]);
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[IGNORED] package `foo v1.0.0` is already installed[..]
[WARNING] be sure to add [..]
",
)
.run();
pkg("foo", "1.0.1");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.0.1 (registry [..])
[INSTALLING] foo v1.0.1
[COMPILING] foo v1.0.1
[FINISHED] release [optimized] target(s) in [..]
[REPLACING] [CWD]/home/.cargo/bin/foo[EXE]
[REPLACED] package `foo v1.0.0` with `foo v1.0.1` (executable `foo[EXE]`)
[WARNING] be sure to add [..]
",
)
.run();
installed_process("foo").with_stdout("1.0.1").run();
validate_trackers("foo", "1.0.1", &["foo"]);
cargo_process("install foo --version=1.0.0 -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[COMPILING] foo v1.0.0")
.run();
installed_process("foo").with_stdout("1.0.0").run();
validate_trackers("foo", "1.0.0", &["foo"]);
cargo_process("install foo --version=^1.0 -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[COMPILING] foo v1.0.1")
.run();
installed_process("foo").with_stdout("1.0.1").run();
validate_trackers("foo", "1.0.1", &["foo"]);
cargo_process("install foo --version=^1.0 -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[IGNORED] package `foo v1.0.1` is already installed[..]")
.run();
}
#[cargo_test]
fn uninstall() {
// Basic uninstall test.
pkg("foo", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
cargo_process("uninstall foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
let data = load_crates2();
assert_eq!(data["installs"].as_object().unwrap().len(), 0);
let v1_table = load_crates1();
assert_eq!(v1_table.get("v1").unwrap().as_table().unwrap().len(), 0);
}
#[cargo_test]
fn upgrade_force() {
pkg("foo", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
cargo_process("install foo -Z install-upgrade --force")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[INSTALLING] foo v1.0.0
[COMPILING] foo v1.0.0
[FINISHED] release [optimized] target(s) in [..]
[REPLACING] [..]/.cargo/bin/foo[EXE]
[REPLACED] package `foo v1.0.0` with `foo v1.0.0` (executable `foo[EXE]`)
[WARNING] be sure to add `[..]/.cargo/bin` to your PATH [..]
",
)
.run();
validate_trackers("foo", "1.0.0", &["foo"]);
}
#[cargo_test]
fn ambiguous_version_no_longer_allowed() {
// Non-semver-requirement is not allowed for `--version`.
pkg("foo", "1.0.0");
cargo_process("install foo --version=1.0 -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[ERROR] the `--vers` provided, `1.0`, is not a valid semver version: cannot parse '1.0' as a semver
if you want to specify semver range, add an explicit qualifier, like ^1.0
",
)
.with_status(101)
.run();
}
#[cargo_test]
fn path_is_always_dirty() {
// --path should always reinstall.
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("install --path . -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
p.cargo("install --path . -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[REPLACING] [..]/foo[EXE]")
.run();
}
#[cargo_test]
fn fails_for_conflicts_unknown() {
// If an untracked file is in the way, it should fail.
pkg("foo", "1.0.0");
let exe = installed_exe("foo");
exe.parent().unwrap().mkdir_p();
fs::write(exe, "").unwrap();
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[ERROR] binary `foo[EXE]` already exists in destination")
.with_status(101)
.run();
}
#[cargo_test]
fn fails_for_conflicts_known() {
// If the same binary exists in another package, it should fail.
pkg("foo", "1.0.0");
Package::new("bar", "1.0.0")
.file("src/bin/foo.rs", "fn main() {}")
.publish();
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
cargo_process("install bar -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains(
"[ERROR] binary `foo[EXE]` already exists in destination as part of `foo v1.0.0`",
)
.with_status(101)
.run();
}
#[cargo_test]
fn supports_multiple_binary_names() {
// Can individually install with --bin or --example
Package::new("foo", "1.0.0")
.file("src/main.rs", r#"fn main() { println!("foo"); }"#)
.file("src/bin/a.rs", r#"fn main() { println!("a"); }"#)
.file("examples/ex1.rs", r#"fn main() { println!("ex1"); }"#)
.publish();
cargo_process("install foo -Z install-upgrade --bin foo")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("foo").run();
assert!(!installed_exe("a").exists());
assert!(!installed_exe("ex1").exists());
validate_trackers("foo", "1.0.0", &["foo"]);
cargo_process("install foo -Z install-upgrade --bin a")
.masquerade_as_nightly_cargo()
.run();
installed_process("a").with_stdout("a").run();
assert!(!installed_exe("ex1").exists());
validate_trackers("foo", "1.0.0", &["a", "foo"]);
cargo_process("install foo -Z install-upgrade --example ex1")
.masquerade_as_nightly_cargo()
.run();
installed_process("ex1").with_stdout("ex1").run();
validate_trackers("foo", "1.0.0", &["a", "ex1", "foo"]);
cargo_process("uninstall foo -Z install-upgrade --bin foo")
.masquerade_as_nightly_cargo()
.run();
assert!(!installed_exe("foo").exists());
assert!(installed_exe("ex1").exists());
validate_trackers("foo", "1.0.0", &["a", "ex1"]);
cargo_process("uninstall foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
assert!(!installed_exe("ex1").exists());
assert!(!installed_exe("a").exists());
}
#[cargo_test]
fn v1_already_installed_fresh() {
// Install with v1, then try to install again with v2.
pkg("foo", "1.0.0");
cargo_process("install foo").run();
cargo_process("install foo -Z install-upgrade")
.with_stderr_contains("[IGNORED] package `foo v1.0.0` is already installed[..]")
.masquerade_as_nightly_cargo()
.run();
}
#[cargo_test]
fn v1_already_installed_dirty() {
// Install with v1, then install a new version with v2.
pkg("foo", "1.0.0");
cargo_process("install foo").run();
pkg("foo", "1.0.1");
cargo_process("install foo -Z install-upgrade")
.with_stderr_contains("[COMPILING] foo v1.0.1")
.with_stderr_contains("[REPLACING] [..]/foo[EXE]")
.masquerade_as_nightly_cargo()
.run();
validate_trackers("foo", "1.0.1", &["foo"]);
}
#[cargo_test]
fn change_features_rebuilds() {
Package::new("foo", "1.0.0")
.file(
"src/main.rs",
r#"fn main() {
if cfg!(feature = "f1") {
println!("f1");
}
if cfg!(feature = "f2") {
println!("f2");
}
}"#,
)
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.0.0"
[features]
f1 = []
f2 = []
default = ["f1"]
"#,
)
.publish();
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("f1").run();
cargo_process("install foo -Z install-upgrade --no-default-features")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("").run();
cargo_process("install foo -Z install-upgrade --all-features")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("f1\nf2").run();
cargo_process("install foo -Z install-upgrade --no-default-features --features=f1")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("f1").run();
}
#[cargo_test]
fn change_profile_rebuilds() {
pkg("foo", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
cargo_process("install foo -Z install-upgrade --debug")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[COMPILING] foo v1.0.0")
.with_stderr_contains("[REPLACING] [..]foo[EXE]")
.run();
cargo_process("install foo -Z install-upgrade --debug")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[IGNORED] package `foo v1.0.0` is already installed[..]")
.run();
}
#[cargo_test]
fn change_target_rebuilds() {
if cross_compile::disabled() {
return;
}
pkg("foo", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
let target = cross_compile::alternate();
cargo_process("install foo -v -Z install-upgrade --target")
.arg(&target)
.masquerade_as_nightly_cargo()
.with_stderr_contains("[COMPILING] foo v1.0.0")
.with_stderr_contains("[REPLACING] [..]foo[EXE]")
.with_stderr_contains(&format!("[..]--target {}[..]", target))
.run();
}
#[cargo_test]
fn change_bin_sets_rebuilds() {
// Changing which bins in a multi-bin project should reinstall.
Package::new("foo", "1.0.0")
.file("src/main.rs", "fn main() { }")
.file("src/bin/x.rs", "fn main() { }")
.file("src/bin/y.rs", "fn main() { }")
.publish();
cargo_process("install foo -Z install-upgrade --bin x")
.masquerade_as_nightly_cargo()
.run();
assert!(installed_exe("x").exists());
assert!(!installed_exe("y").exists());
assert!(!installed_exe("foo").exists());
validate_trackers("foo", "1.0.0", &["x"]);
cargo_process("install foo -Z install-upgrade --bin y")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[INSTALLED] package `foo v1.0.0` (executable `y[EXE]`)")
.run();
assert!(installed_exe("x").exists());
assert!(installed_exe("y").exists());
assert!(!installed_exe("foo").exists());
validate_trackers("foo", "1.0.0", &["x", "y"]);
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`)")
.with_stderr_contains(
"[REPLACED] package `foo v1.0.0` with `foo v1.0.0` (executables `x[EXE]`, `y[EXE]`)",
)
.run();
assert!(installed_exe("x").exists());
assert!(installed_exe("y").exists());
assert!(installed_exe("foo").exists());
validate_trackers("foo", "1.0.0", &["foo", "x", "y"]);
}
#[cargo_test]
fn forwards_compatible() {
// Unknown fields should be preserved.
pkg("foo", "1.0.0");
pkg("bar", "1.0.0");
cargo_process("install foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
let key = "foo 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)";
let v2 = cargo_home().join(".crates2.json");
let mut data = load_crates2();
data["newfield"] = serde_json::Value::Bool(true);
data["installs"][key]["moreinfo"] = serde_json::Value::String("shazam".to_string());
fs::write(&v2, serde_json::to_string(&data).unwrap()).unwrap();
cargo_process("install bar -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
let data: serde_json::Value = serde_json::from_str(&fs::read_to_string(&v2).unwrap()).unwrap();
assert_eq!(data["newfield"].as_bool().unwrap(), true);
assert_eq!(
data["installs"][key]["moreinfo"].as_str().unwrap(),
"shazam"
);
}
#[cargo_test]
fn v2_syncs() {
// V2 inherits the installs from V1.
pkg("one", "1.0.0");
pkg("two", "1.0.0");
pkg("three", "1.0.0");
let p = project()
.file("src/bin/x.rs", "fn main() {}")
.file("src/bin/y.rs", "fn main() {}")
.build();
cargo_process("install one -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
validate_trackers("one", "1.0.0", &["one"]);
p.cargo("install -Z install-upgrade --path .")
.masquerade_as_nightly_cargo()
.run();
validate_trackers("foo", "1.0.0", &["x", "y"]);
// v1 add/remove
cargo_process("install two").run();
cargo_process("uninstall one").run();
// This should pick up that `two` was added, `one` was removed.
cargo_process("install three -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
validate_trackers("three", "1.0.0", &["three"]);
cargo_process("install --list")
.with_stdout(
"\
foo v0.0.1 ([..]/foo):
x[EXE]
y[EXE]
three v1.0.0:
three[EXE]
two v1.0.0:
two[EXE]
",
)
.run();
cargo_process("install one -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
installed_process("one").with_stdout("1.0.0").run();
validate_trackers("one", "1.0.0", &["one"]);
cargo_process("install two -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains("[IGNORED] package `two v1.0.0` is already installed[..]")
.run();
// v1 remove
p.cargo("uninstall --bin x").run();
pkg("x", "1.0.0");
pkg("y", "1.0.0");
// This should succeed because `x` was removed in V1.
cargo_process("install x -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
validate_trackers("x", "1.0.0", &["x"]);
// This should fail because `y` still exists in a different package.
cargo_process("install y -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr_contains(
"[ERROR] binary `y[EXE]` already exists in destination \
as part of `foo v0.0.1 ([..])`",
)
.with_status(101)
.run();
}
#[cargo_test]
fn upgrade_git() {
let git_project = git::new("foo", |project| project.file("src/main.rs", "fn main() {}"));
// install
cargo_process("install -Z install-upgrade --git")
.arg(git_project.url().to_string())
.masquerade_as_nightly_cargo()
.run();
// Check install stays fresh.
cargo_process("install -Z install-upgrade --git")
.arg(git_project.url().to_string())
.masquerade_as_nightly_cargo()
.with_stderr_contains(
"[IGNORED] package `foo v0.0.1 (file://[..]/foo#[..])` is \
already installed,[..]",
)
.run();
// Modify a file.
let repo = git2::Repository::open(git_project.root()).unwrap();
git_project.change_file("src/main.rs", r#"fn main() {println!("onomatopoeia");}"#);
git::add(&repo);
git::commit(&repo);
// Install should reinstall.
cargo_process("install -Z install-upgrade --git")
.arg(git_project.url().to_string())
.masquerade_as_nightly_cargo()
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
.with_stderr_contains("[REPLACING] [..]/foo[EXE]")
.run();
installed_process("foo").with_stdout("onomatopoeia").run();
// Check install stays fresh.
cargo_process("install -Z install-upgrade --git")
.arg(git_project.url().to_string())
.masquerade_as_nightly_cargo()
.with_stderr_contains(
"[IGNORED] package `foo v0.0.1 (file://[..]/foo#[..])` is \
already installed,[..]",
)
.run();
}
#[cargo_test]
fn switch_sources() {
// Installing what appears to be the same thing, but from different
// sources should reinstall.
pkg("foo", "1.0.0");
Package::new("foo", "1.0.0")
.file("src/main.rs", r#"fn main() { println!("alt"); }"#)
.alternative(true)
.publish();
let p = project()
.at("foo-local") // so it doesn't use the same directory as the git project
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", r#"fn main() { println!("local"); }"#)
.build();
let git_project = git::new("foo", |project| {
project.file("src/main.rs", r#"fn main() { println!("git"); }"#)
});
cargo_process("install -Z install-upgrade foo")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("1.0.0").run();
cargo_process("install -Z install-upgrade foo --registry alternative")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("alt").run();
p.cargo("install -Z install-upgrade --path .")
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("local").run();
cargo_process("install -Z install-upgrade --git")
.arg(git_project.url().to_string())
.masquerade_as_nightly_cargo()
.run();
installed_process("foo").with_stdout("git").run();
}
#[cargo_test]
fn multiple_report() {
// Testing the full output that indicates installed/ignored/replaced/summary.
pkg("one", "1.0.0");
pkg("two", "1.0.0");
fn three(vers: &str) {
Package::new("three", vers)
.file("src/main.rs", "fn main() { }")
.file("src/bin/x.rs", "fn main() { }")
.file("src/bin/y.rs", "fn main() { }")
.publish();
}
three("1.0.0");
cargo_process("install -Z install-upgrade one two three")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[DOWNLOADING] crates ...
[DOWNLOADED] one v1.0.0 (registry `[..]`)
[INSTALLING] one v1.0.0
[COMPILING] one v1.0.0
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]/.cargo/bin/one[EXE]
[INSTALLED] package `one v1.0.0` (executable `one[EXE]`)
[DOWNLOADING] crates ...
[DOWNLOADED] two v1.0.0 (registry `[..]`)
[INSTALLING] two v1.0.0
[COMPILING] two v1.0.0
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]/.cargo/bin/two[EXE]
[INSTALLED] package `two v1.0.0` (executable `two[EXE]`)
[DOWNLOADING] crates ...
[DOWNLOADED] three v1.0.0 (registry `[..]`)
[INSTALLING] three v1.0.0
[COMPILING] three v1.0.0
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]/.cargo/bin/three[EXE]
[INSTALLING] [..]/.cargo/bin/x[EXE]
[INSTALLING] [..]/.cargo/bin/y[EXE]
[INSTALLED] package `three v1.0.0` (executables `three[EXE]`, `x[EXE]`, `y[EXE]`)
[SUMMARY] Successfully installed one, two, three!
[WARNING] be sure to add `[..]/.cargo/bin` to your PATH [..]
",
)
.run();
pkg("foo", "1.0.1");
pkg("bar", "1.0.1");
three("1.0.1");
cargo_process("install -Z install-upgrade one two three")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[IGNORED] package `one v1.0.0` is already installed, use --force to override
[IGNORED] package `two v1.0.0` is already installed, use --force to override
[DOWNLOADING] crates ...
[DOWNLOADED] three v1.0.1 (registry `[..]`)
[INSTALLING] three v1.0.1
[COMPILING] three v1.0.1
[FINISHED] release [optimized] target(s) in [..]
[REPLACING] [..]/.cargo/bin/three[EXE]
[REPLACING] [..]/.cargo/bin/x[EXE]
[REPLACING] [..]/.cargo/bin/y[EXE]
[REPLACED] package `three v1.0.0` with `three v1.0.1` (executables `three[EXE]`, `x[EXE]`, `y[EXE]`)
[SUMMARY] Successfully installed one, two, three!
[WARNING] be sure to add `[..]/.cargo/bin` to your PATH [..]
",
)
.run();
cargo_process("uninstall -Z install-upgrade three")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[REMOVING] [..]/.cargo/bin/three[EXE]
[REMOVING] [..]/.cargo/bin/x[EXE]
[REMOVING] [..]/.cargo/bin/y[EXE]
",
)
.run();
cargo_process("install -Z install-upgrade three --bin x")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[INSTALLING] three v1.0.1
[COMPILING] three v1.0.1
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]/.cargo/bin/x[EXE]
[INSTALLED] package `three v1.0.1` (executable `x[EXE]`)
[WARNING] be sure to add `[..]/.cargo/bin` to your PATH [..]
",
)
.run();
cargo_process("install -Z install-upgrade three")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[INSTALLING] three v1.0.1
[COMPILING] three v1.0.1
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]/.cargo/bin/three[EXE]
[INSTALLING] [..]/.cargo/bin/y[EXE]
[REPLACING] [..]/.cargo/bin/x[EXE]
[INSTALLED] package `three v1.0.1` (executables `three[EXE]`, `y[EXE]`)
[REPLACED] package `three v1.0.1` with `three v1.0.1` (executable `x[EXE]`)
[WARNING] be sure to add `[..]/.cargo/bin` to your PATH [..]
",
)
.run();
}
#[cargo_test]
fn no_track_gated() {
cargo_process("install --no-track foo")
.masquerade_as_nightly_cargo()
.with_stderr(
"[ERROR] `--no-track` flag is unstable, pass `-Z install-upgrade` to enable it",
)
.with_status(101)
.run();
}
#[cargo_test]
fn no_track() {
pkg("foo", "1.0.0");
cargo_process("install --no-track foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.run();
assert!(!v1_path().exists());
assert!(!v2_path().exists());
cargo_process("install --no-track foo -Z install-upgrade")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[UPDATING] `[..]` index
[ERROR] binary `foo[EXE]` already exists in destination
Add --force to overwrite
",
)
.with_status(101)
.run();
}
#[cargo_test]
fn deletes_orphaned() {
// When an executable is removed from a project, upgrading should remove it.
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
"#,
)
.file("src/main.rs", "fn main() {}")
.file("src/bin/other.rs", "fn main() {}")
.file("examples/ex1.rs", "fn main() {}")
.build();
p.cargo("install -Z install-upgrade --path . --bins --examples")
.masquerade_as_nightly_cargo()
.run();
assert!(installed_exe("other").exists());
// Remove a binary, add a new one, and bump the version.
fs::remove_file(p.root().join("src/bin/other.rs")).unwrap();
p.change_file("examples/ex2.rs", "fn main() {}");
p.change_file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.2.0"
"#,
);
p.cargo("install -Z install-upgrade --path . --bins --examples")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[INSTALLING] foo v0.2.0 [..]
[COMPILING] foo v0.2.0 [..]
[FINISHED] release [..]
[INSTALLING] [..]/.cargo/bin/ex2[EXE]
[REPLACING] [..]/.cargo/bin/ex1[EXE]
[REPLACING] [..]/.cargo/bin/foo[EXE]
[REMOVING] executable `[..]/.cargo/bin/other[EXE]` from previous version foo v0.1.0 [..]
[INSTALLED] package `foo v0.2.0 [..]` (executable `ex2[EXE]`)
[REPLACED] package `foo v0.1.0 [..]` with `foo v0.2.0 [..]` (executables `ex1[EXE]`, `foo[EXE]`)
[WARNING] be sure to add [..]
",
)
.run();
assert!(!installed_exe("other").exists());
validate_trackers("foo", "0.2.0", &["foo", "ex1", "ex2"]);
// 0.1.0 should not have any entries.
validate_trackers("foo", "0.1.0", &[]);
}