Skip to content

Commit

Permalink
Clean up code around the crawling of a directory
Browse files Browse the repository at this point in the history
The logic for "not recursing into `target`" was pretty hokey and needed
replacement. This commit also unfies the paths a bit to ensure that the main
loop is the same part that adds the root package itself.

This reorganization ends up closing rust-lang#937
  • Loading branch information
alexcrichton committed Nov 25, 2014
1 parent e91d128 commit c84bc16
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 48 deletions.
9 changes: 9 additions & 0 deletions src/cargo/core/package.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt::{mod, Show, Formatter};
use std::hash;
use std::slice;
use semver::Version;

Expand Down Expand Up @@ -128,6 +129,14 @@ impl PartialEq for Package {
}
}

impl Eq for Package {}

impl hash::Hash for Package {
fn hash(&self, into: &mut hash::sip::SipState) {
self.get_package_id().hash(into)
}
}

#[deriving(PartialEq,Clone,Show)]
pub struct PackageSet {
packages: Vec<Package>,
Expand Down
71 changes: 30 additions & 41 deletions src/cargo/ops/cargo_read_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,44 @@ pub fn read_package(path: &Path, source_id: &SourceId)

pub fn read_packages(path: &Path,
source_id: &SourceId) -> CargoResult<Vec<Package>> {
let mut all_packages = Vec::new();
let mut all_packages = HashSet::new();
let mut visited = HashSet::<Path>::new();

log!(5, "looking for root package: {}, source_id={}", path.display(), source_id);
try!(process_possible_package(path, &mut all_packages, source_id, &mut visited));

try!(walk(path, true, |root, dir| {
try!(walk(path, |dir| {
log!(5, "looking for child package: {}", dir.display());
if root && dir.join("target").is_dir() { return Ok(false); }
if root { return Ok(true) }

// Don't recurse into git databases
if dir.filename_str() == Some(".git") { return Ok(false); }
if dir.join(".git").exists() { return Ok(false); }
try!(process_possible_package(dir, &mut all_packages, source_id,

// Don't automatically discover packages across git submodules
if dir != path && dir.join(".git").exists() { return Ok(false); }

// Don't ever look at target directories
if dir.filename_str() == Some("target") && has_manifest(&dir.dir_path()) {
return Ok(false)
}

if has_manifest(dir) {
try!(read_nested_packages(dir, &mut all_packages, source_id,
&mut visited));
}
Ok(true)
}));

if all_packages.is_empty() {
Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
} else {
log!(5, "all packages: {}", all_packages);
Ok(all_packages)
Ok(all_packages.into_iter().collect())
}
}

fn walk(path: &Path, is_root: bool,
callback: |bool, &Path| -> CargoResult<bool>) -> CargoResult<()> {
fn walk(path: &Path,
callback: |&Path| -> CargoResult<bool>) -> CargoResult<()> {
if path.is_dir() {
let continues = try!(callback(is_root, path));
let continues = try!(callback(path));
if !continues {
log!(5, "not processing {}", path.display());
return Ok(());
Expand All @@ -69,56 +78,36 @@ fn walk(path: &Path, is_root: bool,
Err(e) => return Err(FromError::from_error(e)),
};
for dir in dirs.iter() {
try!(walk(dir, false, |a, x| callback(a, x)))
try!(walk(dir, |x| callback(x)))
}
}

Ok(())
}

fn process_possible_package(dir: &Path,
all_packages: &mut Vec<Package>,
source_id: &SourceId,
visited: &mut HashSet<Path>) -> CargoResult<()> {

if !has_manifest(dir) { return Ok(()); }

let packages = try!(read_nested_packages(dir, source_id, visited));
push_all(all_packages, packages);

Ok(())
}

fn has_manifest(path: &Path) -> bool {
find_project_manifest_exact(path, "Cargo.toml").is_ok()
}

fn read_nested_packages(path: &Path, source_id: &SourceId,
visited: &mut HashSet<Path>) -> CargoResult<Vec<Package>> {
if !visited.insert(path.clone()) { return Ok(Vec::new()) }
fn read_nested_packages(path: &Path,
all_packages: &mut HashSet<Package>,
source_id: &SourceId,
visited: &mut HashSet<Path>) -> CargoResult<()> {
if !visited.insert(path.clone()) { return Ok(()) }

let manifest = try!(find_project_manifest_exact(path, "Cargo.toml"));

let (pkg, nested) = try!(read_package(&manifest, source_id));
let mut ret = vec![pkg];
all_packages.insert(pkg);

// Registry sources are not allowed to have `path=` dependencies because
// they're all translated to actual registry dependencies.
if !source_id.is_registry() {
for p in nested.iter() {
ret.extend(try!(read_nested_packages(&path.join(p),
source_id,
visited)).into_iter());
try!(read_nested_packages(&path.join(p), all_packages, source_id,
visited));
}
}

Ok(ret)
}

fn push_all(set: &mut Vec<Package>, packages: Vec<Package>) {
for package in packages.into_iter() {
if set.contains(&package) { continue; }

set.push(package)
}
Ok(())
}
2 changes: 1 addition & 1 deletion src/cargo/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
(d.get_name(), d)
}).collect::<HashMap<_, _>>();
summary.map_dependencies(|d| {
match map.find_equiv(d.get_name()) {
match map.get(d.get_name()) {
Some(&lock) if d.matches_id(lock) => d.lock_to(lock),
_ => d,
}
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl PathSource {
return Err(internal("source has not been updated"))
}

match self.packages.as_slice().head() {
match self.packages.iter().find(|p| p.get_root() == self.path) {
Some(pkg) => Ok(pkg.clone()),
None => Err(internal("no package found in source"))
}
Expand Down
2 changes: 1 addition & 1 deletion src/rustversion.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2014-11-22
2014-11-24
1 change: 1 addition & 0 deletions tests/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,4 @@ pub static PACKAGING: &'static str = " Packaging";
pub static DOWNLOADING: &'static str = " Downloading";
pub static UPLOADING: &'static str = " Uploading";
pub static VERIFYING: &'static str = " Verifying";
pub static ARCHIVING: &'static str = " Archiving";
4 changes: 2 additions & 2 deletions tests/test_cargo_compile_custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ test!(links_duplicates {
native library `a` is being linked to by more than one package, and can only be \
linked to by one package
foo v0.5.0 (file://[..])
a v0.5.0 (file://[..])
[..] v0.5.0 (file://[..])
[..] v0.5.0 (file://[..])
"));
})

Expand Down
39 changes: 37 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::io::{File, MemReader};

use tar::Archive;
use flate2::reader::GzDecoder;
use cargo::util::process;

use support::{project, execs, cargo_dir, ResultTest};
use support::{PACKAGING, VERIFYING, COMPILING};
use support::{project, execs, cargo_dir, ResultTest, paths, git};
use support::{PACKAGING, VERIFYING, COMPILING, ARCHIVING};
use hamcrest::{assert_that, existing_file};

fn setup() {
Expand Down Expand Up @@ -128,7 +129,41 @@ test!(metadata_warning {
verifying = VERIFYING,
compiling = COMPILING,
dir = p.url()).as_slice()));
})

test!(package_verbose {
let root = paths::root().join("all");
let p = git::repo(&root)
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("a/Cargo.toml", r#"
[project]
name = "a"
version = "0.0.1"
authors = []
"#)
.file("a/src/lib.rs", "");
p.build();
let cargo = process(cargo_dir().join("cargo")).unwrap()
.cwd(root)
.env("HOME", Some(paths::home()));
assert_that(cargo.clone().arg("build"), execs().with_status(0));
assert_that(cargo.arg("package").arg("-v")
.arg("--no-verify"),
execs().with_status(0).with_stdout(format!("\
{packaging} foo v0.0.1 ([..])
{archiving} [..]
{archiving} [..]
",
packaging = PACKAGING,
archiving = ARCHIVING).as_slice()));
})

test!(package_verification {
Expand Down

2 comments on commit c84bc16

@alexcrichton
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=brson

@alexcrichton
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors: retry

Please sign in to comment.