From c072ba42425417d62efedaf27e4040de7e263b15 Mon Sep 17 00:00:00 2001 From: Behnam Esfahbod Date: Fri, 7 Jul 2017 12:52:03 -0600 Subject: [PATCH] [sources/path] Add gitignore-like pattern matching and warn on mismatches Add gitignore-like pattern matching logic to `list_files()` and throw warnings for paths getting different inclusion/exclusion results from the old and the new methods. Migration Tracking: --- Cargo.lock | 57 +++++++++++ Cargo.toml | 1 + src/cargo/lib.rs | 1 + src/cargo/sources/path.rs | 200 +++++++++++++++++++++++++++++++------- src/cargo/util/errors.rs | 3 + tests/package.rs | 117 +++++++++++++++++++++- 6 files changed, 342 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 306ede34e43..6205be6e6c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -251,6 +252,11 @@ dependencies = [ "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fnv" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "foreign-types" version = "0.2.0" @@ -300,6 +306,18 @@ name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "globset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hamcrest" version = "0.1.1" @@ -324,6 +342,21 @@ dependencies = [ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ignore" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.3.1" @@ -630,6 +663,15 @@ name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scoped-tls" version = "0.1.0" @@ -847,6 +889,16 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -896,15 +948,18 @@ dependencies = [ "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" +"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866" "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" "checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee" "checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3" "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" +"checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -942,6 +997,7 @@ dependencies = [ "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -971,6 +1027,7 @@ dependencies = [ "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a39ee4464208f6430992ff20154216ab2357772ac871d994c51628d60e58b8b0" diff --git a/Cargo.toml b/Cargo.toml index d7ea2ccfbc8..263f061de3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ git2 = "0.6" git2-curl = "0.7" glob = "0.2" hex = "0.2" +ignore = "^0.2.2" jobserver = "0.1.6" libc = "0.2" libgit2-sys = "0.6" diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 5a1c3de149c..1b96813433b 100755 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -19,6 +19,7 @@ extern crate fs2; extern crate git2; extern crate glob; extern crate hex; +extern crate ignore; extern crate jobserver; extern crate libc; extern crate libgit2_sys; diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 7a21713f49a..317133f0b70 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -5,6 +5,8 @@ use std::path::{Path, PathBuf}; use filetime::FileTime; use git2; use glob::Pattern; +use ignore::Match; +use ignore::gitignore::GitignoreBuilder; use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry}; use ops; @@ -85,42 +87,163 @@ impl<'cfg> PathSource<'cfg> { /// The basic assumption of this method is that all files in the directory /// are relevant for building this package, but it also contains logic to /// use other methods like .gitignore to filter the list of files. + /// + /// ## Pattern matching strategy + /// + /// Migrating from a glob-like pattern matching (using `glob` crate) to a + /// gitignore-like pattern matching (using `ignore` crate). The migration + /// stages are: + /// + /// 1) Only warn users about the future change iff their matching rules are + /// affected. (CURRENT STAGE) + /// + /// 2) Switch to the new strategy and upate documents. Still keep warning + /// affected users. + /// + /// 3) Drop the old strategy and no mor warnings. + /// + /// See for more info. pub fn list_files(&self, pkg: &Package) -> CargoResult> { let root = pkg.root(); + let no_include_option = pkg.manifest().include().is_empty(); + + // glob-like matching rules - let parse = |p: &String| { + let glob_parse = |p: &String| { Pattern::new(p).map_err(|e| { - CargoError::from(format!("could not parse pattern `{}`: {}", p, e)) + CargoError::from(format!("could not parse glob pattern `{}`: {}", p, e)) }) }; - let exclude = pkg.manifest() - .exclude() - .iter() - .map(|p| parse(p)) - .collect::, _>>()?; - - let include = pkg.manifest() - .include() - .iter() - .map(|p| parse(p)) - .collect::, _>>()?; - - let mut filter = |p: &Path| { - let relative_path = util::without_prefix(p, root).unwrap(); - include.iter().any(|p| p.matches_path(relative_path)) || { - include.is_empty() && - !exclude.iter().any(|p| p.matches_path(relative_path)) + let glob_exclude = pkg.manifest() + .exclude() + .iter() + .map(|p| glob_parse(p)) + .collect::, _>>()?; + + let glob_include = pkg.manifest() + .include() + .iter() + .map(|p| glob_parse(p)) + .collect::, _>>()?; + + let glob_should_package = |relative_path: &Path| -> bool { + // include and exclude options are mutually exclusive. + if no_include_option { + !glob_exclude.iter().any(|pattern| { + pattern.matches_path(relative_path) + }) + } else { + glob_include.iter().any(|pattern| { + pattern.matches_path(relative_path) + }) + } + }; + + // ignore-like matching rules + + let mut exclude_builder = GitignoreBuilder::new(root); + for rule in pkg.manifest().exclude() { + exclude_builder.add_line(None, rule)?; + } + let ignore_exclude = exclude_builder.build()?; + + let mut include_builder = GitignoreBuilder::new(root); + for rule in pkg.manifest().include() { + include_builder.add_line(None, rule)?; + } + let ignore_include = include_builder.build()?; + + let ignore_should_package = |relative_path: &Path| -> CargoResult { + // include and exclude options are mutually exclusive. + if no_include_option { + match ignore_exclude.matched_path_or_any_parents( + relative_path, + /* is_dir */ false, + ) { + Match::None => Ok(true), + Match::Ignore(_) => Ok(false), + Match::Whitelist(pattern) => Err(CargoError::from(format!( + "exclude rules cannot start with `!`: {}", + pattern.original() + ))), + } + } else { + match ignore_include.matched_path_or_any_parents( + relative_path, + /* is_dir */ false, + ) { + Match::None => Ok(false), + Match::Ignore(_) => Ok(true), + Match::Whitelist(pattern) => Err(CargoError::from(format!( + "include rules cannot start with `!`: {}", + pattern.original() + ))), + } + } + }; + + // matching to paths + + let mut filter = |path: &Path| -> CargoResult { + let relative_path = util::without_prefix(path, root).unwrap(); + let glob_should_package = glob_should_package(relative_path); + let ignore_should_package = ignore_should_package(relative_path)?; + + if glob_should_package != ignore_should_package { + if glob_should_package { + if no_include_option { + self.config + .shell() + .warn(format!( + "Pattern matching for Cargo's include/exclude fields is changing and \ + file `{}` WILL be excluded in the next Cargo version.\n\ + See https://github.com/rust-lang/cargo/issues/4268 for more info", + relative_path.display() + ))?; + } else { + self.config + .shell() + .warn(format!( + "Pattern matching for Cargo's include/exclude fields is changing and \ + file `{}` WILL NOT be included in the next Cargo version.\n\ + See https://github.com/rust-lang/cargo/issues/4268 for more info", + relative_path.display() + ))?; + } + } else { + if no_include_option { + self.config + .shell() + .warn(format!( + "Pattern matching for Cargo's include/exclude fields is changing and \ + file `{}` WILL NOT be excluded in the next Cargo version.\n\ + See https://github.com/rust-lang/cargo/issues/4268 for more info", + relative_path.display() + ))?; + } else { + self.config + .shell() + .warn(format!( + "Pattern matching for Cargo's include/exclude fields is changing and \ + file `{}` WILL be included in the next Cargo version.\n\ + See https://github.com/rust-lang/cargo/issues/4268 for more info", + relative_path.display() + ))?; + } + } } + + // Update to ignore_should_package for Stage 2 + Ok(glob_should_package) }; // attempt git-prepopulate only if no `include` (rust-lang/cargo#4135) - if include.is_empty() { + if no_include_option { if let Some(result) = self.discover_git_and_list_files(pkg, root, &mut filter) { return result; } } - self.list_files_walk(pkg, &mut filter) } @@ -129,7 +252,7 @@ impl<'cfg> PathSource<'cfg> { fn discover_git_and_list_files(&self, pkg: &Package, root: &Path, - filter: &mut FnMut(&Path) -> bool) + filter: &mut FnMut(&Path) -> CargoResult) -> Option>> { // If this package is in a git repository, then we really do want to // query the git repository as it takes into account items such as @@ -170,7 +293,7 @@ impl<'cfg> PathSource<'cfg> { } fn list_files_git(&self, pkg: &Package, repo: git2::Repository, - filter: &mut FnMut(&Path) -> bool) + filter: &mut FnMut(&Path) -> CargoResult) -> CargoResult> { warn!("list_files_git {}", pkg.package_id()); let index = repo.index()?; @@ -202,7 +325,7 @@ impl<'cfg> PathSource<'cfg> { let untracked = statuses.iter().filter_map(|entry| { match entry.status() { git2::STATUS_WT_NEW => Some((join(root, entry.path_bytes()), None)), - _ => None + _ => None, } }); @@ -262,11 +385,10 @@ impl<'cfg> PathSource<'cfg> { ret.extend(files.into_iter()); } Err(..) => { - PathSource::walk(&file_path, &mut ret, false, - filter)?; + PathSource::walk(&file_path, &mut ret, false, filter)?; } } - } else if (*filter)(&file_path) { + } else if (*filter)(&file_path)? { // We found a file! warn!(" found {}", file_path.display()); ret.push(file_path); @@ -291,7 +413,7 @@ impl<'cfg> PathSource<'cfg> { } } - fn list_files_walk(&self, pkg: &Package, filter: &mut FnMut(&Path) -> bool) + fn list_files_walk(&self, pkg: &Package, filter: &mut FnMut(&Path) -> CargoResult) -> CargoResult> { let mut ret = Vec::new(); PathSource::walk(pkg.root(), &mut ret, true, filter)?; @@ -299,10 +421,11 @@ impl<'cfg> PathSource<'cfg> { } fn walk(path: &Path, ret: &mut Vec, - is_root: bool, filter: &mut FnMut(&Path) -> bool) -> CargoResult<()> + is_root: bool, filter: &mut FnMut(&Path) -> CargoResult) + -> CargoResult<()> { if !fs::metadata(&path).map(|m| m.is_dir()).unwrap_or(false) { - if (*filter)(path) { + if (*filter)(path)? { ret.push(path.to_path_buf()); } return Ok(()) @@ -311,9 +434,18 @@ impl<'cfg> PathSource<'cfg> { if !is_root && fs::metadata(&path.join("Cargo.toml")).is_ok() { return Ok(()) } - for dir in fs::read_dir(path)? { - let dir = dir?.path(); - let name = dir.file_name().and_then(|s| s.to_str()); + + // For package integration tests, we need to sort the paths in a deterministic order to + // be able to match stdout warnings in the same order. + // + // TODO: Drop collect and sort after transition period and dropping wraning tests. + // See + // and + let mut entries: Vec = fs::read_dir(path)?.map(|e| e.unwrap()).collect(); + entries.sort_by(|a, b| a.path().as_os_str().cmp(b.path().as_os_str())); + for entry in entries { + let path = entry.path(); + let name = path.file_name().and_then(|s| s.to_str()); // Skip dotfile directories if name.map(|s| s.starts_with('.')) == Some(true) { continue @@ -324,7 +456,7 @@ impl<'cfg> PathSource<'cfg> { _ => {} } } - PathSource::walk(&dir, ret, false, filter)?; + PathSource::walk(&path, ret, false, filter)?; } Ok(()) } diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index dd748a459b7..0f4cd4cb4c2 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -14,6 +14,7 @@ use semver; use serde_json; use toml; use registry; +use ignore; error_chain! { types { @@ -27,6 +28,7 @@ error_chain! { foreign_links { ParseSemver(semver::ReqParseError); Semver(semver::SemVerError); + Ignore(ignore::Error); Io(io::Error); SerdeJson(serde_json::Error); TomlSer(toml::ser::Error); @@ -74,6 +76,7 @@ impl CargoError { &CargoErrorKind::CrateRegistry(_) => true, &CargoErrorKind::ParseSemver(_) | &CargoErrorKind::Semver(_) | + &CargoErrorKind::Ignore(_) | &CargoErrorKind::Io(_) | &CargoErrorKind::SerdeJson(_) | &CargoErrorKind::ParseInt(_) | diff --git a/tests/package.rs b/tests/package.rs index d54fdc2375a..1a01ac0cdb8 100644 --- a/tests/package.rs +++ b/tests/package.rs @@ -251,21 +251,132 @@ fn exclude() { name = "foo" version = "0.0.1" authors = [] - exclude = ["*.txt"] + exclude = [ + "*.txt", + # file in root + "file_root_1", # NO_CHANGE (ignored) + "/file_root_2", # CHANGING (packaged -> ignored) + "file_root_3/", # NO_CHANGE (packaged) + "file_root_4/*", # NO_CHANGE (packaged) + "file_root_5/**", # NO_CHANGE (packaged) + # file in sub-dir + "file_deep_1", # CHANGING (packaged -> ignored) + "/file_deep_2", # NO_CHANGE (packaged) + "file_deep_3/", # NO_CHANGE (packaged) + "file_deep_4/*", # NO_CHANGE (packaged) + "file_deep_5/**", # NO_CHANGE (packaged) + # dir in root + "dir_root_1", # CHANGING (packaged -> ignored) + "/dir_root_2", # CHANGING (packaged -> ignored) + "dir_root_3/", # CHANGING (packaged -> ignored) + "dir_root_4/*", # NO_CHANGE (ignored) + "dir_root_5/**", # NO_CHANGE (ignored) + # dir in sub-dir + "dir_deep_1", # CHANGING (packaged -> ignored) + "/dir_deep_2", # NO_CHANGE + "dir_deep_3/", # CHANGING (packaged -> ignored) + "dir_deep_4/*", # CHANGING (packaged -> ignored) + "dir_deep_5/**", # CHANGING (packaged -> ignored) + ] "#) .file("src/main.rs", r#" fn main() { println!("hello"); } "#) .file("bar.txt", "") - .file("src/bar.txt", ""); + .file("src/bar.txt", "") + // file in root + .file("file_root_1", "") + .file("file_root_2", "") + .file("file_root_3", "") + .file("file_root_4", "") + .file("file_root_5", "") + // file in sub-dir + .file("some_dir/file_deep_1", "") + .file("some_dir/file_deep_2", "") + .file("some_dir/file_deep_3", "") + .file("some_dir/file_deep_4", "") + .file("some_dir/file_deep_5", "") + // dir in root + .file("dir_root_1/some_dir/file", "") + .file("dir_root_2/some_dir/file", "") + .file("dir_root_3/some_dir/file", "") + .file("dir_root_4/some_dir/file", "") + .file("dir_root_5/some_dir/file", "") + // dir in sub-dir + .file("some_dir/dir_deep_1/some_dir/file", "") + .file("some_dir/dir_deep_2/some_dir/file", "") + .file("some_dir/dir_deep_3/some_dir/file", "") + .file("some_dir/dir_deep_4/some_dir/file", "") + .file("some_dir/dir_deep_5/some_dir/file", "") + ; assert_that(p.cargo_process("package").arg("--no-verify").arg("-v"), - execs().with_status(0).with_stderr("\ + execs().with_status(0).with_stdout("").with_stderr("\ [WARNING] manifest has no description[..] See http://doc.crates.io/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([..]) +[WARNING] [..] file `dir_root_1[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `dir_root_2[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `dir_root_3[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `file_root_2` WILL be excluded [..] +See [..] +[WARNING] [..] file `some_dir[/]dir_deep_1[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `some_dir[/]dir_deep_3[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `some_dir[/]dir_deep_4[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `some_dir[/]dir_deep_5[/]some_dir[/]file` WILL be excluded [..] +See [..] +[WARNING] [..] file `some_dir[/]file_deep_1` WILL be excluded [..] +See [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] [ARCHIVING] [..] [ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +[ARCHIVING] [..] +")); + + 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 +dir_root_1[/]some_dir[/]file +dir_root_2[/]some_dir[/]file +dir_root_3[/]some_dir[/]file +file_root_2 +file_root_3 +file_root_4 +file_root_5 +some_dir[/]dir_deep_1[/]some_dir[/]file +some_dir[/]dir_deep_2[/]some_dir[/]file +some_dir[/]dir_deep_3[/]some_dir[/]file +some_dir[/]dir_deep_4[/]some_dir[/]file +some_dir[/]dir_deep_5[/]some_dir[/]file +some_dir[/]file_deep_1 +some_dir[/]file_deep_2 +some_dir[/]file_deep_3 +some_dir[/]file_deep_4 +some_dir[/]file_deep_5 +src[/]main.rs ")); }