auto merge of #150 : rust-lang/cargo/source-id-cleanup, r=alexcrichton

This PR is a stepping stone towards eventual use of `--extern`, which will allow multiple packages with the same name to exist in the transitive dependency graph.
This commit is contained in:
bors 2014-07-09 02:44:51 +00:00
commit a5bcfa3746
13 changed files with 162 additions and 67 deletions

View File

@ -1,4 +1,4 @@
#![crate_id="cargo-clean"]
#![crate_name="cargo-clean"]
#![feature(phase)]
extern crate cargo;

View File

@ -1,4 +1,4 @@
use core::{VersionReq,SourceId};
use core::{VersionReq,SourceId,Summary};
use util::CargoResult;
#[deriving(PartialEq,Clone,Show)]
@ -45,7 +45,16 @@ impl Dependency {
}
pub fn is_transitive(&self) -> bool {
self.transitive
self.transitive
}
pub fn matches(&self, sum: &Summary) -> bool {
debug!("self={}; summary={}", self, sum);
debug!(" a={}; b={}", self.namespace, sum.get_source_id());
self.name.as_slice() == sum.get_name() &&
self.req.matches(sum.get_version()) &&
&self.namespace == sum.get_source_id()
}
}

View File

@ -9,6 +9,7 @@ use core::{
PackageId,
Summary
};
use core::package_id::Metadata;
use core::dependency::SerializedDependency;
use util::{CargoResult, human};
@ -99,13 +100,13 @@ pub enum TargetKind {
BinTarget
}
#[deriving(Clone, Hash, PartialEq)]
#[deriving(Encodable, Decodable, Clone, Hash, PartialEq)]
pub struct Profile {
env: String, // compile, test, dev, bench, etc.
opt_level: uint,
debug: bool,
test: bool,
dest: Option<String>
dest: Option<String>,
}
impl Profile {
@ -193,15 +194,18 @@ impl Profile {
pub struct Target {
kind: TargetKind,
name: String,
path: Path,
profile: Profile
src_path: Path,
profile: Profile,
metadata: Option<Metadata>
}
#[deriving(Encodable)]
pub struct SerializedTarget {
kind: Vec<&'static str>,
name: String,
path: String
src_path: String,
profile: Profile,
metadata: Option<Metadata>
}
impl<E, S: Encoder<E>> Encodable<S, E> for Target {
@ -214,7 +218,9 @@ impl<E, S: Encoder<E>> Encodable<S, E> for Target {
SerializedTarget {
kind: kind,
name: self.name.clone(),
path: self.path.display().to_str()
src_path: self.src_path.display().to_str(),
profile: self.profile.clone(),
metadata: self.metadata.clone()
}.encode(s)
}
}
@ -222,10 +228,11 @@ impl<E, S: Encoder<E>> Encodable<S, E> for Target {
impl Show for Target {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}(name={}, path={})", self.kind, self.name,
self.path.display())
self.src_path.display())
}
}
impl Manifest {
pub fn new(summary: &Summary, targets: &[Target],
target_dir: &Path, sources: Vec<SourceId>,
@ -292,21 +299,26 @@ impl Manifest {
impl Target {
pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
path: &Path, profile: &Profile) -> Target {
src_path: &Path, profile: &Profile,
metadata: &Metadata)
-> Target
{
Target {
kind: LibTarget(crate_targets),
name: name.to_str(),
path: path.clone(),
profile: profile.clone()
src_path: src_path.clone(),
profile: profile.clone(),
metadata: Some(metadata.clone())
}
}
pub fn bin_target(name: &str, path: &Path, profile: &Profile) -> Target {
pub fn bin_target(name: &str, src_path: &Path, profile: &Profile) -> Target {
Target {
kind: BinTarget,
name: name.to_str(),
path: path.clone(),
profile: profile.clone()
src_path: src_path.clone(),
profile: profile.clone(),
metadata: None
}
}
@ -314,8 +326,8 @@ impl Target {
self.name.as_slice()
}
pub fn get_path<'a>(&'a self) -> &'a Path {
&self.path
pub fn get_src_path<'a>(&'a self) -> &'a Path {
&self.src_path
}
pub fn is_lib(&self) -> bool {
@ -336,6 +348,10 @@ impl Target {
&self.profile
}
pub fn get_metadata<'a>(&'a self) -> Option<&'a Metadata> {
self.metadata.as_ref()
}
pub fn rustc_crate_types(&self) -> Vec<&'static str> {
match self.kind {
LibTarget(ref kinds) => {

View File

@ -9,8 +9,8 @@ use serialize::{
Decoder
};
use util::{CargoResult, CargoError};
use core::source::Location;
use util::{CargoResult, CargoError, short_hash};
use core::source::SourceId;
trait ToVersion {
fn to_version(self) -> Result<semver::Version, String>;
@ -53,11 +53,11 @@ impl<'a> ToUrl for &'a Url {
}
}
#[deriving(Clone,PartialEq)]
#[deriving(Clone, PartialEq)]
pub struct PackageId {
name: String,
version: semver::Version,
namespace: Location,
source_id: SourceId,
}
#[deriving(Clone, Show, PartialEq)]
@ -76,14 +76,20 @@ impl CargoError for PackageIdError {
fn is_human(&self) -> bool { true }
}
#[deriving(PartialEq, Hash, Clone, Encodable)]
pub struct Metadata {
pub metadata: String,
pub extra_filename: String
}
impl PackageId {
pub fn new<T: ToVersion>(name: &str, version: T,
ns: &Location) -> CargoResult<PackageId> {
sid: &SourceId) -> CargoResult<PackageId> {
let v = try!(version.to_version().map_err(InvalidVersion));
Ok(PackageId {
name: name.to_str(),
version: v,
namespace: ns.clone()
source_id: sid.clone()
})
}
@ -95,8 +101,16 @@ impl PackageId {
&self.version
}
pub fn get_namespace<'a>(&'a self) -> &'a Location {
&self.namespace
pub fn get_source_id<'a>(&'a self) -> &'a SourceId {
&self.source_id
}
pub fn generate_metadata(&self) -> Metadata {
let metadata = format!("{}:-:{}:-:{}", self.name, self.version, self.source_id);
let extra_filename = short_hash(
&(self.name.as_slice(), self.version.to_str(), &self.source_id));
Metadata { metadata: metadata, extra_filename: extra_filename }
}
}
@ -106,8 +120,8 @@ impl Show for PackageId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
try!(write!(f, "{} v{}", self.name, self.version));
if self.namespace.to_str().as_slice() != central_repo {
try!(write!(f, " ({})", self.namespace));
if self.source_id.to_str().as_slice() != central_repo {
try!(write!(f, " ({})", self.source_id));
}
Ok(())
@ -118,31 +132,29 @@ impl<D: Decoder<Box<CargoError + Send>>>
Decodable<D,Box<CargoError + Send>>
for PackageId
{
fn decode(d: &mut D) -> Result<PackageId, Box<CargoError + Send>> {
let vector: Vec<String> = try!(Decodable::decode(d));
fn decode(d: &mut D) -> CargoResult<PackageId> {
let (name, version, source_id): (String, String, SourceId) = try!(Decodable::decode(d));
PackageId::new(
vector.get(0).as_slice(),
vector.get(1).as_slice(),
&try!(Location::parse(vector.get(2).as_slice())))
PackageId::new(name.as_slice(), version.as_slice(), &source_id)
}
}
impl<E, S: Encoder<E>> Encodable<S,E> for PackageId {
fn encode(&self, e: &mut S) -> Result<(), E> {
(vec!(self.name.clone(), self.version.to_str()),
self.namespace.to_str()).encode(e)
(self.name.clone(), self.version.to_str(), self.source_id.clone()).encode(e)
}
}
#[cfg(test)]
mod tests {
use super::{PackageId, central_repo};
use core::source::Location;
use core::source::{Location, RegistryKind, SourceId};
#[test]
fn invalid_version_handled_nicely() {
let repo = Location::parse(central_repo).unwrap();
let loc = Location::parse(central_repo).unwrap();
let repo = SourceId::new(RegistryKind, loc);
assert!(PackageId::new("foo", "1.0", &repo).is_err());
assert!(PackageId::new("foo", "1", &repo).is_err());
assert!(PackageId::new("foo", "bar", &repo).is_err());

View File

@ -7,9 +7,9 @@ pub trait Registry {
}
impl Registry for Vec<Summary> {
fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
Ok(self.iter()
.filter(|summary| name.get_name() == summary.get_name())
.filter(|summary| dep.matches(*summary))
.map(|summary| summary.clone())
.collect())
}
@ -105,6 +105,13 @@ impl<'a> PackageRegistry<'a> {
Ok(())
}).chain_error(|| human(format!("Unable to update {}", namespace)))
}
fn query_overrides(&self, dep: &Dependency) -> Vec<Summary> {
self.overrides.iter()
.filter(|s| s.get_name() == dep.get_name())
.map(|s| s.clone())
.collect()
}
}
fn dedup(ids: Vec<SourceId>) -> Vec<SourceId> {
@ -120,7 +127,7 @@ fn dedup(ids: Vec<SourceId>) -> Vec<SourceId> {
impl<'a> Registry for PackageRegistry<'a> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
let overrides = try!(self.overrides.query(dep)); // this can never fail in practice
let overrides = self.query_overrides(dep);
if overrides.is_empty() {
// Ensure the requested namespace is loaded

View File

@ -4,7 +4,7 @@ use core::{
Dependency,
PackageId,
Summary,
Registry
Registry,
};
use util::{CargoResult, human, internal};
@ -96,8 +96,9 @@ mod test {
)
)
fn registry_loc() -> Location {
Location::parse("http://www.example.com/").unwrap()
fn registry_loc() -> SourceId {
let remote = Location::parse("http://example.com").unwrap();
SourceId::new(RegistryKind, remote)
}
fn pkg(name: &str) -> Summary {

View File

@ -1,12 +1,13 @@
use std::fmt;
use std::fmt::{Show, Formatter};
use serialize::{Decodable, Decoder, Encodable, Encoder};
use url::Url;
use core::{Summary, Package, PackageId};
use sources::{PathSource, GitSource};
use sources::git;
use util::{Config, CargoResult};
use util::{Config, CargoResult, CargoError};
use util::errors::human;
/// A Source finds and downloads remote packages based on names and
@ -45,7 +46,7 @@ pub trait Source {
fn fingerprint(&self, pkg: &Package) -> CargoResult<String>;
}
#[deriving(Show, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[deriving(Encodable, Decodable, Show, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SourceKind {
/// GitKind(<git reference>) represents a git repository
GitKind(String),
@ -55,13 +56,28 @@ pub enum SourceKind {
RegistryKind
}
#[deriving(Clone, PartialEq, Eq)]
#[deriving(Clone, PartialEq, Eq, Hash)]
pub enum Location {
Local(Path),
Remote(Url),
}
#[deriving(Clone, Eq)]
type Error = Box<CargoError + Send>;
impl<E, D: Decoder<E>> Decodable<D, E> for Location {
fn decode(d: &mut D) -> Result<Location, E> {
let url: String = raw_try!(Decodable::decode(d));
Ok(Location::parse(url.as_slice()).unwrap())
}
}
impl<E, S: Encoder<E>> Encodable<S, E> for Location {
fn encode(&self, e: &mut S) -> Result<(), E> {
self.to_str().encode(e)
}
}
#[deriving(Encodable, Decodable, Clone, Eq, Hash)]
pub struct SourceId {
pub kind: SourceKind,
pub location: Location,
@ -97,7 +113,7 @@ impl Show for SourceId {
SourceId { kind: GitKind(ref reference), ref location } => {
try!(write!(f, "{}", location));
if reference.as_slice() != "master" {
try!(write!(f, " (ref={})", reference));
try!(write!(f, "#ref={}", reference));
}
},
SourceId { kind: RegistryKind, .. } => {

View File

@ -1,7 +1,8 @@
use semver::Version;
use core::{
Dependency,
PackageId
PackageId,
SourceId
};
/// Summaries are cloned, and should not be mutated after creation
@ -31,6 +32,10 @@ impl Summary {
self.get_package_id().get_version()
}
pub fn get_source_id<'a>(&'a self) -> &'a SourceId {
self.package_id.get_source_id()
}
pub fn get_dependencies<'a>(&'a self) -> &'a [Dependency] {
self.dependencies.as_slice()
}

View File

@ -121,6 +121,7 @@ fn compile(targets: &[&Target], pkg: &Package,
// TODO: Figure out how this works with targets
let fingerprint_loc = cx.dest.join(format!(".{}.fingerprint",
pkg.get_name()));
let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, cx,
targets));
@ -244,10 +245,15 @@ fn prepare_rustc(root: &Path, target: &Target, crate_types: Vec<&str>,
.env("RUST_LOG", None) // rustc is way too noisy
}
fn build_base_args(into: &mut Args, target: &Target, crate_types: Vec<&str>,
cx: &Context) {
fn build_base_args(into: &mut Args,
target: &Target,
crate_types: Vec<&str>,
cx: &Context)
{
let metadata = target.get_metadata();
// TODO: Handle errors in converting paths into args
into.push(target.get_path().display().to_str());
into.push(target.get_src_path().display().to_str());
into.push("--crate-name".to_str());
into.push(target.get_name().to_str());
@ -273,6 +279,17 @@ fn build_base_args(into: &mut Args, target: &Target, crate_types: Vec<&str>,
into.push("--test".to_str());
}
match metadata {
Some(m) => {
into.push("-C".to_str());
into.push(format!("metadata={}", m.metadata));
into.push("-C".to_str());
into.push(format!("extra-filename={}", m.extra_filename));
}
None => {}
}
if target.is_lib() {
into.push("--out-dir".to_str());
into.push(out.display().to_str());

View File

@ -1,4 +1,6 @@
use std::io::MemWriter;
use std::hash::{Hasher, Hash};
use std::hash::sip::SipHasher;
use serialize::hex::ToHex;
@ -8,3 +10,7 @@ pub fn to_hex(num: u64) -> String {
writer.get_ref().to_hex()
}
pub fn short_hash<H: Hash>(hashable: &H) -> String {
let hasher = SipHasher::new_with_keys(0, 0);
to_hex(hasher.hash(hashable))
}

View File

@ -5,7 +5,7 @@ pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult}
pub use self::errors::{CliError, FromError, ProcessError};
pub use self::errors::{process_error, internal_error, internal, human};
pub use self::paths::realpath;
pub use self::hex::to_hex;
pub use self::hex::{to_hex, short_hash};
pub use self::pool::TaskPool;
pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness};

View File

@ -7,6 +7,7 @@ use toml;
use core::{SourceId, GitKind};
use core::manifest::{LibKind, Lib, Profile};
use core::{Summary, Manifest, Target, Dependency, PackageId};
use core::package_id::Metadata;
use core::source::Location;
use util::{CargoResult, Require, human};
@ -39,7 +40,7 @@ pub fn project_layout(root: &Path) -> Layout {
bins.push(root.join("src/main.rs"));
}
fs::readdir(&root.join("src/bin"))
let _ = fs::readdir(&root.join("src/bin"))
.map(|v| v.move_iter())
.map(|i| i.filter(|f| f.extension_str() == Some("rs")))
.map(|mut i| i.collect())
@ -176,8 +177,8 @@ pub enum TomlBuildCommandsList {
}
impl TomlProject {
pub fn to_package_id(&self, namespace: &Location) -> CargoResult<PackageId> {
PackageId::new(self.name.as_slice(), self.version.as_slice(), namespace)
pub fn to_package_id(&self, source_id: &SourceId) -> CargoResult<PackageId> {
PackageId::new(self.name.as_slice(), self.version.as_slice(), source_id)
}
}
@ -236,6 +237,8 @@ impl TomlManifest {
human("No `package` or `project` section found.")
}));
let pkgid = try!(project.to_package_id(source_id));
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
@ -279,7 +282,8 @@ impl TomlManifest {
// Get targets
let targets = normalize(lib.as_ref().map(|l| l.as_slice()),
bins.as_ref().map(|b| b.as_slice()));
bins.as_ref().map(|b| b.as_slice()),
&metadata);
if targets.is_empty() {
debug!("manifest has no build targets; project={}", self.project);
@ -301,7 +305,6 @@ impl TomlManifest {
try!(process_dependencies(&mut cx, true, self.dev_dependencies.as_ref()));
}
let pkgid = try!(project.to_package_id(source_id.get_location()));
let summary = Summary::new(&pkgid, deps.as_slice());
Ok((Manifest::new(
&summary,
@ -377,7 +380,8 @@ struct TomlTarget {
}
fn normalize(lib: Option<&[TomlLibTarget]>,
bin: Option<&[TomlBinTarget]>)
bin: Option<&[TomlBinTarget]>,
metadata: &Metadata)
-> Vec<Target>
{
log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);
@ -393,7 +397,7 @@ fn normalize(lib: Option<&[TomlLibTarget]>,
ret
}
fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget]) {
fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget], metadata: &Metadata) {
let l = &libs[0];
let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
let crate_types = l.crate_type.clone().and_then(|kinds| {
@ -402,7 +406,8 @@ fn normalize(lib: Option<&[TomlLibTarget]>,
for profile in target_profiles(l).iter() {
dst.push(Target::lib_target(l.name.as_slice(), crate_types.clone(),
&Path::new(path.as_slice()), profile));
&Path::new(path.as_slice()), profile,
metadata));
}
}
@ -413,7 +418,8 @@ fn normalize(lib: Option<&[TomlLibTarget]>,
for profile in target_profiles(bin).iter() {
dst.push(Target::bin_target(bin.name.as_slice(),
&Path::new(path.as_slice()), profile));
&Path::new(path.as_slice()),
profile));
}
}
}
@ -422,12 +428,12 @@ fn normalize(lib: Option<&[TomlLibTarget]>,
match (lib, bin) {
(Some(ref libs), Some(ref bins)) => {
lib_targets(&mut ret, libs.as_slice());
lib_targets(&mut ret, libs.as_slice(), metadata);
bin_targets(&mut ret, bins.as_slice(),
|bin| format!("src/bin/{}.rs", bin.name));
},
(Some(ref libs), None) => {
lib_targets(&mut ret, libs.as_slice());
lib_targets(&mut ret, libs.as_slice(), metadata);
},
(None, Some(ref bins)) => {
bin_targets(&mut ret, bins.as_slice(),

View File

@ -149,7 +149,7 @@ test!(cargo_compile_git_dep_branch {
assert_that(project.cargo_process("cargo-build"),
execs()
.with_stdout(format!("{} git repository `file:{}`\n\
{} dep1 v0.5.0 (file:{})\n\
{} dep1 v0.5.0 (file:{}#ref=branchy)\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_root.display(),
COMPILING, git_root.display(),
@ -214,7 +214,7 @@ test!(cargo_compile_git_dep_tag {
assert_that(project.cargo_process("cargo-build"),
execs()
.with_stdout(format!("{} git repository `file:{}`\n\
{} dep1 v0.5.0 (file:{})\n\
{} dep1 v0.5.0 (file:{}#ref=v0.1.0)\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_root.display(),
COMPILING, git_root.display(),