Skip to content

Commit

Permalink
[path] Also match parent dirs in include/exclude
Browse files Browse the repository at this point in the history
NOTE: This is a major change in pattern matching for `include` and
`exclude` fields, and can result in additional inclusion/exclusion for
some patterns.

Previously, for inclusion/exclusion matters, Cargo only works with paths
of files in a package/repository, and glob pattern matching has been
applying only to these file paths.

The old behavior results in some unexpected behavior. For example,
having:

```toml
exclude = ["data"]
```

in a manifest next to a `data` directory, it will not exclude the
directory. To make it work, a pattern must be provided that matches the
*files* under this directory, like:

```toml
exclude = ["data/*"]
```

To make Cargo's inclusion/exclusion behavior more intutional, and bring
it on par with similar systems, like `gitignore`, we need to also match
these patterns with the *directories*. The directories are seen
internally as *parents* of the files. Therefore, this diff expands the
pattern matching to files and their parent directories.

Now, it's easier to exclude all data files:

```toml
exclude = ["data"]
```

or include only the `src` directory:

```toml
include = ["src"]
```

Fixes <rust-lang#3578>
  • Loading branch information
behnam committed Jul 7, 2017
1 parent cc8aa6f commit 454cbd1
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 5 deletions.
22 changes: 19 additions & 3 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,27 @@ impl<'cfg> PathSource<'cfg> {
.map(|p| parse(p))
.collect::<Result<Vec<_>, _>>()?;

fn matches_path_or_parents(pattern: &Pattern, target: &Path) -> bool {
if pattern.matches_path(target) {
return true;
}
let mut current = target;
while let Some(parent) = current.parent() {
if pattern.matches_path(parent) {
return true;
}
current = parent;
}
false
}

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))
// mutually exclusive: setting include will override exclude
if include.is_empty() {
!exclude.iter().any(|exc| matches_path_or_parents(exc, relative_path))
} else {
include.iter().any(|inc| matches_path_or_parents(inc, relative_path))
}
};

Expand Down
24 changes: 22 additions & 2 deletions tests/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,23 @@ fn exclude() {
name = "foo"
version = "0.0.1"
authors = []
exclude = ["*.txt"]
exclude = [
"*.txt",
"data1",
"data2/", # Does NOT match
"data3/*",
"data4/**",
]
"#)
.file("src/main.rs", r#"
fn main() { println!("hello"); }
"#)
.file("bar.txt", "")
.file("src/bar.txt", "");
.file("src/bar.txt", "")
.file("data1/hello1.bin", "")
.file("data2/hello2.bin", "")
.file("data3/hello3.bin", "")
.file("data4/hello4.bin", "");

assert_that(p.cargo_process("package").arg("--no-verify").arg("-v"),
execs().with_status(0).with_stderr("\
Expand All @@ -266,6 +276,16 @@ See http://doc.crates.io/manifest.html#package-metadata for more info.
[PACKAGING] foo v0.0.1 ([..])
[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
data2[/]hello2.bin
src[/]main.rs
"));
}

Expand Down

0 comments on commit 454cbd1

Please sign in to comment.