cargo/tests/testsuite/install.rs

1014 lines
29 KiB
Rust
Raw Normal View History

use cargotest;
use std::fs::{self, File, OpenOptions};
use std::io::prelude::*;
use cargo::util::ProcessBuilder;
use cargotest::install::{cargo_home, has_installed_exe};
use cargotest::support::git;
use cargotest::support::paths;
use cargotest::support::registry::Package;
use cargotest::support::{project, execs};
use hamcrest::{assert_that, existing_dir, is_not};
fn cargo_process(s: &str) -> ProcessBuilder {
let mut p = cargotest::cargo_process();
p.arg(s);
2017-02-18 12:01:10 +00:00
p
}
fn pkg(name: &str, vers: &str) {
Package::new(name, vers)
.file("src/lib.rs", "")
.file("src/main.rs", &format!("
extern crate {};
fn main() {{}}
", name))
2016-07-05 17:28:51 +00:00
.publish();
}
#[test]
fn simple() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("foo"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-10 23:52:02 +00:00
[UPDATING] registry `[..]`
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[DOWNLOADING] foo v0.0.1 (registry [..])
[INSTALLING] foo v0.0.1
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] foo v0.0.1
[FINISHED] release [optimized] target(s) in [..]
2016-05-10 23:52:02 +00:00
[INSTALLING] {home}[..]bin[..]foo[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_process("uninstall").arg("foo"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-10 23:52:02 +00:00
[REMOVING] {home}[..]bin[..]foo[..]
",
home = cargo_home().display())));
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
}
#[test]
2017-06-23 23:30:05 +00:00
fn multiple_pkgs() {
pkg("foo", "0.0.1");
2017-07-12 20:28:33 +00:00
pkg("bar", "0.0.2");
2017-07-12 20:28:33 +00:00
assert_that(cargo_process("install").args(&["foo", "bar", "baz"]),
execs().with_status(101).with_stderr(&format!("\
2017-06-23 23:30:05 +00:00
[UPDATING] registry `[..]`
2017-10-04 22:07:01 +00:00
[DOWNLOADING] foo v0.0.1 (registry `file://[..]`)
2017-06-23 23:30:05 +00:00
[INSTALLING] foo v0.0.1
[COMPILING] foo v0.0.1
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo[..]
2017-10-04 22:07:01 +00:00
[DOWNLOADING] bar v0.0.2 (registry `file://[..]`)
2017-07-12 20:28:33 +00:00
[INSTALLING] bar v0.0.2
[COMPILING] bar v0.0.2
2017-06-23 23:30:05 +00:00
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]bar[..]
2017-10-04 22:07:01 +00:00
error: could not find `baz` in registry `[..]`
[SUMMARY] Successfully installed foo, bar! Failed to install baz (see error(s) above).
2017-07-12 18:57:47 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
error: some crates failed to install
",
home = cargo_home().display())));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_home(), has_installed_exe("bar"));
assert_that(cargo_process("uninstall").args(&["foo", "bar"]),
2017-06-23 23:30:05 +00:00
execs().with_status(0).with_stderr(&format!("\
[REMOVING] {home}[..]bin[..]foo[..]
[REMOVING] {home}[..]bin[..]bar[..]
[SUMMARY] Successfully uninstalled foo, bar!
",
home = cargo_home().display())));
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
assert_that(cargo_home(), is_not(has_installed_exe("bar")));
2017-06-23 23:30:05 +00:00
}
2017-06-23 23:30:05 +00:00
#[test]
fn pick_max_version() {
pkg("foo", "0.0.1");
pkg("foo", "0.0.2");
assert_that(cargo_process("install").arg("foo"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `[..]`
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[DOWNLOADING] foo v0.0.2 (registry [..])
[INSTALLING] foo v0.0.2
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] foo v0.0.2
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn missing() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("bar"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
2016-05-15 22:16:54 +00:00
[UPDATING] registry [..]
2017-10-04 22:07:01 +00:00
[ERROR] could not find `bar` in registry `[..]`
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn bad_version() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("foo").arg("--vers=0.2.0"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
2016-05-15 22:16:54 +00:00
[UPDATING] registry [..]
2017-10-04 22:07:01 +00:00
[ERROR] could not find `foo` in registry `[..]` with version `=0.2.0`
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn no_crate() {
assert_that(cargo_process("install"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] `[..]` is not a crate root; specify a crate to install [..]
Caused by:
failed to read `[..]Cargo.toml`
Caused by:
[..] (os error [..])
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn install_location_precedence() {
pkg("foo", "0.0.1");
let root = paths::root();
let t1 = root.join("t1");
let t2 = root.join("t2");
let t3 = root.join("t3");
let t4 = cargo_home();
fs::create_dir(root.join(".cargo")).unwrap();
File::create(root.join(".cargo/config")).unwrap().write_all(format!("\
[install]
root = '{}'
", t3.display()).as_bytes()).unwrap();
println!("install --root");
assert_that(cargo_process("install").arg("foo")
.arg("--root").arg(&t1)
.env("CARGO_INSTALL_ROOT", &t2),
execs().with_status(0));
assert_that(&t1, has_installed_exe("foo"));
assert_that(&t2, is_not(has_installed_exe("foo")));
println!("install CARGO_INSTALL_ROOT");
assert_that(cargo_process("install").arg("foo")
.env("CARGO_INSTALL_ROOT", &t2),
execs().with_status(0));
assert_that(&t2, has_installed_exe("foo"));
assert_that(&t3, is_not(has_installed_exe("foo")));
println!("install install.root");
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(&t3, has_installed_exe("foo"));
assert_that(&t4, is_not(has_installed_exe("foo")));
fs::remove_file(root.join(".cargo/config")).unwrap();
println!("install cargo home");
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(&t4, has_installed_exe("foo"));
}
#[test]
fn install_path() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_process("install").arg("--path").arg(".").cwd(p.root()),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[INSTALLING] foo v0.1.0 [..]
[ERROR] binary `foo[..]` already exists in destination as part of `foo v0.1.0 [..]`
Add --force to overwrite
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn multiple_crates_error() {
let p = git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.file("a/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("a/src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--git").arg(p.url().to_string()),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
2016-05-15 22:16:54 +00:00
[UPDATING] git repository [..]
[ERROR] multiple packages with binaries found: bar, foo
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn multiple_crates_select() {
let p = git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.file("a/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("a/src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--git").arg(p.url().to_string())
.arg("foo"),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_home(), is_not(has_installed_exe("bar")));
assert_that(cargo_process("install").arg("--git").arg(p.url().to_string())
.arg("bar"),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("bar"));
}
#[test]
fn multiple_crates_auto_binaries() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "a" }
"#)
.file("src/main.rs", "extern crate bar; fn main() {}")
.file("a/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("a/src/lib.rs", "")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn multiple_crates_auto_examples() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "a" }
"#)
.file("src/lib.rs", "extern crate bar;")
.file("examples/foo.rs", "
extern crate bar;
extern crate foo;
fn main() {}
")
.file("a/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("a/src/lib.rs", "")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root())
.arg("--example=foo"),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn no_binaries_or_examples() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "a" }
"#)
.file("src/lib.rs", "")
.file("a/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("a/src/lib.rs", "")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no packages found with binaries or examples
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn no_binaries() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "")
.file("examples/foo.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()).arg("foo"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[INSTALLING] foo [..]
[ERROR] specified package has no binaries
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn examples() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "")
.file("examples/foo.rs", "extern crate foo; fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root())
.arg("--example=foo"),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn install_twice() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/bin/foo-bin1.rs", "fn main() {}")
.file("src/bin/foo-bin2.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
assert_that(cargo_process("install").arg("--path").arg(p.root()),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[INSTALLING] foo v0.1.0 [..]
[ERROR] binary `foo-bin1[..]` already exists in destination as part of `foo v0.1.0 ([..])`
binary `foo-bin2[..]` already exists in destination as part of `foo v0.1.0 ([..])`
Add --force to overwrite
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn install_force() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
let p = project("foo2")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--force").arg("--path").arg(p.root()),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
[REPLACING] {home}[..]bin[..]foo[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
foo v0.2.0 ([..]):
foo[..]
"));
}
#[test]
fn install_force_partial_overlap() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/bin/foo-bin1.rs", "fn main() {}")
.file("src/bin/foo-bin2.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
let p = project("foo2")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#)
.file("src/bin/foo-bin2.rs", "fn main() {}")
.file("src/bin/foo-bin3.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--force").arg("--path").arg(p.root()),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo-bin3[..]
[REPLACING] {home}[..]bin[..]foo-bin2[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
foo v0.1.0 ([..]):
foo-bin1[..]
foo v0.2.0 ([..]):
foo-bin2[..]
foo-bin3[..]
"));
}
#[test]
fn install_force_bin() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/bin/foo-bin1.rs", "fn main() {}")
.file("src/bin/foo-bin2.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
let p = project("foo2")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#)
.file("src/bin/foo-bin1.rs", "fn main() {}")
.file("src/bin/foo-bin2.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--force")
.arg("--bin")
.arg("foo-bin2")
.arg("--path")
.arg(p.root()),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
[REPLACING] {home}[..]bin[..]foo-bin2[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
foo v0.1.0 ([..]):
foo-bin1[..]
foo v0.2.0 ([..]):
foo-bin2[..]
"));
}
#[test]
fn compile_failure() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(101).with_stderr_contains("\
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[ERROR] failed to compile `foo v0.1.0 ([..])`, intermediate artifacts can be \
found at `[..]target`
Caused by:
Could not compile `foo`.
To learn more, run the command again with --verbose.
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn git_repo() {
let p = git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
// use `--locked` to test that we don't even try to write a lockfile
assert_that(cargo_process("install").arg("--locked").arg("--git").arg(p.url().to_string()),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[UPDATING] git repository `[..]`
[INSTALLING] foo v0.1.0 ([..])
[COMPILING] foo v0.1.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo[..]
2016-05-15 22:16:54 +00:00
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn list() {
pkg("foo", "0.0.1");
pkg("bar", "0.2.1");
pkg("bar", "0.2.2");
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout(""));
assert_that(cargo_process("install").arg("bar").arg("--vers").arg("=0.2.1"),
execs().with_status(0));
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
bar v0.2.1:
bar[..]
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
foo v0.0.1:
foo[..]
"));
}
#[test]
fn list_error() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
foo v0.0.1:
foo[..]
"));
let mut worldfile_path = cargo_home();
worldfile_path.push(".crates.toml");
let mut worldfile = OpenOptions::new()
.write(true)
.open(worldfile_path)
.expect(".crates.toml should be there");
worldfile.write_all(b"\x00").unwrap();
drop(worldfile);
assert_that(cargo_process("install").arg("--list").arg("--verbose"),
execs().with_status(101).with_stderr("\
[ERROR] failed to parse crate metadata at `[..]`
Caused by:
invalid TOML found for metadata
Caused by:
unexpected character[..]
"));
}
#[test]
fn uninstall_pkg_does_not_exist() {
assert_that(cargo_process("uninstall").arg("foo"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] package id specification `foo` matched no packages
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn uninstall_bin_does_not_exist() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(cargo_process("uninstall").arg("foo").arg("--bin=bar"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[ERROR] binary `bar[..]` not installed as part of `foo v0.0.1`
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn uninstall_piecemeal() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/bin/foo.rs", "fn main() {}")
.file("src/bin/bar.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_home(), has_installed_exe("bar"));
assert_that(cargo_process("uninstall").arg("foo").arg("--bin=bar"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[REMOVING] [..]bar[..]
"));
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_home(), is_not(has_installed_exe("bar")));
assert_that(cargo_process("uninstall").arg("foo").arg("--bin=foo"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[REMOVING] [..]foo[..]
"));
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
assert_that(cargo_process("uninstall").arg("foo"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] package id specification `foo` matched no packages
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn subcommand_works_out_of_the_box() {
Package::new("cargo-foo", "1.0.0")
.file("src/main.rs", r#"
fn main() {
println!("bar");
}
"#)
.publish();
assert_that(cargo_process("install").arg("cargo-foo"),
execs().with_status(0));
assert_that(cargo_process("foo"),
execs().with_status(0).with_stdout("bar\n"));
assert_that(cargo_process("--list"),
execs().with_status(0).with_stdout_contains(" foo\n"));
}
#[test]
fn installs_from_cwd_by_default() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").cwd(p.root()),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn do_not_rebuilds_on_local_install() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(p.cargo("build").arg("--release"),
execs().with_status(0));
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr("[INSTALLING] [..]
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
"));
assert!(p.build_dir().exists());
assert!(p.release_bin("foo").exists());
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn reports_unsuccessful_subcommand_result() {
Package::new("cargo-fail", "1.0.0")
.file("src/main.rs", r#"
fn main() {
panic!();
}
"#)
.publish();
assert_that(cargo_process("install").arg("cargo-fail"),
execs().with_status(0));
assert_that(cargo_process("--list"),
execs().with_status(0).with_stdout_contains(" fail\n"));
assert_that(cargo_process("fail"),
execs().with_status(101).with_stderr_contains("\
thread '[..]' panicked at 'explicit panic', [..]
"));
}
#[test]
fn git_with_lockfile() {
let p = git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "bar" }
"#)
.file("src/main.rs", "fn main() {}")
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("bar/src/lib.rs", "fn main() {}")
.file("Cargo.lock", r#"
[[package]]
name = "foo"
version = "0.1.0"
dependencies = [ "bar 0.1.0" ]
[[package]]
name = "bar"
version = "0.1.0"
"#)
.build();
assert_that(cargo_process("install").arg("--git").arg(p.url().to_string()),
execs().with_status(0));
}
#[test]
fn q_silences_warnings() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install").arg("-q").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr(""));
}
2016-04-23 03:33:58 +00:00
#[test]
fn readonly_dir() {
2016-04-23 03:33:58 +00:00
pkg("foo", "0.0.1");
let root = paths::root();
let dir = &root.join("readonly");
fs::create_dir(root.join("readonly")).unwrap();
let mut perms = fs::metadata(dir).unwrap().permissions();
perms.set_readonly(true);
fs::set_permissions(dir, perms).unwrap();
assert_that(cargo_process("install").arg("foo").cwd(dir),
execs().with_status(0));
assert_that(cargo_home(), has_installed_exe("foo"));
}
#[test]
fn use_path_workspace() {
Package::new("foo", "1.0.0").publish();
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
[workspace]
members = ["baz"]
"#)
.file("src/main.rs", "fn main() {}")
.file("baz/Cargo.toml", r#"
[package]
name = "baz"
version = "0.1.0"
authors = []
[dependencies]
foo = "1"
"#)
.file("baz/src/lib.rs", "")
.build();
assert_that(p.cargo("build"), execs().with_status(0));
let lock = p.read_lockfile();
assert_that(p.cargo("install"), execs().with_status(0));
let lock2 = p.read_lockfile();
assert_eq!(lock, lock2, "different lockfiles");
}
#[test]
fn vers_precise() {
pkg("foo", "0.1.1");
pkg("foo", "0.1.2");
assert_that(cargo_process("install").arg("foo").arg("--vers").arg("0.1.1"),
execs().with_status(0).with_stderr_contains("\
[DOWNLOADING] foo v0.1.1 (registry [..])
"));
}
2017-10-18 06:18:42 +00:00
#[test]
fn version_too() {
pkg("foo", "0.1.1");
pkg("foo", "0.1.2");
assert_that(cargo_process("install").arg("foo").arg("--version").arg("0.1.1"),
execs().with_status(0).with_stderr_contains("\
[DOWNLOADING] foo v0.1.1 (registry [..])
"));
}
#[test]
2017-10-18 06:39:11 +00:00
fn not_both_vers_and_version() {
2017-10-18 06:18:42 +00:00
pkg("foo", "0.1.1");
pkg("foo", "0.1.2");
assert_that(cargo_process("install").arg("foo").arg("--version").arg("0.1.1").arg("--vers").arg("0.1.2"),
2017-10-18 06:39:11 +00:00
execs().with_status(101).with_stderr_contains("\
error: invalid arguments
2017-10-18 06:18:42 +00:00
"));
}
#[test]
fn legacy_version_requirement() {
pkg("foo", "0.1.1");
assert_that(cargo_process("install").arg("foo").arg("--vers").arg("0.1"),
execs().with_status(0).with_stderr_contains("\
warning: the `--vers` provided, `0.1`, is not a valid semver version
historically Cargo treated this as a semver version requirement accidentally
and will continue to do so, but this behavior will be removed eventually
"));
}
#[test]
fn test_install_git_cannot_be_a_base_url() {
assert_that(cargo_process("install").arg("--git").arg("github.com:rust-lang-nursery/rustfmt.git"),
execs().with_status(101).with_stderr("\
error: invalid url `github.com:rust-lang-nursery/rustfmt.git`: cannot-be-a-base-URLs are not supported
"));
}
#[test]
fn uninstall_multiple_and_specifying_bin() {
assert_that(cargo_process("uninstall").args(&["foo", "bar"]).arg("--bin").arg("baz"),
execs().with_status(101).with_stderr("\
error: A binary can only be associated with a single installed package, specifying multiple specs with --bin is redundant.
"));
}
#[test]
fn uninstall_multiple_and_some_pkg_does_not_exist() {
pkg("foo", "0.0.1");
assert_that(cargo_process("install").arg("foo"),
execs().with_status(0));
assert_that(cargo_process("uninstall").args(&["foo", "bar"]),
execs().with_status(101).with_stderr(&format!("\
[REMOVING] {home}[..]bin[..]foo[..]
error: package id specification `bar` matched no packages
[SUMMARY] Successfully uninstalled foo! Failed to uninstall bar (see error(s) above).
error: some packages failed to uninstall
",
home = cargo_home().display())));
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
assert_that(cargo_home(), is_not(has_installed_exe("bar")));
}
#[test]
fn custom_target_dir_for_git_source() {
let p = git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();
assert_that(cargo_process("install")
.arg("--git").arg(p.url().to_string()),
execs().with_status(0));
assert_that(&paths::root().join("target/release"),
is_not(existing_dir()));
assert_that(cargo_process("install").arg("--force")
.arg("--git").arg(p.url().to_string())
.env("CARGO_TARGET_DIR", "target"),
execs().with_status(0));
assert_that(&paths::root().join("target/release"),
existing_dir());
}