cargo/tests/package.rs

590 lines
17 KiB
Rust
Raw Normal View History

#[macro_use]
extern crate cargotest;
extern crate flate2;
extern crate git2;
extern crate hamcrest;
extern crate tar;
extern crate cargo;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
2014-09-09 02:38:16 +00:00
use cargotest::{cargo_process, process};
use cargotest::support::{project, execs, paths, git, path2url, cargo_exe};
use flate2::read::GzDecoder;
use hamcrest::{assert_that, existing_file, contains};
use tar::Archive;
#[test]
fn simple() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
2014-09-09 02:38:16 +00:00
exclude = ["*.txt"]
license = "MIT"
description = "foo"
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
2014-09-09 02:38:16 +00:00
"#)
.file("src/bar.txt", ""); // should be ignored when packaging
assert_that(p.cargo_process("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no documentation[..]
See [..]
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2015-03-26 18:17:44 +00:00
dir = p.url())));
assert_that(&p.root().join("target/package/foo-0.0.1.crate"), existing_file());
assert_that(p.cargo("package").arg("-l"),
execs().with_status(0).with_stdout("\
Cargo.toml
src[/]main.rs
"));
assert_that(p.cargo("package"),
2014-09-09 02:38:16 +00:00
execs().with_status(0).with_stdout(""));
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
let mut rdr = GzDecoder::new(f).unwrap();
let mut contents = Vec::new();
rdr.read_to_end(&mut contents).unwrap();
let mut ar = Archive::new(&contents[..]);
for f in ar.entries().unwrap() {
let f = f.unwrap();
let fname = f.header().path_bytes();
let fname = &*fname;
2014-11-19 06:29:19 +00:00
assert!(fname == b"foo-0.0.1/Cargo.toml" ||
fname == b"foo-0.0.1/src/main.rs",
"unexpected filename: {:?}", f.header().path())
2014-09-09 02:38:16 +00:00
}
}
#[test]
fn metadata_warning() {
let p = project("all")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
assert_that(p.cargo_process("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-20 00:52:13 +00:00
warning: manifest has no description, license, license-file, documentation, \
homepage or repository.
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2016-05-20 00:52:13 +00:00
dir = p.url())));
let p = project("one")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
license = "MIT"
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
assert_that(p.cargo_process("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
warning: manifest has no description, documentation, homepage or repository.
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2016-05-20 00:52:13 +00:00
dir = p.url())));
let p = project("all")
2016-05-30 22:41:36 +00:00
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
license = "MIT"
description = "foo"
repository = "bar"
2016-05-30 22:41:36 +00:00
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
assert_that(p.cargo_process("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2015-03-26 18:17:44 +00:00
dir = p.url())));
}
#[test]
fn package_verbose() {
let root = paths::root().join("all");
let p = git::repo(&root)
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("a/Cargo.toml", r#"
[project]
name = "a"
version = "0.0.1"
authors = []
"#)
.file("a/src/lib.rs", "");
p.build();
let mut cargo = cargo_process();
cargo.cwd(p.root());
assert_that(cargo.clone().arg("build"), execs().with_status(0));
println!("package main repo");
assert_that(cargo.clone().arg("package").arg("-v").arg("--no-verify"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no description[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([..])
[ARCHIVING] [..]
[ARCHIVING] [..]
"));
println!("package sub-repo");
assert_that(cargo.arg("package").arg("-v").arg("--no-verify")
.cwd(p.root().join("a")),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no description[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] a v0.0.1 ([..])
[ARCHIVING] [..]
[ARCHIVING] [..]
"));
}
#[test]
fn package_verification() {
let p = project("all")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(p.cargo("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no description[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2015-03-26 18:17:44 +00:00
dir = p.url())));
}
#[test]
fn path_dependency_no_version() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
license = "MIT"
description = "foo"
[dependencies.bar]
path = "bar"
"#)
.file("src/main.rs", "fn main() {}")
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("bar/src/lib.rs", "");
assert_that(p.cargo_process("package"),
execs().with_status(101).with_stderr("\
[WARNING] manifest has no documentation, homepage or repository.
See http://doc.crates.io/manifest.html#package-metadata for more info.
[ERROR] all path dependencies must have a version specified when packaging.
dependency `bar` does not specify a version.
"));
}
#[test]
fn exclude() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
exclude = ["*.txt"]
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#)
.file("bar.txt", "")
.file("src/bar.txt", "");
assert_that(p.cargo_process("package").arg("--no-verify").arg("-v"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no description[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([..])
[ARCHIVING] [..]
[ARCHIVING] [..]
"));
}
#[test]
fn include() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
exclude = ["*.txt"]
include = ["foo.txt", "**/*.rs", "Cargo.toml"]
"#)
.file("foo.txt", "")
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#)
.file("src/bar.txt", ""); // should be ignored when packaging
assert_that(p.cargo_process("package").arg("--no-verify").arg("-v"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no description[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([..])
[ARCHIVING] [..]
[ARCHIVING] [..]
[ARCHIVING] [..]
"));
}
#[test]
fn package_lib_with_bin() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
extern crate foo;
fn main() {}
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("package").arg("-v"),
execs().with_status(0));
}
#[test]
fn package_git_submodule() {
let project = git::new("foo", |project| {
project.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = ["foo@example.com"]
license = "MIT"
description = "foo"
repository = "foo"
"#)
.file("src/lib.rs", "pub fn foo() {}")
}).unwrap();
let library = git::new("bar", |library| {
library.file("Makefile", "all:")
}).unwrap();
let repository = git2::Repository::open(&project.root()).unwrap();
let url = path2url(library.root()).to_string();
git::add_submodule(&repository, &url, Path::new("bar"));
git::commit(&repository);
let repository = git2::Repository::open(&project.root().join("bar")).unwrap();
repository.reset(&repository.revparse_single("HEAD").unwrap(),
git2::ResetType::Hard, None).unwrap();
assert_that(cargo_process().arg("package").cwd(project.root())
.arg("--no-verify").arg("-v"),
2016-05-20 00:52:13 +00:00
execs().with_status(0).with_stderr_contains("[ARCHIVING] bar/Makefile"));
}
#[test]
fn no_duplicates_from_modified_tracked_files() {
let root = paths::root().join("all");
let p = git::repo(&root)
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
p.build();
2017-02-18 12:01:10 +00:00
File::create(p.root().join("src/main.rs")).unwrap().write_all(br#"
fn main() { println!("A change!"); }
2017-02-18 12:01:10 +00:00
"#).unwrap();
let mut cargo = cargo_process();
cargo.cwd(p.root());
assert_that(cargo.clone().arg("build"), execs().with_status(0));
assert_that(cargo.arg("package").arg("--list"),
2016-05-12 17:06:36 +00:00
execs().with_status(0).with_stdout("\
Cargo.toml
src/main.rs
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn ignore_nested() {
let cargo_toml = r#"
[project]
name = "nested"
version = "0.0.1"
authors = []
license = "MIT"
description = "nested"
"#;
let main_rs = r#"
fn main() { println!("hello"); }
"#;
let p = project("nested")
.file("Cargo.toml", cargo_toml)
.file("src/main.rs", main_rs)
// If a project happens to contain a copy of itself, we should
// ignore it.
.file("a_dir/nested/Cargo.toml", cargo_toml)
.file("a_dir/nested/src/main.rs", main_rs);
assert_that(p.cargo_process("package"),
2016-05-14 21:44:18 +00:00
execs().with_status(0).with_stderr(&format!("\
2016-05-20 00:52:13 +00:00
[WARNING] manifest has no documentation[..]
See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] nested v0.0.1 ({dir})
[VERIFYING] nested v0.0.1 ({dir})
[COMPILING] nested v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
dir = p.url())));
assert_that(&p.root().join("target/package/nested-0.0.1.crate"), existing_file());
assert_that(p.cargo("package").arg("-l"),
execs().with_status(0).with_stdout("\
Cargo.toml
src[..]main.rs
"));
assert_that(p.cargo("package"),
execs().with_status(0).with_stdout(""));
let f = File::open(&p.root().join("target/package/nested-0.0.1.crate")).unwrap();
let mut rdr = GzDecoder::new(f).unwrap();
let mut contents = Vec::new();
rdr.read_to_end(&mut contents).unwrap();
let mut ar = Archive::new(&contents[..]);
for f in ar.entries().unwrap() {
let f = f.unwrap();
let fname = f.header().path_bytes();
let fname = &*fname;
assert!(fname == b"nested-0.0.1/Cargo.toml" ||
fname == b"nested-0.0.1/src/main.rs",
"unexpected filename: {:?}", f.header().path())
}
}
#[cfg(unix)] // windows doesn't allow these characters in filenames
#[test]
fn package_weird_characters() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#)
.file("src/:foo", "");
assert_that(p.cargo_process("package"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
warning: [..]
See [..]
2016-05-20 00:52:13 +00:00
[PACKAGING] foo [..]
[ERROR] failed to prepare local package for uploading
Caused by:
cannot package a filename with a special character `:`: src/:foo
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn repackage_on_source_change() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#);
assert_that(p.cargo_process("package"),
execs().with_status(0));
// Add another source file
let mut file = File::create(p.root().join("src").join("foo.rs")).unwrap_or_else(|e| {
panic!("could not create file {}: {}", p.root().join("src/foo.rs").display(), e)
});
2017-02-18 12:01:10 +00:00
file.write_all(br#"
fn main() { println!("foo"); }
2017-02-18 12:01:10 +00:00
"#).unwrap();
std::mem::drop(file);
let mut pro = process(&cargo_exe());
pro.arg("package").cwd(p.root());
// Check that cargo rebuilds the tarball
assert_that(pro, execs().with_status(0).with_stderr(&format!("\
[WARNING] [..]
See [..]
[PACKAGING] foo v0.0.1 ({dir})
[VERIFYING] foo v0.0.1 ({dir})
[COMPILING] foo v0.0.1 ({dir}[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
dir = p.url())));
// Check that the tarball contains the added file
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
let mut rdr = GzDecoder::new(f).unwrap();
let mut contents = Vec::new();
rdr.read_to_end(&mut contents).unwrap();
let mut ar = Archive::new(&contents[..]);
let entries = ar.entries().unwrap();
let entry_paths = entries.map(|entry| {
entry.unwrap().path().unwrap().into_owned()
}).collect::<Vec<PathBuf>>();
assert_that(&entry_paths, contains(vec![PathBuf::from("foo-0.0.1/src/foo.rs")]));
}
#[test]
#[cfg(unix)]
fn broken_symlink() {
use std::os::unix::fs;
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
license = "MIT"
description = 'foo'
documentation = 'foo'
homepage = 'foo'
repository = 'foo'
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#);
p.build();
t!(fs::symlink("nowhere", &p.root().join("src/foo.rs")));
assert_that(p.cargo("package").arg("-v"),
execs().with_status(101)
.with_stderr_contains("\
error: failed to prepare local package for uploading
Caused by:
failed to open for archiving: `[..]foo.rs`
Caused by:
[..]
"));
}
#[test]
fn do_not_package_if_repository_is_dirty() {
let p = project("foo");
p.build();
// Create a Git repository containing a minimal Rust project.
git::repo(&paths::root().join("foo"))
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
license = "MIT"
description = "foo"
documentation = "foo"
homepage = "foo"
repository = "foo"
"#)
.file("src/main.rs", "fn main() {}")
.build();
// Modify Cargo.toml without committing the change.
p.change_file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
license = "MIT"
description = "foo"
documentation = "foo"
homepage = "foo"
repository = "foo"
# change
"#);
assert_that(p.cargo("package"),
execs().with_status(101)
.with_stderr("\
error: 1 dirty files found in the working directory:
Cargo.toml
to proceed despite this, pass the `--allow-dirty` flag
"));
}