mirror of
https://github.com/rust-lang/cargo
synced 2024-10-14 03:32:39 +00:00
353 lines
11 KiB
Rust
353 lines
11 KiB
Rust
|
use std::env;
|
||
|
use std::fs::{self, File};
|
||
|
use std::io::Write;
|
||
|
use std::net::TcpListener;
|
||
|
use std::process::Stdio;
|
||
|
use std::thread;
|
||
|
|
||
|
use git2;
|
||
|
use hamcrest::{assert_that, existing_file};
|
||
|
|
||
|
use support::{execs, project, ERROR};
|
||
|
use support::git;
|
||
|
use support::registry::Package;
|
||
|
use test_cargo_install::{cargo_home, has_installed_exe};
|
||
|
|
||
|
fn setup() {}
|
||
|
|
||
|
test!(multiple_installs {
|
||
|
let p = project("foo")
|
||
|
.file("a/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
"#)
|
||
|
.file("a/src/main.rs", "fn main() {}")
|
||
|
.file("b/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "bar"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
"#)
|
||
|
.file("b/src/main.rs", "fn main() {}");
|
||
|
p.build();
|
||
|
|
||
|
let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
|
||
|
let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
assert_that(a, execs().with_status(0));
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
|
||
|
assert_that(cargo_home(), has_installed_exe("foo"));
|
||
|
assert_that(cargo_home(), has_installed_exe("bar"));
|
||
|
});
|
||
|
|
||
|
test!(one_install_should_be_bad {
|
||
|
let p = project("foo")
|
||
|
.file("a/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
"#)
|
||
|
.file("a/src/main.rs", "fn main() {}")
|
||
|
.file("b/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
"#)
|
||
|
.file("b/src/main.rs", "fn main() {}");
|
||
|
p.build();
|
||
|
|
||
|
let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
|
||
|
let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
let (bad, good) = if a.status.code() == Some(101) {(a, b)} else {(b, a)};
|
||
|
assert_that(bad, execs().with_status(101).with_stderr_contains(&format!("\
|
||
|
{error} binary `foo[..]` already exists in destination as part of `[..]`
|
||
|
", error = ERROR)));
|
||
|
assert_that(good, execs().with_status(0).with_stderr("\
|
||
|
be sure to add `[..]` to your PATH [..]
|
||
|
"));
|
||
|
|
||
|
assert_that(cargo_home(), has_installed_exe("foo"));
|
||
|
});
|
||
|
|
||
|
test!(multiple_registry_fetches {
|
||
|
let mut pkg = Package::new("bar", "1.0.2");
|
||
|
for i in 0..10 {
|
||
|
let name = format!("foo{}", i);
|
||
|
Package::new(&name, "1.0.0").publish();
|
||
|
pkg.dep(&name, "*");
|
||
|
}
|
||
|
pkg.publish();
|
||
|
|
||
|
let p = project("foo")
|
||
|
.file("a/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
bar = "*"
|
||
|
"#)
|
||
|
.file("a/src/main.rs", "fn main() {}")
|
||
|
.file("b/Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "bar"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
bar = "*"
|
||
|
"#)
|
||
|
.file("b/src/main.rs", "fn main() {}");
|
||
|
p.build();
|
||
|
|
||
|
let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
|
||
|
let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
assert_that(a, execs().with_status(0));
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
|
||
|
let suffix = env::consts::EXE_SUFFIX;
|
||
|
assert_that(&p.root().join("a/target/debug").join(format!("foo{}", suffix)),
|
||
|
existing_file());
|
||
|
assert_that(&p.root().join("b/target/debug").join(format!("bar{}", suffix)),
|
||
|
existing_file());
|
||
|
});
|
||
|
|
||
|
test!(git_same_repo_different_tags {
|
||
|
let a = git::new("dep", |project| {
|
||
|
project.file("Cargo.toml", r#"
|
||
|
[project]
|
||
|
name = "dep"
|
||
|
version = "0.5.0"
|
||
|
authors = []
|
||
|
"#).file("src/lib.rs", "pub fn tag1() {}")
|
||
|
}).unwrap();
|
||
|
|
||
|
let repo = git2::Repository::open(&a.root()).unwrap();
|
||
|
git::tag(&repo, "tag1");
|
||
|
|
||
|
File::create(a.root().join("src/lib.rs")).unwrap()
|
||
|
.write_all(b"pub fn tag2() {}").unwrap();
|
||
|
git::add(&repo);
|
||
|
git::commit(&repo);
|
||
|
git::tag(&repo, "tag2");
|
||
|
|
||
|
let p = project("foo")
|
||
|
.file("a/Cargo.toml", &format!(r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
dep = {{ git = '{}', tag = 'tag1' }}
|
||
|
"#, a.url()))
|
||
|
.file("a/src/main.rs", "extern crate dep; fn main() { dep::tag1(); }")
|
||
|
.file("b/Cargo.toml", &format!(r#"
|
||
|
[package]
|
||
|
name = "bar"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
dep = {{ git = '{}', tag = 'tag2' }}
|
||
|
"#, a.url()))
|
||
|
.file("b/src/main.rs", "extern crate dep; fn main() { dep::tag2(); }");
|
||
|
p.build();
|
||
|
|
||
|
let mut a = p.cargo("build").arg("-v").cwd(p.root().join("a")).build_command();
|
||
|
let mut b = p.cargo("build").arg("-v").cwd(p.root().join("b")).build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
assert_that(a, execs().with_status(0));
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
});
|
||
|
|
||
|
test!(git_same_branch_different_revs {
|
||
|
let a = git::new("dep", |project| {
|
||
|
project.file("Cargo.toml", r#"
|
||
|
[project]
|
||
|
name = "dep"
|
||
|
version = "0.5.0"
|
||
|
authors = []
|
||
|
"#).file("src/lib.rs", "pub fn f1() {}")
|
||
|
}).unwrap();
|
||
|
|
||
|
let p = project("foo")
|
||
|
.file("a/Cargo.toml", &format!(r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
dep = {{ git = '{}' }}
|
||
|
"#, a.url()))
|
||
|
.file("a/src/main.rs", "extern crate dep; fn main() { dep::f1(); }")
|
||
|
.file("b/Cargo.toml", &format!(r#"
|
||
|
[package]
|
||
|
name = "bar"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
|
||
|
[dependencies]
|
||
|
dep = {{ git = '{}' }}
|
||
|
"#, a.url()))
|
||
|
.file("b/src/main.rs", "extern crate dep; fn main() { dep::f2(); }");
|
||
|
p.build();
|
||
|
|
||
|
// Generate a Cargo.lock pointing at the current rev, then clear out the
|
||
|
// target directory
|
||
|
assert_that(p.cargo("build").cwd(p.root().join("a")),
|
||
|
execs().with_status(0));
|
||
|
fs::remove_dir_all(p.root().join("a/target")).unwrap();
|
||
|
|
||
|
// Make a new commit on the master branch
|
||
|
let repo = git2::Repository::open(&a.root()).unwrap();
|
||
|
File::create(a.root().join("src/lib.rs")).unwrap()
|
||
|
.write_all(b"pub fn f2() {}").unwrap();
|
||
|
git::add(&repo);
|
||
|
git::commit(&repo);
|
||
|
|
||
|
// Now run both builds in parallel. The build of `b` should pick up the
|
||
|
// newest commit while the build of `a` should use the locked old commit.
|
||
|
let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
|
||
|
let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
assert_that(a, execs().with_status(0));
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
});
|
||
|
|
||
|
test!(same_project {
|
||
|
let p = project("foo")
|
||
|
.file("Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
"#)
|
||
|
.file("src/main.rs", "fn main() {}")
|
||
|
.file("src/lib.rs", "");
|
||
|
p.build();
|
||
|
|
||
|
let mut a = p.cargo("build").build_command();
|
||
|
let mut b = p.cargo("build").build_command();
|
||
|
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
|
||
|
let a = a.spawn().unwrap();
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
assert_that(a, execs().with_status(0));
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
});
|
||
|
|
||
|
// Make sure that if Cargo dies while holding a lock that it's released and the
|
||
|
// next Cargo to come in will take over cleanly.
|
||
|
test!(killing_cargo_releases_the_lock {
|
||
|
let p = project("foo")
|
||
|
.file("Cargo.toml", r#"
|
||
|
[package]
|
||
|
name = "foo"
|
||
|
authors = []
|
||
|
version = "0.0.0"
|
||
|
build = "build.rs"
|
||
|
"#)
|
||
|
.file("src/main.rs", "fn main() {}")
|
||
|
.file("build.rs", r#"
|
||
|
use std::net::TcpStream;
|
||
|
|
||
|
fn main() {
|
||
|
if std::env::var("A").is_ok() {
|
||
|
TcpStream::connect(&std::env::var("ADDR").unwrap()[..])
|
||
|
.unwrap();
|
||
|
std::thread::sleep(std::time::Duration::new(10, 0));
|
||
|
}
|
||
|
}
|
||
|
"#);
|
||
|
p.build();
|
||
|
|
||
|
// Our build script will connect to our local TCP socket to inform us that
|
||
|
// it's started running, and that's how we know that `a` will have the lock
|
||
|
// when we kill it.
|
||
|
let l = TcpListener::bind("127.0.0.1:0").unwrap();
|
||
|
let mut a = p.cargo("build").build_command();
|
||
|
let mut b = p.cargo("build").build_command();
|
||
|
a.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
b.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||
|
a.env("ADDR", l.local_addr().unwrap().to_string()).env("A", "a");
|
||
|
b.env("ADDR", l.local_addr().unwrap().to_string()).env_remove("A");
|
||
|
|
||
|
// Spawn `a`, wait for it to get to the build script (at which point the
|
||
|
// lock is held), then kill it.
|
||
|
let mut a = a.spawn().unwrap();
|
||
|
l.accept().unwrap();
|
||
|
a.kill().unwrap();
|
||
|
|
||
|
// Spawn `b`, then just finish the output of a/b the same way the above
|
||
|
// tests does.
|
||
|
let b = b.spawn().unwrap();
|
||
|
let a = thread::spawn(move || a.wait_with_output().unwrap());
|
||
|
let b = b.wait_with_output().unwrap();
|
||
|
let a = a.join().unwrap();
|
||
|
|
||
|
// We killed `a`, so it shouldn't succeed, but `b` should have succeeded.
|
||
|
assert!(!a.status.success());
|
||
|
assert_that(b, execs().with_status(0));
|
||
|
});
|