auto merge of #563 : mbrubeck/cargo/list-files-git, r=alexcrichton

`list_files_git` assumes that the package is at the root of the git repository. This breaks when trying to list files for a package in a subdirectory of a repo, or in other cases, e.g. if the user's home directory is a git repo.
This commit is contained in:
bors 2014-09-13 02:43:50 +00:00
commit 287abd87d2
2 changed files with 92 additions and 9 deletions

View file

@ -69,16 +69,27 @@ impl PathSource {
/// are relevant for building this package, but it also contains logic to
/// use other methods like .gitignore to filter the list of files.
pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<Path>> {
let candidates = match git2::Repository::open(&self.path) {
let root = pkg.get_manifest_path().dir_path();
// Check whether the package itself is a git repository.
let candidates = match git2::Repository::open(&root) {
Ok(repo) => try!(self.list_files_git(pkg, repo)),
Err(..) => try!(self.list_files_walk(pkg)),
// If not, check whether the package is in a sub-directory of the main repository.
Err(..) if self.path.is_ancestor_of(&root) => {
match git2::Repository::open(&self.path) {
Ok(repo) => try!(self.list_files_git(pkg, repo)),
_ => try!(self.list_files_walk(pkg))
}
}
// If neither is true, fall back to walking the filesystem.
_ => try!(self.list_files_walk(pkg))
};
let pats = pkg.get_manifest().get_exclude().iter().map(|p| {
Pattern::new(p.as_slice())
}).collect::<Vec<Pattern>>();
let root = pkg.get_manifest_path().dir_path();
Ok(candidates.move_iter().filter(|candidate| {
let relative_path = candidate.path_relative_from(&root).unwrap();
!pats.iter().any(|p| p.matches_path(&relative_path)) &&
@ -88,25 +99,38 @@ impl PathSource {
fn list_files_git(&self, pkg: &Package, repo: git2::Repository)
-> CargoResult<Vec<Path>> {
warn!("list_files_git {}", pkg.get_package_id());
let index = try!(repo.index());
let root = match repo.workdir() {
Some(dir) => dir,
None => return Err(internal_error("Can't list files on a bare repository.", "")),
};
let pkg_path = pkg.get_manifest_path().dir_path();
let mut ret = Vec::new();
'outer: for i in range(0, index.len()) {
let entry = match index.get(i) { Some(e) => e, None => continue };
let fname = entry.path.as_bytes_no_nul();
let path = pkg.get_manifest_path().dir_path().join(fname);
let file_path = root.join(fname);
// Filter out files outside this package.
if !pkg_path.is_ancestor_of(&file_path) { continue }
// Filter out Cargo.lock and target always
if fname == b"Cargo.lock" { continue }
if fname == b"target" { continue }
// Filter out all other packages
for pkg in self.packages.iter().filter(|p| *p != pkg) {
let pkg_path = pkg.get_manifest_path().dir_path();
if pkg_path.is_ancestor_of(&path) { continue 'outer; }
// Filter out sub-packages of this package
for other_pkg in self.packages.iter().filter(|p| *p != pkg) {
let other_path = other_pkg.get_manifest_path().dir_path();
if pkg_path.is_ancestor_of(&other_path) && other_path.is_ancestor_of(&file_path) {
continue 'outer;
}
}
// We found a file!
ret.push(path);
warn!(" found {}", file_path.display());
ret.push(file_path);
}
Ok(ret)
}
@ -193,6 +217,7 @@ impl Source for PathSource {
// condition where this path was rm'ed - either way,
// we can ignore the error and treat the path's mtime
// as 0.
warn!("{} {}", file.stat().map(|s| s.modified).unwrap_or(0), file.display());
max = cmp::max(max, file.stat().map(|s| s.modified).unwrap_or(0));
}
log!(5, "fingerprint {}: {}", self.path.display(), max);

View file

@ -1143,3 +1143,61 @@ test!(git_repo_changing_no_rebuild {
assert_that(p1.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(""));
})
test!(git_dep_build_cmd {
let p = git_repo("foo", |project| {
project.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
version = "0.5.0"
path = "bar"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice())
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
build = "cp src/bar.rs.in src/bar.rs"
[lib]
name = "bar"
"#)
.file("bar/src/bar.rs.in", r#"
pub fn gimme() -> int { 0 }
"#)
}).assert();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0));
assert_that(
cargo::util::process(p.bin("foo")),
execs().with_stdout("0\n"));
// Touching bar.rs.in should cause the `build` command to run again.
let mut file = fs::File::create(&p.root().join("bar/src/bar.rs.in")).assert();
file.write_str(r#"pub fn gimme() -> int { 1 }"#).assert();
drop(file);
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0));
assert_that(
cargo::util::process(p.bin("foo")),
execs().with_stdout("1\n"));
})