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

Scan untracked files in git for packaging/deps #1584

Merged
merged 1 commit into from
May 5, 2015
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
116 changes: 65 additions & 51 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,35 +123,49 @@ impl<'a, 'b> PathSource<'a, 'b> {
.next();
match repo {
Some(repo) => self.list_files_git(pkg, repo, &mut filter),
None => self.list_files_walk(pkg, filter),
None => self.list_files_walk(pkg, &mut filter),
}
}

fn list_files_git<F>(&self, pkg: &Package, repo: git2::Repository,
filter: &mut F)
-> CargoResult<Vec<PathBuf>>
where F: FnMut(&Path) -> bool
{
fn list_files_git(&self, pkg: &Package, repo: git2::Repository,
filter: &mut FnMut(&Path) -> bool)
-> CargoResult<Vec<PathBuf>> {
warn!("list_files_git {}", pkg.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 root = try!(repo.workdir().chain_error(|| {
internal_error("Can't list files on a bare repository.", "")
}));
let pkg_path = pkg.root();

let mut ret = Vec::new();
'outer: for entry in index.iter() {
let fname = &entry.path[..];
let file_path = try!(join(&root, fname));

// We use information from the git repository to guide use in traversing
// its tree. The primary purpose of this is to take advantage of the
// .gitignore and auto-ignore files that don't matter.
//
// Here we're also careful to look at both tracked an untracked files as
// the untracked files are often part of a build and may become relevant
// as part of a future commit.
let index_files = index.iter().map(|entry| join(&root, &entry.path));
let mut opts = git2::StatusOptions::new();
opts.include_untracked(true);
let statuses = try!(repo.statuses(Some(&mut opts)));
let untracked = statuses.iter().map(|entry| {
join(&root, entry.path_bytes())
});

'outer: for file_path in index_files.chain(untracked) {
let file_path = try!(file_path);

// Filter out files outside this package.
if !file_path.starts_with(pkg_path) { continue }

// Filter out Cargo.lock and target always
if fname == b"Cargo.lock" { continue }
if fname == b"target" { continue }
{
let fname = file_path.file_name().and_then(|s| s.to_str());
if fname == Some("Cargo.lock") { continue }
if fname == Some("target") { continue }
}

// Filter out sub-packages of this package
for other_pkg in self.packages.iter().filter(|p| *p != pkg) {
Expand All @@ -173,13 +187,16 @@ impl<'a, 'b> PathSource<'a, 'b> {
// Git submodules are currently only named through `/` path
// separators, explicitly not `\` which windows uses. Who knew?
let rel = rel.replace(r"\", "/");
let submodule = try!(repo.find_submodule(&rel));
let repo = match submodule.open() {
Ok(repo) => repo,
Err(..) => continue,
};
let files = try!(self.list_files_git(pkg, repo, filter));
ret.extend(files.into_iter());
match repo.find_submodule(&rel).and_then(|s| s.open()) {
Ok(repo) => {
let files = try!(self.list_files_git(pkg, repo, filter));
ret.extend(files.into_iter());
}
Err(..) => {
try!(PathSource::walk(&file_path, &mut ret, false,
filter));
}
}
} else if (*filter)(&file_path) {
// We found a file!
warn!(" found {}", file_path.display());
Expand All @@ -205,43 +222,40 @@ impl<'a, 'b> PathSource<'a, 'b> {
}
}

fn list_files_walk<F>(&self, pkg: &Package, mut filter: F)
-> CargoResult<Vec<PathBuf>>
where F: FnMut(&Path) -> bool
{
fn list_files_walk(&self, pkg: &Package, filter: &mut FnMut(&Path) -> bool)
-> CargoResult<Vec<PathBuf>> {
let mut ret = Vec::new();
for pkg in self.packages.iter().filter(|p| *p == pkg) {
let loc = pkg.root();
try!(walk(loc, &mut ret, true, &mut filter));
try!(PathSource::walk(loc, &mut ret, true, filter));
}
return Ok(ret);
}

fn walk<F>(path: &Path, ret: &mut Vec<PathBuf>,
is_root: bool, filter: &mut F) -> CargoResult<()>
where F: FnMut(&Path) -> bool
{
if !fs::metadata(&path).map(|m| m.is_dir()).unwrap_or(false) {
if (*filter)(path) {
ret.push(path.to_path_buf());
}
return Ok(())
}
// Don't recurse into any sub-packages that we have
if !is_root && fs::metadata(&path.join("Cargo.toml")).is_ok() {
return Ok(())
}
for dir in try!(fs::read_dir(path)) {
let dir = try!(dir).path();
match (is_root, dir.file_name().and_then(|s| s.to_str())) {
(_, Some(".git")) |
(true, Some("target")) |
(true, Some("Cargo.lock")) => continue,
_ => {}
}
try!(walk(&dir, ret, false, filter));
fn walk(path: &Path, ret: &mut Vec<PathBuf>,
is_root: bool, filter: &mut FnMut(&Path) -> bool) -> CargoResult<()>
{
if !fs::metadata(&path).map(|m| m.is_dir()).unwrap_or(false) {
if (*filter)(path) {
ret.push(path.to_path_buf());
}
return Ok(())
}
// Don't recurse into any sub-packages that we have
if !is_root && fs::metadata(&path.join("Cargo.toml")).is_ok() {
return Ok(())
}
for dir in try!(fs::read_dir(path)) {
let dir = try!(dir).path();
match (is_root, dir.file_name().and_then(|s| s.to_str())) {
(_, Some(".git")) |
(true, Some("target")) |
(true, Some("Cargo.lock")) => continue,
_ => {}
}
try!(PathSource::walk(&dir, ret, false, filter));
}
return Ok(())
}
}

Expand Down
25 changes: 23 additions & 2 deletions tests/test_cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use std::fs::File;
use std::io::Cursor;
use std::io::prelude::*;

use tar::Archive;
use flate2::read::GzDecoder;
use cargo::util::process;
use flate2::read::GzDecoder;
use git2;
use tar::Archive;

use support::{project, execs, cargo_dir, paths, git};
use support::{PACKAGING, VERIFYING, COMPILING, ARCHIVING};
Expand Down Expand Up @@ -261,3 +262,23 @@ test!(package_lib_with_bin {
assert_that(p.cargo_process("package").arg("-v"),
execs().with_status(0));
});

test!(package_new_git_repo {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
"#)
.file("src/main.rs", "fn main() {}");
p.build();
git2::Repository::init(&p.root()).unwrap();

assert_that(p.process(cargo_dir().join("cargo")).arg("package")
.arg("--no-verify").arg("-v"),
execs().with_status(0).with_stdout(&format!("\
{packaging} foo v0.0.1 ([..])
{archiving} [..]
{archiving} [..]
", packaging = PACKAGING, archiving = ARCHIVING)));
});