From 80d1ba7f5d28a306e29d5dd1da160a27e9d944d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Nov 2015 18:08:06 -0800 Subject: [PATCH 1/2] Refactor testing the registry Use a builder to publish packages instead of a one-off function with many variants, should provide a much finer grained level of configurability for future test cases against the registry. --- tests/support/registry.rs | 232 ++++++++++++++++++++--------------- tests/test_cargo_install.rs | 33 +++-- tests/test_cargo_package.rs | 12 +- tests/test_cargo_registry.rs | 139 +++++++++++---------- 4 files changed, 234 insertions(+), 182 deletions(-) diff --git a/tests/support/registry.rs b/tests/support/registry.rs index be48cb7845e..df0d5301a91 100644 --- a/tests/support/registry.rs +++ b/tests/support/registry.rs @@ -6,10 +6,9 @@ use flate2::Compression::Default; use flate2::write::GzEncoder; use git2; use rustc_serialize::hex::ToHex; -use tar::Archive; +use tar::{Archive, Header}; use url::Url; -use support::project; use support::paths; use support::git::repo; use cargo::util::Sha256; @@ -19,9 +18,20 @@ pub fn registry() -> Url { Url::from_file_path(&*registry_path()).ok().unwrap() pub fn dl_path() -> PathBuf { paths::root().join("dl") } pub fn dl_url() -> Url { Url::from_file_path(&*dl_path()).ok().unwrap() } -pub fn init() { +pub struct Package { + name: String, + vers: String, + deps: Vec<(String, String, &'static str)>, + files: Vec<(String, String)>, + yanked: bool, +} + +fn init() { let config = paths::home().join(".cargo/config"); fs::create_dir_all(config.parent().unwrap()).unwrap(); + if fs::metadata(&config).is_ok() { + return + } File::create(&config).unwrap().write_all(format!(r#" [registry] index = "{reg}" @@ -36,114 +46,142 @@ pub fn init() { .build(); } -pub fn mock_archive(name: &str, version: &str, deps: &[(&str, &str, &str)]) { - let mut manifest = format!(r#" - [package] - name = "{}" - version = "{}" - authors = [] - "#, name, version); - for &(dep, req, kind) in deps.iter() { - manifest.push_str(&format!(r#" - [{}dependencies.{}] - version = "{}" - "#, match kind { - "build" => "build-", - "dev" => "dev-", - _ => "" - }, dep, req)); +impl Package { + pub fn new(name: &str, vers: &str) -> Package { + init(); + Package { + name: name.to_string(), + vers: vers.to_string(), + deps: Vec::new(), + files: Vec::new(), + yanked: false, + } } - let p = project(name) - .file("Cargo.toml", &manifest) - .file("src/lib.rs", "") - .file("src/main.rs", &format!("\ - extern crate {}; - fn main() {{}} - ", name)); - p.build(); - - let dst = mock_archive_dst(name, version); - fs::create_dir_all(dst.parent().unwrap()).unwrap(); - let f = File::create(&dst).unwrap(); - let a = Archive::new(GzEncoder::new(f, Default)); - a.append_file(&format!("{}-{}/Cargo.toml", name, version), - &mut File::open(&p.root().join("Cargo.toml")).unwrap()).unwrap(); - a.append_file(&format!("{}-{}/src/lib.rs", name, version), - &mut File::open(&p.root().join("src/lib.rs")).unwrap()).unwrap(); - a.append_file(&format!("{}-{}/src/main.rs", name, version), - &mut File::open(&p.root().join("src/main.rs")).unwrap()).unwrap(); - a.finish().unwrap(); -} -pub fn mock_archive_dst(name: &str, version: &str) -> PathBuf { - dl_path().join(name).join(version).join("download") -} + pub fn file(&mut self, name: &str, contents: &str) -> &mut Package { + self.files.push((name.to_string(), contents.to_string())); + self + } -pub fn mock_pkg(name: &str, version: &str, deps: &[(&str, &str, &str)]) { - mock_pkg_yank(name, version, deps, false) -} + pub fn dep(&mut self, name: &str, vers: &str) -> &mut Package { + self.deps.push((name.to_string(), vers.to_string(), "normal")); + self + } -pub fn mock_pkg_yank(name: &str, version: &str, deps: &[(&str, &str, &str)], - yanked: bool) { - mock_archive(name, version, deps); - let mut c = Vec::new(); - File::open(&mock_archive_dst(name, version)).unwrap() - .read_to_end(&mut c).unwrap(); - let line = pkg(name, version, deps, &cksum(&c), yanked); - - let file = match name.len() { - 1 => format!("1/{}", name), - 2 => format!("2/{}", name), - 3 => format!("3/{}/{}", &name[..1], name), - _ => format!("{}/{}/{}", &name[0..2], &name[2..4], name), - }; - publish(&file, &line); -} + pub fn dev_dep(&mut self, name: &str, vers: &str) -> &mut Package { + self.deps.push((name.to_string(), vers.to_string(), "dev")); + self + } + + pub fn yanked(&mut self, yanked: bool) -> &mut Package { + self.yanked = yanked; + self + } + + #[allow(deprecated)] // connect => join in 1.3 + pub fn publish(&self) { + self.make_archive(); -pub fn publish(file: &str, line: &str) { - let repo = git2::Repository::open(®istry_path()).unwrap(); - let mut index = repo.index().unwrap(); - { - let dst = registry_path().join(file); + // Figure out what we're going to write into the index + let deps = self.deps.iter().map(|&(ref name, ref req, ref kind)| { + format!("{{\"name\":\"{}\",\ + \"req\":\"{}\",\ + \"features\":[],\ + \"default_features\":false,\ + \"target\":null,\ + \"optional\":false,\ + \"kind\":\"{}\"}}", name, req, kind) + }).collect::>().connect(","); + let cksum = { + let mut c = Vec::new(); + File::open(&self.archive_dst()).unwrap() + .read_to_end(&mut c).unwrap(); + cksum(&c) + }; + let line = format!("{{\"name\":\"{}\",\"vers\":\"{}\",\ + \"deps\":[{}],\"cksum\":\"{}\",\"features\":{{}},\ + \"yanked\":{}}}", + self.name, self.vers, deps, cksum, self.yanked); + let file = match self.name.len() { + 1 => format!("1/{}", self.name), + 2 => format!("2/{}", self.name), + 3 => format!("3/{}/{}", &self.name[..1], self.name), + _ => format!("{}/{}/{}", &self.name[0..2], &self.name[2..4], self.name), + }; + + // Write file/line in the index + let dst = registry_path().join(&file); let mut prev = String::new(); let _ = File::open(&dst).and_then(|mut f| f.read_to_string(&mut prev)); fs::create_dir_all(dst.parent().unwrap()).unwrap(); File::create(&dst).unwrap() - .write_all((prev + line + "\n").as_bytes()).unwrap(); + .write_all((prev + &line[..] + "\n").as_bytes()).unwrap(); + + // Add the new file to the index + let repo = git2::Repository::open(®istry_path()).unwrap(); + let mut index = repo.index().unwrap(); + index.add_path(Path::new(&file)).unwrap(); + index.write().unwrap(); + let id = index.write_tree().unwrap(); + + // Commit this change + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + let parent = repo.refname_to_id("refs/heads/master").unwrap(); + let parent = repo.find_commit(parent).unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, + "Another commit", &tree, + &[&parent]).unwrap(); } - index.add_path(Path::new(file)).unwrap(); - index.write().unwrap(); - let id = index.write_tree().unwrap(); - let tree = repo.find_tree(id).unwrap(); - let sig = repo.signature().unwrap(); - let parent = repo.refname_to_id("refs/heads/master").unwrap(); - let parent = repo.find_commit(parent).unwrap(); - repo.commit(Some("HEAD"), &sig, &sig, - "Another commit", &tree, - &[&parent]).unwrap(); -} -#[allow(deprecated)] // connect => join in 1.3 -pub fn pkg(name: &str, vers: &str, deps: &[(&str, &str, &str)], cksum: &str, - yanked: bool) -> String { - let deps = deps.iter().map(|&(a, b, c)| dep(a, b, c)).collect::>(); - format!("{{\"name\":\"{}\",\"vers\":\"{}\",\ - \"deps\":[{}],\"cksum\":\"{}\",\"features\":{{}},\ - \"yanked\":{}}}", - name, vers, deps.connect(","), cksum, yanked) -} + fn make_archive(&self) { + let mut manifest = format!(r#" + [package] + name = "{}" + version = "{}" + authors = [] + "#, self.name, self.vers); + for &(ref dep, ref req, kind) in self.deps.iter() { + manifest.push_str(&format!(r#" + [{}dependencies.{}] + version = "{}" + "#, match kind { + "build" => "build-", + "dev" => "dev-", + _ => "" + }, dep, req)); + } -pub fn dep(name: &str, req: &str, kind: &str) -> String { - format!("{{\"name\":\"{}\",\ - \"req\":\"{}\",\ - \"features\":[],\ - \"default_features\":false,\ - \"target\":null,\ - \"optional\":false,\ - \"kind\":\"{}\"}}", name, req, kind) + let dst = self.archive_dst(); + fs::create_dir_all(dst.parent().unwrap()).unwrap(); + let f = File::create(&dst).unwrap(); + let a = Archive::new(GzEncoder::new(f, Default)); + self.append(&a, "Cargo.toml", &manifest); + if self.files.len() == 0 { + self.append(&a, "src/lib.rs", ""); + } else { + for &(ref name, ref contents) in self.files.iter() { + self.append(&a, name, contents); + } + } + a.finish().unwrap(); + } + + fn append(&self, ar: &Archive, file: &str, contents: &str) { + let mut header = Header::new(); + header.set_size(contents.len() as u64); + header.set_path(format!("{}-{}/{}", self.name, self.vers, file)).unwrap(); + header.set_cksum(); + + ar.append(&header, &mut contents.as_bytes()).unwrap(); + } + + pub fn archive_dst(&self) -> PathBuf { + dl_path().join(&self.name).join(&self.vers).join("download") + } } -pub fn cksum(s: &[u8]) -> String { +fn cksum(s: &[u8]) -> String { let mut sha = Sha256::new(); sha.update(s); sha.finish().to_hex() diff --git a/tests/test_cargo_install.rs b/tests/test_cargo_install.rs index a26c75997ff..cd1e926ab15 100644 --- a/tests/test_cargo_install.rs +++ b/tests/test_cargo_install.rs @@ -9,13 +9,22 @@ use hamcrest::{assert_that, existing_file, is_not, Matcher, MatchResult}; use support::{project, execs, cargo_dir}; use support::{UPDATING, DOWNLOADING, COMPILING, INSTALLING, REMOVING}; use support::paths; -use support::registry as r; +use support::registry::Package; use support::git; use self::InstalledExe as has_installed_exe; fn setup() { - r::init(); +} + +fn pkg(name: &str, vers: &str) { + Package::new(name, vers) + .file("src/lib.rs", "") + .file("src/main.rs", &format!(" + extern crate {}; + fn main() {{}} + ", name)) + .publish() } fn cargo_process(s: &str) -> ProcessBuilder { @@ -50,7 +59,7 @@ impl fmt::Display for InstalledExe { } test!(simple { - r::mock_pkg("foo", "0.0.1", &[]); + pkg("foo", "0.0.1"); assert_that(cargo_process("install").arg("foo"), execs().with_status(0).with_stdout(&format!("\ @@ -76,8 +85,8 @@ test!(simple { }); test!(pick_max_version { - r::mock_pkg("foo", "0.0.1", &[]); - r::mock_pkg("foo", "0.0.2", &[]); + pkg("foo", "0.0.1"); + pkg("foo", "0.0.2"); assert_that(cargo_process("install").arg("foo"), execs().with_status(0).with_stdout(&format!("\ @@ -95,7 +104,7 @@ test!(pick_max_version { }); test!(missing { - r::mock_pkg("foo", "0.0.1", &[]); + pkg("foo", "0.0.1"); assert_that(cargo_process("install").arg("bar"), execs().with_status(101).with_stderr("\ could not find `bar` in `registry file://[..]` @@ -103,7 +112,7 @@ could not find `bar` in `registry file://[..]` }); test!(bad_version { - r::mock_pkg("foo", "0.0.1", &[]); + pkg("foo", "0.0.1"); assert_that(cargo_process("install").arg("foo").arg("--vers=0.2.0"), execs().with_status(101).with_stderr("\ could not find `foo` in `registry file://[..]` with version `0.2.0` @@ -118,7 +127,7 @@ must specify a crate to install from crates.io }); test!(install_location_precedence { - r::mock_pkg("foo", "0.0.1", &[]); + pkg("foo", "0.0.1"); let root = paths::root(); let t1 = root.join("t1"); @@ -428,9 +437,9 @@ test!(git_repo { }); test!(list { - r::mock_pkg("foo", "0.0.1", &[]); - r::mock_pkg("bar", "0.2.1", &[]); - r::mock_pkg("bar", "0.2.2", &[]); + 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("")); @@ -456,7 +465,7 @@ package id specification `foo` matched no packages }); test!(uninstall_bin_does_not_exist { - r::mock_pkg("foo", "0.0.1", &[]); + pkg("foo", "0.0.1"); assert_that(cargo_process("install").arg("foo"), execs().with_status(0)); diff --git a/tests/test_cargo_package.rs b/tests/test_cargo_package.rs index 5088d1ce2ec..3c8a7a5837f 100644 --- a/tests/test_cargo_package.rs +++ b/tests/test_cargo_package.rs @@ -10,7 +10,7 @@ use tar::Archive; use support::{project, execs, cargo_dir, paths, git, path2url}; use support::{PACKAGING, VERIFYING, COMPILING, ARCHIVING, UPDATING, DOWNLOADING}; -use support::registry as r; +use support::registry::{self, Package}; use hamcrest::{assert_that, existing_file}; fn setup() { @@ -143,8 +143,6 @@ http://doc.crates.io/manifest.html#package-metadata for more info.")); }); test!(wildcard_deps { - r::init(); - let p = project("foo") .file("Cargo.toml", r#" [project] @@ -166,9 +164,9 @@ test!(wildcard_deps { "#) .file("src/main.rs", "fn main() {}"); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg("bar", "0.0.1", &[("baz", "0.0.1", "normal")]); - r::mock_pkg("buz", "0.0.1", &[("bar", "0.0.1", "normal")]); + Package::new("baz", "0.0.1").publish(); + Package::new("bar", "0.0.1").dep("baz", "0.0.1").publish(); + Package::new("buz", "0.0.1").dep("bar", "0.0.1").publish(); assert_that(p.cargo_process("package"), execs().with_status(0).with_stdout(&format!("\ @@ -188,7 +186,7 @@ test!(wildcard_deps { downloading = DOWNLOADING, compiling = COMPILING, dir = p.url(), - reg = r::registry())) + reg = registry::registry())) .with_stderr("\ warning: some dependencies have wildcard (\"*\") version constraints. On December 11th, 2015, \ crates.io will begin rejecting packages with wildcard dependency constraints. See \ diff --git a/tests/test_cargo_registry.rs b/tests/test_cargo_registry.rs index 8209b5bb293..3f9fd85115a 100644 --- a/tests/test_cargo_registry.rs +++ b/tests/test_cargo_registry.rs @@ -5,13 +5,12 @@ use cargo::util::process; use support::{project, execs, cargo_dir}; use support::{UPDATING, DOWNLOADING, COMPILING, PACKAGING, VERIFYING, ADDING, REMOVING}; use support::paths::{self, CargoPathExt}; -use support::registry as r; +use support::registry::{self, Package}; use support::git; use hamcrest::assert_that; fn setup() { - r::init(); } test!(simple { @@ -27,7 +26,7 @@ test!(simple { "#) .file("src/main.rs", "fn main() {}"); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo_process("build"), execs().with_status(0).with_stdout(&format!("\ @@ -40,7 +39,7 @@ test!(simple { downloading = DOWNLOADING, compiling = COMPILING, dir = p.url(), - reg = r::registry()))); + reg = registry::registry()))); // Don't download a second time assert_that(p.cargo_process("build"), @@ -51,7 +50,7 @@ test!(simple { ", updating = UPDATING, dir = p.url(), - reg = r::registry()))); + reg = registry::registry()))); }); test!(deps { @@ -67,8 +66,8 @@ test!(deps { "#) .file("src/main.rs", "fn main() {}"); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]); + Package::new("baz", "0.0.1").publish(); + Package::new("bar", "0.0.1").dep("baz", "*").publish(); assert_that(p.cargo_process("build"), execs().with_status(0).with_stdout(&format!("\ @@ -83,10 +82,12 @@ test!(deps { downloading = DOWNLOADING, compiling = COMPILING, dir = p.url(), - reg = r::registry()))); + reg = registry::registry()))); }); test!(nonexistent { + Package::new("init", "0.0.1").publish(); + let p = project("foo") .file("Cargo.toml", r#" [project] @@ -120,8 +121,8 @@ test!(wrong_version { "#) .file("src/main.rs", "fn main() {}"); - r::mock_pkg("foo", "0.0.1", &[]); - r::mock_pkg("foo", "0.0.2", &[]); + Package::new("foo", "0.0.1").publish(); + Package::new("foo", "0.0.2").publish(); assert_that(p.cargo_process("build"), execs().with_status(101).with_stderr("\ @@ -131,8 +132,8 @@ version required: >= 1.0.0 versions found: 0.0.2, 0.0.1 ")); - r::mock_pkg("foo", "0.0.3", &[]); - r::mock_pkg("foo", "0.0.4", &[]); + Package::new("foo", "0.0.3").publish(); + Package::new("foo", "0.0.4").publish(); assert_that(p.cargo_process("build"), execs().with_status(101).with_stderr("\ @@ -156,8 +157,9 @@ test!(bad_cksum { "#) .file("src/main.rs", "fn main() {}"); - r::mock_pkg("bad-cksum", "0.0.1", &[]); - File::create(&r::mock_archive_dst("bad-cksum", "0.0.1")).unwrap(); + let pkg = Package::new("bad-cksum", "0.0.1"); + pkg.publish(); + File::create(&pkg.archive_dst()).unwrap(); assert_that(p.cargo_process("build").arg("-v"), execs().with_status(101).with_stderr("\ @@ -172,6 +174,8 @@ Caused by: }); test!(update_registry { + Package::new("init", "0.0.1").publish(); + let p = project("foo") .file("Cargo.toml", r#" [project] @@ -191,7 +195,7 @@ location searched: registry file://[..] version required: >= 0.0.0 ")); - r::mock_pkg("notyet", "0.0.1", &[]); + Package::new("notyet", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -204,10 +208,12 @@ version required: >= 0.0.0 downloading = DOWNLOADING, compiling = COMPILING, dir = p.url(), - reg = r::registry()))); + reg = registry::registry()))); }); test!(package_with_path_deps { + Package::new("init", "0.0.1").publish(); + let p = project("foo") .file("Cargo.toml", r#" [project] @@ -242,7 +248,7 @@ location searched: registry file://[..] version required: ^0.0.1 ")); - r::mock_pkg("notyet", "0.0.1", &[]); + Package::new("notyet", "0.0.1").publish(); assert_that(p.cargo("package"), execs().with_status(0).with_stdout(format!("\ @@ -276,7 +282,7 @@ test!(lockfile_locks { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -288,7 +294,7 @@ test!(lockfile_locks { dir = p.url()))); p.root().move_into_the_past().unwrap(); - r::mock_pkg("bar", "0.0.2", &[]); + Package::new("bar", "0.0.2").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); @@ -308,8 +314,8 @@ test!(lockfile_locks_transitively { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]); + Package::new("baz", "0.0.1").publish(); + Package::new("bar", "0.0.1").dep("baz", "*").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -323,8 +329,8 @@ test!(lockfile_locks_transitively { dir = p.url()))); p.root().move_into_the_past().unwrap(); - r::mock_pkg("baz", "0.0.2", &[]); - r::mock_pkg("bar", "0.0.2", &[("baz", "*", "normal")]); + Package::new("baz", "0.0.2").publish(); + Package::new("bar", "0.0.2").dep("baz", "*").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); @@ -344,10 +350,10 @@ test!(yanks_are_not_used { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg_yank("baz", "0.0.2", &[], true); - r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]); - r::mock_pkg_yank("bar", "0.0.2", &[("baz", "*", "normal")], true); + Package::new("baz", "0.0.1").publish(); + Package::new("baz", "0.0.2").yanked(true).publish(); + Package::new("bar", "0.0.1").dep("baz", "*").publish(); + Package::new("bar", "0.0.2").dep("baz", "*").yanked(true).publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -375,9 +381,9 @@ test!(relying_on_a_yank_is_bad { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg_yank("baz", "0.0.2", &[], true); - r::mock_pkg("bar", "0.0.1", &[("baz", "=0.0.2", "normal")]); + Package::new("baz", "0.0.1").publish(); + Package::new("baz", "0.0.2").yanked(true).publish(); + Package::new("bar", "0.0.1").dep("baz", "=0.0.2").publish(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ @@ -402,14 +408,14 @@ test!(yanks_in_lockfiles_are_ok { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0)); - fs::remove_dir_all(&r::registry_path().join("3")).unwrap(); + fs::remove_dir_all(®istry::registry_path().join("3")).unwrap(); - r::mock_pkg_yank("bar", "0.0.1", &[], true); + Package::new("bar", "0.0.1").yanked(true).publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); @@ -436,7 +442,7 @@ test!(update_with_lockfile_if_packages_missing { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0)); p.root().move_into_the_past().unwrap(); @@ -464,12 +470,12 @@ test!(update_lockfile { p.build(); println!("0.0.1"); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0)); - r::mock_pkg("bar", "0.0.2", &[]); - r::mock_pkg("bar", "0.0.3", &[]); + Package::new("bar", "0.0.2").publish(); + Package::new("bar", "0.0.3").publish(); paths::home().join(".cargo/registry").rm_rf().unwrap(); println!("0.0.2 update"); assert_that(p.cargo("update") @@ -506,8 +512,8 @@ test!(update_lockfile { dir = p.url()))); println!("new dependencies update"); - r::mock_pkg("bar", "0.0.4", &[("spam", "0.2.5", "")]); - r::mock_pkg("spam", "0.2.5", &[]); + Package::new("bar", "0.0.4").dep("spam", "0.2.5").publish(); + Package::new("spam", "0.2.5").publish(); assert_that(p.cargo("update") .arg("-p").arg("bar"), execs().with_status(0).with_stdout(&format!("\ @@ -517,7 +523,7 @@ test!(update_lockfile { ", updating = UPDATING, adding = ADDING))); println!("new dependencies update"); - r::mock_pkg("bar", "0.0.5", &[]); + Package::new("bar", "0.0.5").publish(); assert_that(p.cargo("update") .arg("-p").arg("bar"), execs().with_status(0).with_stdout(&format!("\ @@ -541,8 +547,8 @@ test!(dev_dependency_not_used { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("baz", "0.0.1", &[]); - r::mock_pkg("bar", "0.0.1", &[("baz", "*", "dev")]); + Package::new("baz", "0.0.1").publish(); + Package::new("bar", "0.0.1").dev_dep("baz", "*").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -608,7 +614,7 @@ test!(updating_a_dep { .file("a/src/lib.rs", ""); p.build(); - r::mock_pkg("bar", "0.0.1", &[]); + Package::new("bar", "0.0.1").publish(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout(&format!("\ @@ -629,7 +635,7 @@ test!(updating_a_dep { [dependencies] bar = "0.1.0" "#).unwrap(); - r::mock_pkg("bar", "0.1.0", &[]); + Package::new("bar", "0.1.0").publish(); println!("second"); assert_that(p.cargo("build"), @@ -672,7 +678,7 @@ test!(git_and_registry_dep { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("a", "0.0.1", &[]); + Package::new("a", "0.0.1").publish(); p.root().move_into_the_past().unwrap(); assert_that(p.cargo("build"), @@ -706,13 +712,12 @@ test!(update_publish_then_update { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("a", "0.1.0", &[]); + Package::new("a", "0.1.0").publish(); assert_that(p.cargo("build"), execs().with_status(0)); - - r::mock_pkg("a", "0.1.1", &[]); + Package::new("a", "0.1.1").publish(); let lock = p.root().join("Cargo.lock"); let mut s = String::new(); @@ -747,7 +752,7 @@ test!(fetch_downloads { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("a", "0.1.0", &[]); + Package::new("a", "0.1.0").publish(); assert_that(p.cargo("fetch"), execs().with_status(0) @@ -771,13 +776,13 @@ test!(update_transitive_dependency { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("a", "0.1.0", &[("b", "*", "normal")]); - r::mock_pkg("b", "0.1.0", &[]); + Package::new("a", "0.1.0").dep("b", "*").publish(); + Package::new("b", "0.1.0").publish(); assert_that(p.cargo("fetch"), execs().with_status(0)); - r::mock_pkg("b", "0.1.1", &[]); + Package::new("b", "0.1.1").publish(); assert_that(p.cargo("update").arg("-pb"), execs().with_status(0) @@ -810,18 +815,20 @@ test!(update_backtracking_ok { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("webdriver", "0.1.0", &[("hyper", "0.6", "normal")]); - r::mock_pkg("hyper", "0.6.5", &[("openssl", "0.1", "normal"), - ("cookie", "0.1", "normal")]); - r::mock_pkg("cookie", "0.1.0", &[("openssl", "0.1", "normal")]); - r::mock_pkg("openssl", "0.1.0", &[]); + Package::new("webdriver", "0.1.0").dep("hyper", "0.6").publish(); + Package::new("hyper", "0.6.5").dep("openssl", "0.1") + .dep("cookie", "0.1") + .publish(); + Package::new("cookie", "0.1.0").dep("openssl", "0.1").publish(); + Package::new("openssl", "0.1.0").publish(); assert_that(p.cargo("generate-lockfile"), execs().with_status(0)); - r::mock_pkg("openssl", "0.1.1", &[]); - r::mock_pkg("hyper", "0.6.6", &[("openssl", "0.1.1", "normal"), - ("cookie", "0.1.0", "normal")]); + Package::new("openssl", "0.1.1").publish(); + Package::new("hyper", "0.6.6").dep("openssl", "0.1.1") + .dep("cookie", "0.1.0") + .publish(); assert_that(p.cargo("update").arg("-p").arg("hyper"), execs().with_status(0) @@ -846,16 +853,16 @@ test!(update_multiple_packages { .file("src/main.rs", "fn main() {}"); p.build(); - r::mock_pkg("a", "0.1.0", &[]); - r::mock_pkg("b", "0.1.0", &[]); - r::mock_pkg("c", "0.1.0", &[]); + Package::new("a", "0.1.0").publish(); + Package::new("b", "0.1.0").publish(); + Package::new("c", "0.1.0").publish(); assert_that(p.cargo("fetch"), execs().with_status(0)); - r::mock_pkg("a", "0.1.1", &[]); - r::mock_pkg("b", "0.1.1", &[]); - r::mock_pkg("c", "0.1.1", &[]); + Package::new("a", "0.1.1").publish(); + Package::new("b", "0.1.1").publish(); + Package::new("c", "0.1.1").publish(); assert_that(p.cargo("update").arg("-pa").arg("-pb"), execs().with_status(0) From 542355d8bf4522fcdd9cb77eae8e83144d6e3052 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Nov 2015 18:17:23 -0800 Subject: [PATCH 2/2] Only read one package from registry tarballs Even if multiple ones are included, don't recurse! Closes #2132 --- src/cargo/sources/path.rs | 15 ++++++++++---- tests/test_cargo_registry.rs | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index eedb88303bf..fabdc27ae49 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -59,12 +59,19 @@ impl<'cfg> PathSource<'cfg> { pub fn read_packages(&self) -> CargoResult> { if self.updated { Ok(self.packages.clone()) - } else if self.id.is_path() && self.id.precise().is_some() { + } else if (self.id.is_path() && self.id.precise().is_some()) || + self.id.is_registry() { // If our source id is a path and it's listed with a precise // version, then it means that we're not allowed to have nested - // dependencies (they've been rewritten to crates.io dependencies) - // In this case we specifically read just one package, not a list of - // packages. + // dependencies (they've been rewritten to crates.io dependencies). + // + // If our source id is a registry dependency then crates are + // published one at a time so we don't recurse as well. Note that + // cargo by default doesn't package up nested dependencies but it + // may do so for custom-crafted tarballs. + // + // In these cases we specifically read just one package, not a list + // of packages. let path = self.path.join("Cargo.toml"); let (pkg, _) = try!(ops::read_package(&path, &self.id, self.config)); diff --git a/tests/test_cargo_registry.rs b/tests/test_cargo_registry.rs index 3f9fd85115a..23be64c5586 100644 --- a/tests/test_cargo_registry.rs +++ b/tests/test_cargo_registry.rs @@ -896,3 +896,43 @@ test!(update_multiple_packages { .with_stdout_contains(format!("\ {compiling} foo v0.5.0 ([..])", compiling = COMPILING))); }); + +test!(bundled_crate_in_registry { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + + [dependencies] + bar = "0.1" + baz = "0.1" + "#) + .file("src/main.rs", "fn main() {}"); + p.build(); + + Package::new("bar", "0.1.0").publish(); + Package::new("baz", "0.1.0") + .dep("bar", "0.1.0") + .file("Cargo.toml", r#" + [package] + name = "baz" + version = "0.1.0" + authors = [] + + [dependencies] + bar = { path = "bar", version = "0.1.0" } + "#) + .file("src/lib.rs", "") + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.1.0" + authors = [] + "#) + .file("bar/src/lib.rs", "") + .publish(); + + assert_that(p.cargo("run"), execs().with_status(0)); +});