mirror of https://github.com/rust-lang/cargo
Improvements to transitive dependency infra
Initial work to enable cross-source transitive dependencies.
This commit is contained in:
parent
9b278af150
commit
98322afd90
2
Makefile
2
Makefile
|
@ -9,7 +9,7 @@ BINS = cargo \
|
|||
cargo-verify-project \
|
||||
cargo-git-checkout \
|
||||
|
||||
SRC = $(shell find src -name '*.rs')
|
||||
SRC = $(shell find src -name '*.rs' -not -path 'src/bin*')
|
||||
|
||||
DEPS = -L libs/hammer.rs/target -L libs/rust-toml/lib
|
||||
TOML = libs/rust-toml/lib/$(shell rustc --crate-file-name libs/rust-toml/src/toml/lib.rs)
|
||||
|
|
|
@ -13,7 +13,7 @@ use hammer::FlagConfig;
|
|||
use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
|
||||
use cargo::ops;
|
||||
use cargo::util::important_paths::find_project;
|
||||
use cargo::util::{ToCLI,simple_human};
|
||||
use cargo::util::{ToCLI};
|
||||
|
||||
#[deriving(PartialEq,Clone,Decodable,Encodable)]
|
||||
pub struct Options {
|
||||
|
|
|
@ -8,13 +8,12 @@ extern crate url;
|
|||
use hammer::FlagConfig;
|
||||
use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
|
||||
use cargo::core::source::Source;
|
||||
use cargo::sources::git::{GitSource,GitRemote};
|
||||
use cargo::sources::git::{GitSource};
|
||||
use cargo::util::{Config,ToCLI};
|
||||
use url::Url;
|
||||
|
||||
#[deriving(PartialEq,Clone,Decodable)]
|
||||
struct Options {
|
||||
database_path: String,
|
||||
checkout_path: String,
|
||||
url: String,
|
||||
reference: String,
|
||||
verbose: bool
|
||||
|
@ -27,13 +26,13 @@ fn main() {
|
|||
}
|
||||
|
||||
fn execute(options: Options) -> CLIResult<Option<()>> {
|
||||
let Options { database_path, checkout_path, url, reference, verbose } = options;
|
||||
let Options { url, reference, .. } = options;
|
||||
|
||||
let url: Url = try!(from_str(url.as_slice()).to_result(|_|
|
||||
CLIError::new(format!("The URL `{}` you passed was not a valid URL", url), None::<&str>, 1)));
|
||||
|
||||
let remote = GitRemote::new(url, verbose);
|
||||
let source = GitSource::new(remote, reference, Path::new(database_path), Path::new(checkout_path));
|
||||
let source = GitSource::new(&url, reference.as_slice(), &try!(Config::new().to_cli(1)));
|
||||
|
||||
try!(source.update().map_err(|e| {
|
||||
CLIError::new(format!("Couldn't update {}: {}", source, e), None::<&str>, 1)
|
||||
}));
|
||||
|
|
|
@ -14,7 +14,7 @@ use serialize::Encodable;
|
|||
use cargo::{NoFlags,execute_main_without_stdin,handle_error};
|
||||
use cargo::core::errors::{CLIError,CLIResult,ToResult};
|
||||
use cargo::util::important_paths::find_project;
|
||||
use cargo::util::{ToCLI,Wrap,config,io_error,simple_human};
|
||||
use cargo::util::{ToCLI,config,simple_human};
|
||||
|
||||
fn main() {
|
||||
execute();
|
||||
|
|
|
@ -167,7 +167,7 @@ impl Manifest {
|
|||
&self.target_dir
|
||||
}
|
||||
|
||||
pub fn get_sources<'a>(&'a self) -> &'a [SourceId] {
|
||||
pub fn get_source_ids<'a>(&'a self) -> &'a [SourceId] {
|
||||
self.sources.as_slice()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,10 @@ impl Package {
|
|||
self.get_root().join(self.get_target_dir())
|
||||
}
|
||||
|
||||
pub fn get_sources<'a>(&'a self) -> &'a [SourceId] {
|
||||
self.manifest.get_sources()
|
||||
pub fn get_source_ids(&self) -> Vec<SourceId> {
|
||||
let mut ret = vec!(SourceId::for_path(&self.get_root()));
|
||||
ret.push_all(self.manifest.get_source_ids());
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::vec::Vec;
|
||||
use core::{Source, SourceId, SourceSet, Summary, Dependency, PackageSet};
|
||||
use util::CargoResult;
|
||||
use core::{Source, SourceId, Summary, Dependency, PackageId, Package};
|
||||
use util::{CargoResult,Config};
|
||||
|
||||
pub trait Registry {
|
||||
fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>>;
|
||||
|
@ -23,33 +23,71 @@ pub struct PackageRegistry {
|
|||
}
|
||||
|
||||
impl PackageRegistry {
|
||||
pub fn new(sources: Vec<Box<Source>>, overrides: SourceSet) -> CargoResult<PackageRegistry> {
|
||||
Ok(PackageRegistry {
|
||||
sources: sources,
|
||||
overrides: try!(overrides.list()),
|
||||
pub fn new(source_ids: Vec<SourceId>, override_ids: Vec<SourceId>) -> CargoResult<PackageRegistry> {
|
||||
let mut reg = PackageRegistry::empty();
|
||||
|
||||
for id in source_ids.iter() {
|
||||
try!(reg.load(id, false));
|
||||
}
|
||||
|
||||
for id in override_ids.iter() {
|
||||
try!(reg.load(id, true));
|
||||
}
|
||||
|
||||
Ok(reg)
|
||||
}
|
||||
|
||||
fn empty() -> PackageRegistry {
|
||||
PackageRegistry {
|
||||
sources: vec!(),
|
||||
overrides: vec!(),
|
||||
summaries: vec!(),
|
||||
searched: vec!()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, package_ids: &[PackageId]) -> CargoResult<Vec<Package>> {
|
||||
log!(5, "getting packags; sources={}; ids={}", self.sources.len(), package_ids);
|
||||
|
||||
// TODO: Only call source with package ID if the package came from the source
|
||||
let mut ret = Vec::new();
|
||||
|
||||
for source in self.sources.iter() {
|
||||
try!(source.download(package_ids));
|
||||
let packages = try!(source.get(package_ids));
|
||||
|
||||
ret.push_all_move(packages);
|
||||
}
|
||||
|
||||
// TODO: Return earlier if fail
|
||||
assert!(package_ids.len() == ret.len(), "could not get packages from registry; ids={}", package_ids);
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn ensure_loaded(&mut self, namespace: &SourceId) -> CargoResult<()> {
|
||||
if self.searched.contains(namespace) { return Ok(()); }
|
||||
self.load(namespace);
|
||||
try!(self.load(namespace, false));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load(&mut self, namespace: &SourceId) -> CargoResult<()> {
|
||||
let source = namespace.load();
|
||||
fn load(&mut self, namespace: &SourceId, override: bool) -> CargoResult<()> {
|
||||
let source = namespace.load(&try!(Config::new()));
|
||||
let dst = if override { &mut self.overrides } else { &mut self.summaries };
|
||||
|
||||
// Ensure the source has fetched all necessary remote data.
|
||||
try!(source.update());
|
||||
|
||||
// Get the summaries
|
||||
for summary in (try!(source.list())).iter() {
|
||||
assert!(!self.summaries.contains(summary), "duplicate summaries");
|
||||
self.summaries.push(summary.clone());
|
||||
assert!(!dst.contains(summary), "duplicate summaries");
|
||||
dst.push(summary.clone());
|
||||
// self.summaries.push(summary.clone());
|
||||
}
|
||||
|
||||
// Save off the source
|
||||
self.sources.push(source);
|
||||
|
||||
// Track that the source has been searched
|
||||
self.searched.push(namespace.clone());
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::fmt::Show;
|
||||
use std::collections::HashMap;
|
||||
use core::{
|
||||
Dependency,
|
||||
|
@ -12,8 +11,8 @@ use util::result::CargoResult;
|
|||
* - The correct input here is not a registry. Resolves should be performable
|
||||
* on package summaries vs. the packages themselves.
|
||||
*/
|
||||
pub fn resolve<R: Registry + Show>(deps: &[Dependency], registry: &mut R) -> CargoResult<Vec<PackageId>> {
|
||||
log!(5, "resolve; deps={}; registry={}", deps, registry);
|
||||
pub fn resolve<R: Registry>(deps: &[Dependency], registry: &mut R) -> CargoResult<Vec<PackageId>> {
|
||||
log!(5, "resolve; deps={}", deps);
|
||||
|
||||
let mut remaining = Vec::from_slice(deps);
|
||||
let mut resolve = HashMap::<String, Summary>::new();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use url;
|
||||
use url::Url;
|
||||
use core::{Summary,Package,PackageId};
|
||||
use util::CargoResult;
|
||||
use sources::{PathSource,GitSource};
|
||||
use util::{Config,CargoResult};
|
||||
|
||||
/**
|
||||
* A Source finds and downloads remote packages based on names and
|
||||
|
@ -58,10 +60,43 @@ impl SourceId {
|
|||
SourceId { kind: kind, url: url }
|
||||
}
|
||||
|
||||
pub fn load(&self) -> Box<Source> {
|
||||
// Pass absolute path
|
||||
pub fn for_path(path: &Path) -> SourceId {
|
||||
// TODO: use proper path -> URL
|
||||
SourceId::new(PathKind, url::from_str(format!("file://{}", path.display()).as_slice()).unwrap())
|
||||
}
|
||||
|
||||
pub fn for_central() -> SourceId {
|
||||
SourceId::new(RegistryKind, url::from_str(format!("https://example.com").as_slice()).unwrap())
|
||||
}
|
||||
|
||||
/*
|
||||
let git_sources: Vec<Box<Source>> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| {
|
||||
match source_id.kind {
|
||||
GitKind(ref reference) => {
|
||||
let remote = GitRemote::new(source_id.url.clone(), false);
|
||||
let home = try!(os::homedir().require(simple_human("Cargo couldn't find a home directory")));
|
||||
let git = home.join(".cargo").join("git");
|
||||
let ident = url_to_path_ident(&source_id.url);
|
||||
|
||||
// .cargo/git/db
|
||||
// .cargo/git/checkouts
|
||||
let db_path = git.join("db").join(ident.as_slice());
|
||||
let checkout_path = git.join("checkouts").join(ident.as_slice()).join(reference.as_slice());
|
||||
Ok(box GitSource::new(remote, reference.clone(), db_path, checkout_path) as Box<Source>)
|
||||
},
|
||||
ref PathKind => fail!("Cannot occur")
|
||||
}
|
||||
})));
|
||||
*/
|
||||
|
||||
pub fn load(&self, config: &Config) -> Box<Source> {
|
||||
match self.kind {
|
||||
GitKind(ref reference) => unimplemented!(),
|
||||
_ => unimplemented!()
|
||||
GitKind(ref reference) => {
|
||||
box GitSource::new(&self.url, reference.as_slice(), config) as Box<Source>
|
||||
},
|
||||
PathKind => box PathSource::new(&Path::new(self.url.path.as_slice())) as Box<Source>,
|
||||
RegistryKind => unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@ use core::{
|
|||
PackageId
|
||||
};
|
||||
|
||||
/**
|
||||
* Summaries are cloned, and should not be mutated after creation
|
||||
*/
|
||||
|
||||
#[deriving(Show,Clone,PartialEq)]
|
||||
pub struct Summary {
|
||||
package_id: PackageId,
|
||||
|
|
|
@ -14,23 +14,13 @@
|
|||
* b. Compile each dependency in order, passing in the -L's pointing at each previously compiled dependency
|
||||
*/
|
||||
|
||||
use std::io::MemWriter;
|
||||
use std::os;
|
||||
use std::result;
|
||||
use std::hash::sip::SipHasher;
|
||||
use std::hash::Hasher;
|
||||
use serialize::hex::ToHex;
|
||||
use url::Url;
|
||||
use util::config;
|
||||
use util::config::{ConfigValue};
|
||||
use core::{Package,PackageSet,Source,SourceSet};
|
||||
use core::resolver::resolve;
|
||||
use core::source::{GitKind,SourceId};
|
||||
use core::{SourceId,PackageSet,resolver};
|
||||
use core::registry::PackageRegistry;
|
||||
use sources::{PathSource,GitSource};
|
||||
use sources::git::GitRemote;
|
||||
use ops;
|
||||
use util::{CargoResult, Wrap, Require, simple_human, other_error};
|
||||
use sources::{PathSource};
|
||||
use util::{CargoResult,Wrap,config,other_error};
|
||||
|
||||
pub fn compile(manifest_path: &Path) -> CargoResult<()> {
|
||||
log!(4, "compile; manifest-path={}", manifest_path.display());
|
||||
|
@ -39,112 +29,32 @@ pub fn compile(manifest_path: &Path) -> CargoResult<()> {
|
|||
let package = try!(PathSource::read_package(manifest_path));
|
||||
debug!("loaded package; package={}", package);
|
||||
|
||||
let overrides = try!(sources_from_config());
|
||||
let sources = try!(sources_for(&package));
|
||||
let override_ids = try!(source_ids_from_config());
|
||||
let source_ids = package.get_source_ids();
|
||||
|
||||
let registry = PackageRegistry::new(sources, overrides);
|
||||
let mut registry = try!(PackageRegistry::new(source_ids, override_ids));
|
||||
let resolved = try!(resolver::resolve(package.get_dependencies(), &mut registry).wrap("unable to resolve dependencies"));
|
||||
|
||||
//try!(sources.update().wrap("unable to update sources"));
|
||||
//let summaries = try!(sources.list().wrap("unable to list packages from source"));
|
||||
let packages = try!(registry.get(resolved.as_slice()).wrap("unable to get packages from source"));
|
||||
|
||||
//let registry = PackageRegistry::new(&summaries, &overrides);
|
||||
debug!("packages={}", packages);
|
||||
|
||||
//let resolved = try!(resolve(package.get_dependencies(), &summaries).wrap("unable to resolve dependencies"));
|
||||
|
||||
//try!(sources.download(resolved.as_slice()).wrap("unable to download packages"));
|
||||
|
||||
//let packages = try!(sources.get(resolved.as_slice()).wrap("unable to get packages from source"));
|
||||
|
||||
//log!(5, "fetch packages from source; packages={}; ids={}", packages, resolved);
|
||||
|
||||
//let package_set = PackageSet::new(packages.as_slice());
|
||||
|
||||
//try!(ops::compile_packages(&package, &package_set));
|
||||
try!(ops::compile_packages(&package, &PackageSet::new(packages.as_slice())));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sources_for(package: &Package) -> CargoResult<Vec<Box<Source>>> {
|
||||
let mut sources = vec!(box PathSource::new(vec!(package.get_manifest_path().dir_path())) as Box<Source>);
|
||||
|
||||
let git_sources: Vec<Box<Source>> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| {
|
||||
match source_id.kind {
|
||||
GitKind(ref reference) => {
|
||||
let remote = GitRemote::new(source_id.url.clone(), false);
|
||||
let home = try!(os::homedir().require(simple_human("Cargo couldn't find a home directory")));
|
||||
let git = home.join(".cargo").join("git");
|
||||
let ident = url_to_path_ident(&source_id.url);
|
||||
|
||||
// .cargo/git/db
|
||||
// .cargo/git/checkouts
|
||||
let db_path = git.join("db").join(ident.as_slice());
|
||||
let checkout_path = git.join("checkouts").join(ident.as_slice()).join(reference.as_slice());
|
||||
Ok(box GitSource::new(remote, reference.clone(), db_path, checkout_path) as Box<Source>)
|
||||
},
|
||||
ref PathKind => fail!("Cannot occur")
|
||||
}
|
||||
})));
|
||||
|
||||
sources.push_all_move(git_sources);
|
||||
|
||||
Ok(sources)
|
||||
}
|
||||
|
||||
fn sources_from_config() -> CargoResult<SourceSet> {
|
||||
fn source_ids_from_config() -> CargoResult<Vec<SourceId>> {
|
||||
let configs = try!(config::all_configs(os::getcwd()));
|
||||
|
||||
debug!("loaded config; configs={}", configs);
|
||||
|
||||
let config_paths = configs.find_equiv(&"paths").map(|v| v.clone()).unwrap_or_else(|| ConfigValue::new());
|
||||
|
||||
let mut paths: Vec<Path> = match config_paths.get_value() {
|
||||
let paths: Vec<Path> = match config_paths.get_value() {
|
||||
&config::String(_) => return Err(other_error("The path was configured as a String instead of a List")),
|
||||
&config::List(ref list) => list.iter().map(|path| Path::new(path.as_slice())).collect()
|
||||
};
|
||||
|
||||
Ok(SourceSet::new(vec!(box PathSource::new(paths) as Box<Source>)))
|
||||
}
|
||||
|
||||
fn url_to_path_ident(url: &Url) -> String {
|
||||
let hasher = SipHasher::new_with_keys(0,0);
|
||||
|
||||
let mut ident = url.path.as_slice().split('/').last().unwrap();
|
||||
|
||||
ident = if ident == "" {
|
||||
"_empty"
|
||||
} else {
|
||||
ident
|
||||
};
|
||||
|
||||
format!("{}-{}", ident, to_hex(hasher.hash(&url.to_str())))
|
||||
}
|
||||
|
||||
fn to_hex(num: u64) -> String {
|
||||
let mut writer = MemWriter::with_capacity(8);
|
||||
writer.write_le_u64(num).unwrap(); // this should never fail
|
||||
writer.get_ref().to_hex()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use url;
|
||||
use url::Url;
|
||||
use super::url_to_path_ident;
|
||||
|
||||
#[test]
|
||||
pub fn test_url_to_path_ident_with_path() {
|
||||
let ident = url_to_path_ident(&url("https://github.com/carlhuda/cargo"));
|
||||
assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_url_to_path_ident_without_path() {
|
||||
let ident = url_to_path_ident(&url("https://github.com"));
|
||||
assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
|
||||
}
|
||||
|
||||
|
||||
fn url(s: &str) -> Url {
|
||||
url::from_str(s).unwrap()
|
||||
}
|
||||
Ok(paths.iter().map(|p| SourceId::for_path(p)).collect())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
use ops;
|
||||
use std::fmt;
|
||||
use std::hash::sip::SipHasher;
|
||||
use std::hash::Hasher;
|
||||
use std::fmt::{Show,Formatter};
|
||||
use std::io::MemWriter;
|
||||
use serialize::hex::ToHex;
|
||||
use url;
|
||||
use url::Url;
|
||||
|
||||
use ops;
|
||||
use core::source::Source;
|
||||
use core::{Package,PackageId,Summary};
|
||||
use util::CargoResult;
|
||||
use util::{CargoResult,Config};
|
||||
use sources::git::utils::{GitReference,GitRemote,Master,Other};
|
||||
use std::fmt;
|
||||
use std::fmt::{Show,Formatter};
|
||||
|
||||
pub struct GitSource {
|
||||
remote: GitRemote,
|
||||
|
@ -15,13 +21,48 @@ pub struct GitSource {
|
|||
}
|
||||
|
||||
impl GitSource {
|
||||
pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path) -> GitSource {
|
||||
GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout }
|
||||
pub fn new(url: &Url, reference: &str, config: &Config) -> GitSource {
|
||||
let remote = GitRemote::new(url);
|
||||
let ident = ident(url);
|
||||
|
||||
let db_path = config.git_db_path()
|
||||
.join(ident.as_slice());
|
||||
|
||||
let checkout_path = config.git_checkout_path()
|
||||
.join(ident.as_slice()).join(reference);
|
||||
|
||||
GitSource {
|
||||
remote: remote,
|
||||
reference: GitReference::for_str(reference),
|
||||
db_path: db_path,
|
||||
checkout_path: checkout_path
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_namespace<'a>(&'a self) -> &'a url::Url {
|
||||
self.remote.get_url()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn ident(url: &Url) -> String {
|
||||
let hasher = SipHasher::new_with_keys(0,0);
|
||||
|
||||
let mut ident = url.path.as_slice().split('/').last().unwrap();
|
||||
|
||||
ident = if ident == "" {
|
||||
"_empty"
|
||||
} else {
|
||||
ident
|
||||
};
|
||||
|
||||
format!("{}-{}", ident, to_hex(hasher.hash(&url.to_str())))
|
||||
}
|
||||
|
||||
fn to_hex(num: u64) -> String {
|
||||
let mut writer = MemWriter::with_capacity(8);
|
||||
writer.write_le_u64(num).unwrap(); // this should never fail
|
||||
writer.get_ref().to_hex()
|
||||
}
|
||||
|
||||
impl Show for GitSource {
|
||||
|
@ -72,3 +113,27 @@ fn read_manifest(path: &Path, url: &url::Url) -> CargoResult<Package> {
|
|||
let path = path.join("Cargo.toml");
|
||||
ops::read_package(&path, url)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use url;
|
||||
use url::Url;
|
||||
use super::ident;
|
||||
|
||||
#[test]
|
||||
pub fn test_url_to_path_ident_with_path() {
|
||||
let ident = ident(&url("https://github.com/carlhuda/cargo"));
|
||||
assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_url_to_path_ident_without_path() {
|
||||
let ident = ident(&url("https://github.com"));
|
||||
assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
|
||||
}
|
||||
|
||||
|
||||
fn url(s: &str) -> Url {
|
||||
url::from_str(s).unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,22 +40,22 @@ impl Show for GitReference {
|
|||
|
||||
|
||||
macro_rules! git(
|
||||
($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
|
||||
try!(git_inherit(&$config, $verbose, format!($str, $($rest),*)))
|
||||
($config:expr, $str:expr, $($rest:expr),*) => (
|
||||
try!(git_inherit(&$config, format!($str, $($rest),*)))
|
||||
);
|
||||
|
||||
($config:expr, $verbose:expr, $str:expr) => (
|
||||
try!(git_inherit(&$config, $verbose, format!($str)))
|
||||
($config:expr, $str:expr) => (
|
||||
try!(git_inherit(&$config, format!($str)))
|
||||
);
|
||||
)
|
||||
|
||||
macro_rules! git_output(
|
||||
($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
|
||||
try!(git_output(&$config, $verbose, format!($str, $($rest),*)))
|
||||
($config:expr, $str:expr, $($rest:expr),*) => (
|
||||
try!(git_output(&$config, format!($str, $($rest),*)))
|
||||
);
|
||||
|
||||
($config:expr, $verbose:expr, $str:expr) => (
|
||||
try!(git_output(&$config, $verbose, format!($str)))
|
||||
($config:expr, $str:expr) => (
|
||||
try!(git_output(&$config, format!($str)))
|
||||
);
|
||||
)
|
||||
|
||||
|
@ -70,7 +70,6 @@ macro_rules! errln(
|
|||
#[deriving(PartialEq,Clone,Show)]
|
||||
pub struct GitRemote {
|
||||
url: Url,
|
||||
verbose: bool
|
||||
}
|
||||
|
||||
#[deriving(PartialEq,Clone,Encodable)]
|
||||
|
@ -95,7 +94,6 @@ impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
|
|||
pub struct GitDatabase {
|
||||
remote: GitRemote,
|
||||
path: Path,
|
||||
verbose: bool
|
||||
}
|
||||
|
||||
#[deriving(Encodable)]
|
||||
|
@ -124,7 +122,6 @@ pub struct GitCheckout {
|
|||
location: Path,
|
||||
reference: GitReference,
|
||||
revision: String,
|
||||
verbose: bool
|
||||
}
|
||||
|
||||
#[deriving(Encodable)]
|
||||
|
@ -151,8 +148,8 @@ impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
|
|||
*/
|
||||
|
||||
impl GitRemote {
|
||||
pub fn new(url: Url, verbose: bool) -> GitRemote {
|
||||
GitRemote { url: url, verbose: verbose }
|
||||
pub fn new(url: &Url) -> GitRemote {
|
||||
GitRemote { url: url.clone() }
|
||||
}
|
||||
|
||||
pub fn get_url<'a>(&'a self) -> &'a Url {
|
||||
|
@ -166,11 +163,11 @@ impl GitRemote {
|
|||
try!(self.clone_into(into));
|
||||
}
|
||||
|
||||
Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose })
|
||||
Ok(GitDatabase { remote: self.clone(), path: into.clone() })
|
||||
}
|
||||
|
||||
fn fetch_into(&self, path: &Path) -> CargoResult<()> {
|
||||
Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.fetch_location()))
|
||||
Ok(git!(*path, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.fetch_location()))
|
||||
}
|
||||
|
||||
fn clone_into(&self, path: &Path) -> CargoResult<()> {
|
||||
|
@ -179,7 +176,7 @@ impl GitRemote {
|
|||
try!(mkdir_recursive(path, UserDir).map_err(|err|
|
||||
human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err))));
|
||||
|
||||
Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
|
||||
Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
|
||||
}
|
||||
|
||||
fn fetch_location(&self) -> String {
|
||||
|
@ -196,8 +193,7 @@ impl GitDatabase {
|
|||
}
|
||||
|
||||
pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> {
|
||||
let verbose = self.verbose;
|
||||
let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose));
|
||||
let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice())));
|
||||
|
||||
try!(checkout.fetch());
|
||||
try!(checkout.update_submodules());
|
||||
|
@ -206,15 +202,15 @@ impl GitDatabase {
|
|||
}
|
||||
|
||||
pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
|
||||
Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice()))
|
||||
Ok(git_output!(self.path, "rev-parse {}", reference.as_slice()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl GitCheckout {
|
||||
fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult<GitCheckout> {
|
||||
fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult<GitCheckout> {
|
||||
let revision = try!(database.rev_for(reference.as_slice()));
|
||||
let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose };
|
||||
let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision };
|
||||
|
||||
// If the git checkout already exists, we don't need to clone it again
|
||||
if !checkout.location.join(".git").exists() {
|
||||
|
@ -239,40 +235,40 @@ impl GitCheckout {
|
|||
human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e))));
|
||||
}
|
||||
|
||||
git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
|
||||
git!(dirname, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
|
||||
try!(chmod(&self.location, AllPermissions).map_err(io_error));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch(&self) -> CargoResult<()> {
|
||||
git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display());
|
||||
git!(self.location, "fetch --force --quiet --tags {}", self.get_source().display());
|
||||
try!(self.reset(self.revision.as_slice()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
|
||||
Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision))
|
||||
Ok(git!(self.location, "reset -q --hard {}", revision))
|
||||
}
|
||||
|
||||
fn update_submodules(&self) -> CargoResult<()> {
|
||||
Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet"))
|
||||
Ok(git!(self.location, "submodule update --init --recursive --quiet"))
|
||||
}
|
||||
}
|
||||
|
||||
fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder {
|
||||
fn git(path: &Path, str: &str) -> ProcessBuilder {
|
||||
debug!("Executing git {} @ {}", str, path.display());
|
||||
|
||||
process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice()).cwd(path.clone())
|
||||
}
|
||||
|
||||
fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> {
|
||||
git(path, verbose, str.as_slice()).exec().map_err(|err|
|
||||
fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
|
||||
git(path, str.as_slice()).exec().map_err(|err|
|
||||
human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err))
|
||||
}
|
||||
|
||||
fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult<String> {
|
||||
let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err|
|
||||
fn git_output(path: &Path, str: String) -> CargoResult<String> {
|
||||
let output = try!(git(path, str.as_slice()).exec_with_output().map_err(|err|
|
||||
human_error(format!("Executing `git {}` failed", str), None::<&str>, err)));
|
||||
|
||||
Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
|
||||
|
|
|
@ -11,12 +11,20 @@ use util::{CargoResult,simple_human,io_error,realpath};
|
|||
* take in a single path vs. a vec of paths. The pros / cons are unknown at
|
||||
* this point.
|
||||
*/
|
||||
pub struct PathSource { paths: Vec<Path> }
|
||||
pub struct PathSource {
|
||||
path: Path
|
||||
}
|
||||
|
||||
impl PathSource {
|
||||
pub fn new(paths: Vec<Path>) -> PathSource {
|
||||
log!(5, "new; paths={}", display(paths.as_slice()));
|
||||
PathSource { paths: paths }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
pub fn new(path: &Path) -> PathSource {
|
||||
log!(5, "new; path={}", path.display());
|
||||
PathSource { path: path.clone() }
|
||||
}
|
||||
|
||||
pub fn read_package(path: &Path) -> CargoResult<Package> {
|
||||
|
@ -37,48 +45,44 @@ impl Show for PathSource {
|
|||
}
|
||||
|
||||
impl Source for PathSource {
|
||||
fn update(&self) -> CargoResult<()> { Ok(()) }
|
||||
fn update(&self) -> CargoResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list(&self) -> CargoResult<Vec<Summary>> {
|
||||
Ok(self.paths.iter().filter_map(|path| {
|
||||
match PathSource::read_package(&path.join("Cargo.toml")) {
|
||||
Ok(ref pkg) => Some(pkg.get_summary().clone()),
|
||||
Err(e) => {
|
||||
debug!("failed to read manifest; path={}; err={}", path.display(), e);
|
||||
None
|
||||
}
|
||||
// TODO: Recursively find manifests
|
||||
|
||||
match PathSource::read_package(&self.path.join("Cargo.toml")) {
|
||||
Ok(ref pkg) => Ok(vec!(pkg.get_summary().clone())),
|
||||
Err(e) => {
|
||||
debug!("failed to read manifest; path={}; err={}", self.path.display(), e);
|
||||
Err(e)
|
||||
}
|
||||
}).collect())
|
||||
}
|
||||
}
|
||||
|
||||
fn download(&self, _: &[PackageId]) -> CargoResult<()>{
|
||||
// TODO: assert! that the PackageId is contained by the source
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
|
||||
log!(5, "getting packages; ids={}", ids);
|
||||
|
||||
Ok(self.paths.iter().filter_map(|path| {
|
||||
match PathSource::read_package(&path.join("Cargo.toml")) {
|
||||
Ok(pkg) => {
|
||||
log!(5, "comparing; pkg={}", pkg);
|
||||
PathSource::read_package(&self.path.join("Cargo.toml")).and_then(|pkg| {
|
||||
log!(5, "comparing; pkg={}", pkg);
|
||||
|
||||
if ids.iter().any(|pkg_id| pkg.get_package_id() == pkg_id) {
|
||||
Some(pkg)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(_) => None
|
||||
if ids.iter().any(|pkg_id| pkg.get_package_id() == pkg_id) {
|
||||
Ok(vec!(pkg))
|
||||
} else {
|
||||
// TODO: Be smarter
|
||||
// Err(simple_human(format!("Couldn't find `{}` in path source", ids)))
|
||||
Ok(vec!())
|
||||
}
|
||||
}).collect())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn display(paths: &[Path]) -> Vec<String> {
|
||||
paths.iter().map(|p| p.display().to_str()).collect()
|
||||
}
|
||||
|
||||
fn namespace(path: &Path) -> CargoResult<url::Url> {
|
||||
let real = try!(realpath(path).map_err(io_error));
|
||||
url::from_str(format!("file://{}", real.display()).as_slice()).map_err(|err|
|
||||
|
|
|
@ -1,8 +1,29 @@
|
|||
use std::{io,fmt};
|
||||
use std::{io,fmt,os};
|
||||
use std::collections::HashMap;
|
||||
use serialize::{Encodable,Encoder};
|
||||
use toml;
|
||||
use util::{other_error,CargoResult,Require};
|
||||
use util::{CargoResult,Require,other_error,simple_human};
|
||||
|
||||
pub struct Config {
|
||||
home_path: Path
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> CargoResult<Config> {
|
||||
Ok(Config {
|
||||
home_path: try!(os::homedir()
|
||||
.require(simple_human("Couldn't find the home directory")))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn git_db_path(&self) -> Path {
|
||||
self.home_path.join(".cargo").join("git").join("db")
|
||||
}
|
||||
|
||||
pub fn git_checkout_path(&self) -> Path {
|
||||
self.home_path.join(".cargo").join("git").join("checkouts")
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq,PartialEq,Clone,Encodable,Decodable)]
|
||||
pub enum Location {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub use self::config::Config;
|
||||
pub use self::process_builder::{process,ProcessBuilder};
|
||||
pub use self::result::{CargoError,CargoResult,Wrap,Require,ToCLI,other_error,human_error,simple_human,toml_error,io_error,process_error};
|
||||
pub use self::paths::realpath;
|
||||
|
|
|
@ -4,7 +4,7 @@ use url::Url;
|
|||
use std::collections::HashMap;
|
||||
use serialize::Decodable;
|
||||
|
||||
use core::{SourceId,GitKind,RegistryKind};
|
||||
use core::{SourceId,GitKind};
|
||||
use core::manifest::{LibKind,Lib};
|
||||
use core::{Summary,Manifest,Target,Dependency,PackageId};
|
||||
use util::{CargoResult,Require,simple_human,toml_error};
|
||||
|
@ -132,8 +132,7 @@ impl TomlManifest {
|
|||
for (n, v) in dependencies.iter() {
|
||||
let (version, source_id) = match *v {
|
||||
SimpleDep(ref string) => {
|
||||
let source_id = SourceId::new(RegistryKind, url::from_str("http://example.com").unwrap());
|
||||
(string.clone(), source_id)
|
||||
(string.clone(), SourceId::for_central())
|
||||
},
|
||||
DetailedDep(ref details) => {
|
||||
let source_id = details.other.find_equiv(&"git").map(|git| {
|
||||
|
@ -141,11 +140,17 @@ impl TomlManifest {
|
|||
let kind = GitKind("master".to_str());
|
||||
let url = url::from_str(git.as_slice()).unwrap();
|
||||
let source_id = SourceId::new(kind, url);
|
||||
// TODO: Don't do this for path
|
||||
sources.push(source_id.clone());
|
||||
source_id
|
||||
});
|
||||
|
||||
(details.version.clone(), try!(source_id.require(simple_human("Dependencies must supply a git location"))))
|
||||
// TODO: Convert relative path dependencies to namespace
|
||||
|
||||
match source_id {
|
||||
Some(source_id) => (details.version.clone(), source_id),
|
||||
None => (details.version.clone(), SourceId::for_central())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue