Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 4135: include = [...] should override git file list #4180

Merged
merged 3 commits into from
Jun 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ impl<'cfg> PathSource<'cfg> {
}
};

// attempt git-prepopulate only if no `include` (rust-lang/cargo#4135)
if include.is_empty() {
if let Some(result) = self.discover_git_and_list_files(pkg, root, &mut filter) {
return result;
}
}

self.list_files_walk(pkg, &mut filter)
}

// Returns Some(_) if found sibling Cargo.toml and .git folder;
// otherwise caller should fall back on full file list.
fn discover_git_and_list_files(&self,
pkg: &Package,
root: &Path,
filter: &mut FnMut(&Path) -> bool)
-> Option<CargoResult<Vec<PathBuf>>> {
// 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
// .gitignore. We're not quite sure where the git repository is,
Expand All @@ -129,11 +146,14 @@ impl<'cfg> PathSource<'cfg> {
// check to see if we are indeed part of the index. If not, then
// this is likely an unrelated git repo, so keep going.
if let Ok(repo) = git2::Repository::open(cur) {
let index = repo.index()?;
let index = match repo.index() {
Ok(index) => index,
Err(err) => return Some(Err(err.into())),
};
let path = util::without_prefix(root, cur)
.unwrap().join("Cargo.toml");
if index.get_path(&path, 0).is_some() {
return self.list_files_git(pkg, repo, &mut filter);
return Some(self.list_files_git(pkg, repo, filter));
}
}
}
Expand All @@ -146,7 +166,7 @@ impl<'cfg> PathSource<'cfg> {
None => break,
}
}
self.list_files_walk(pkg, &mut filter)
return None;
}

fn list_files_git(&self, pkg: &Package, repo: git2::Repository,
Expand Down
113 changes: 113 additions & 0 deletions tests/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1984,3 +1984,116 @@ fn two_at_rev_instead_of_tag() {
assert_that(p.cargo_process("generate-lockfile"), execs().with_status(0));
assert_that(p.cargo("build").arg("-v"), execs().with_status(0));
}

#[test]
fn include_overrides_gitignore() {
let p = git::new("reduction", |repo| {
repo.file("Cargo.toml", r#"
[package]
name = "reduction"
version = "0.5.0"
authors = ["pnkfelix"]
build = "tango-build.rs"
include = ["src/lib.rs", "src/incl.rs", "src/mod.md", "tango-build.rs", "Cargo.toml"]

[build-dependencies]
filetime = "0.1"
"#)
.file(".gitignore", r#"
target
Cargo.lock
# Below files represent generated code, thus not managed by `git`
src/incl.rs
src/not_incl.rs
"#)
.file("tango-build.rs", r#"
extern crate filetime;
use filetime::FileTime;
use std::fs::{self, File};

fn main() {
// generate files, or bring their timestamps into sync.
let source = "src/mod.md";

let metadata = fs::metadata(source).unwrap();
let mtime = FileTime::from_last_modification_time(&metadata);
let atime = FileTime::from_last_access_time(&metadata);

// sync time stamps for generated files with time stamp of source file.

let files = ["src/not_incl.rs", "src/incl.rs"];
for file in files.iter() {
File::create(file).unwrap();
filetime::set_file_times(file, atime, mtime).unwrap();
}
}
"#)
.file("src/lib.rs", r#"
mod not_incl;
mod incl;
"#)
.file("src/mod.md", r#"
(The content of this file does not matter since we are not doing real codegen.)
"#)
}).unwrap();

println!("build 1: all is new");
assert_that(p.cargo("build").arg("-v"),
execs().with_status(0)
.with_stderr("\
[UPDATING] registry `[..]`
[DOWNLOADING] filetime [..]
[DOWNLOADING] libc [..]
[COMPILING] libc [..]
[RUNNING] `rustc --crate-name libc [..]`
[COMPILING] filetime [..]
[RUNNING] `rustc --crate-name filetime [..]`
[COMPILING] reduction [..]
[RUNNING] `rustc --crate-name build_script_tango_build tango-build.rs --crate-type bin [..]`
[RUNNING] `[..][/]build-script-tango-build`
[RUNNING] `rustc --crate-name reduction src[/]lib.rs --crate-type lib [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
"));

println!("build 2: nothing changed; file timestamps reset by build script");
assert_that(p.cargo("build").arg("-v"),
execs().with_status(0)
.with_stderr("\
[FRESH] libc [..]
[FRESH] filetime [..]
[FRESH] reduction [..]
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
"));

println!("build 3: touch `src/not_incl.rs`; expect build script *not* re-run");
sleep_ms(1000);
File::create(p.root().join("src").join("not_incl.rs")).unwrap();

assert_that(p.cargo("build").arg("-v"),
execs().with_status(0)
.with_stderr("\
[FRESH] libc [..]
[FRESH] filetime [..]
[COMPILING] reduction [..]
[RUNNING] `rustc --crate-name reduction src[/]lib.rs --crate-type lib [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
"));

// This final case models the bug from rust-lang/cargo#4135: an
// explicitly included file should cause a build-script re-run,
// even if that same file is matched by `.gitignore`.
println!("build 4: touch `src/incl.rs`; expect build script re-run");
sleep_ms(1000);
File::create(p.root().join("src").join("incl.rs")).unwrap();

assert_that(p.cargo("build").arg("-v"),
execs().with_status(0)
.with_stderr("\
[FRESH] libc [..]
[FRESH] filetime [..]
[COMPILING] reduction [..]
[RUNNING] `[..][/]build-script-tango-build`
[RUNNING] `rustc --crate-name reduction src[/]lib.rs --crate-type lib [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
"));
}