}
pub fn generate_metadata(&self) -> Metadata {
- self.package_id().generate_metadata(self.root())
+ self.package_id().generate_metadata()
}
}
impl hash::Hash for Package {
fn hash<H: hash::Hasher>(&self, into: &mut H) {
- // We want to be sure that a path-based package showing up at the same
- // location always has the same hash. To that effect we don't hash the
- // vanilla package ID if we're a path, but instead feed in our own root
- // path.
- if self.package_id().source_id().is_path() {
- (0, self.root(), self.name(), self.package_id().version()).hash(into)
- } else {
- (1, self.package_id()).hash(into)
- }
+ self.package_id().hash(into)
}
}
use std::fmt::{self, Formatter};
use std::hash::Hash;
use std::hash;
-use std::path::Path;
use std::sync::Arc;
use regex::Regex;
pub fn version(&self) -> &semver::Version { &self.inner.version }
pub fn source_id(&self) -> &SourceId { &self.inner.source_id }
- pub fn generate_metadata(&self, source_root: &Path) -> Metadata {
- // See comments in Package::hash for why we have this test
- let metadata = if self.inner.source_id.is_path() {
- short_hash(&(0, &self.inner.name, &self.inner.version, source_root))
- } else {
- short_hash(&(1, self))
- };
+ pub fn generate_metadata(&self) -> Metadata {
+ let metadata = short_hash(self);
let extra_filename = format!("-{}", metadata);
Metadata { metadata: metadata, extra_filename: extra_filename }
try!(repo.copy_to(actual_rev.clone(), &self.checkout_path));
let source_id = self.source_id.with_precise(Some(actual_rev.to_string()));
- let path_source = PathSource::new(&self.checkout_path, &source_id,
- self.config);
+ let path_source = PathSource::new_recursive(&self.checkout_path,
+ &source_id,
+ self.config);
self.path_source = Some(path_source);
self.rev = Some(actual_rev);
updated: bool,
packages: Vec<Package>,
config: &'cfg Config,
+ recursive: bool,
}
-// TODO: Figure out if packages should be discovered in new or self should be
-// mut and packages are discovered in update
impl<'cfg> PathSource<'cfg> {
- pub fn for_path(path: &Path, config: &'cfg Config)
- -> CargoResult<PathSource<'cfg>> {
- trace!("PathSource::for_path; path={}", path.display());
- Ok(PathSource::new(path, &try!(SourceId::for_path(path)), config))
- }
-
/// Invoked with an absolute path to a directory that contains a Cargo.toml.
- /// The source will read the manifest and find any other packages contained
- /// in the directory structure reachable by the root manifest.
+ ///
+ /// This source will only return the package at precisely the `path`
+ /// specified, and it will be an error if there's not a package at `path`.
pub fn new(path: &Path, id: &SourceId, config: &'cfg Config)
-> PathSource<'cfg> {
- trace!("new; id={}", id);
-
PathSource {
id: id.clone(),
path: path.to_path_buf(),
updated: false,
packages: Vec::new(),
config: config,
+ recursive: false,
+ }
+ }
+
+ /// Creates a new source which is walked recursively to discover packages.
+ ///
+ /// This is similar to the `new` method except that instead of requiring a
+ /// valid package to be present at `root` the folder is walked entirely to
+ /// crawl for packages.
+ ///
+ /// Note that this should be used with care and likely shouldn't be chosen
+ /// by default!
+ pub fn new_recursive(root: &Path, id: &SourceId, config: &'cfg Config)
+ -> PathSource<'cfg> {
+ PathSource {
+ recursive: true,
+ .. PathSource::new(root, id, config)
}
}
pub fn read_packages(&self) -> CargoResult<Vec<Package>> {
if self.updated {
Ok(self.packages.clone())
- } else if (self.id.is_path() && self.id.precise().is_some()) ||
- self.id.is_registry() {
- // If our source id is a path and it's listed with a precise
- // version, then it means that we're not allowed to have nested
- // dependencies (they've been rewritten to crates.io dependencies).
- //
- // If our source id is a registry dependency then crates are
- // published one at a time so we don't recurse as well. Note that
- // cargo by default doesn't package up nested dependencies but it
- // may do so for custom-crafted tarballs.
- //
- // In these cases we specifically read just one package, not a list
- // of packages.
+ } else if self.recursive {
+ ops::read_packages(&self.path, &self.id, self.config)
+ } else {
let path = self.path.join("Cargo.toml");
let (pkg, _) = try!(ops::read_package(&path, &self.id,
self.config));
Ok(vec![pkg])
- } else {
- ops::read_packages(&self.path, &self.id, self.config)
}
}
config: &'b Config,
warnings: &'a mut Vec<String>,
platform: Option<Platform>,
+ layout: &'a Layout,
}
// These functions produce the equivalent of specific manifest entries. One
}
let pkgid = try!(project.to_package_id(source_id));
- let metadata = pkgid.generate_metadata(&layout.root);
+ let metadata = pkgid.generate_metadata();
// If we have no lib at all, use the inferred lib if available
// If we have a lib with a path, we're done
config: config,
warnings: &mut warnings,
platform: None,
+ layout: &layout,
};
// Collect the deps
Some(SourceId::for_git(&loc, reference))
}
None => {
- details.path.as_ref().map(|path| {
- cx.nested_paths.push(PathBuf::from(path));
- cx.source_id.clone()
- })
+ match details.path.as_ref() {
+ Some(path) => {
+ cx.nested_paths.push(PathBuf::from(path));
+ // If the source id for the package we're parsing is a
+ // path source, then we normalize the path here to get
+ // rid of components like `..`.
+ //
+ // The purpose of this is to get a canonical id for the
+ // package that we're depending on to ensure that builds
+ // of this package always end up hashing to the same
+ // value no matter where it's built from.
+ if cx.source_id.is_path() {
+ let path = cx.layout.root.join(path);
+ let path = util::normalize_path(&path);
+ Some(try!(SourceId::for_path(&path)))
+ } else {
+ Some(cx.source_id.clone())
+ }
+ }
+ None => None,
+ }
}
}.unwrap_or(try!(SourceId::for_central(cx.config)));