Skip to content

Commit

Permalink
Implement source redirection
Browse files Browse the repository at this point in the history
This commit implements a scheme for .cargo/config files where sources can be
redirected to other sources. The purpose of this will be to override crates.io
for a few use cases:

  * Replace it with a mirror site that is sync'd to crates.io
  * Replace it with a "directory source" or some other local source

This major feature of this redirection, however, is that none of it is encoded
into the lock file. If one source is redirected to another then it is assumed
that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in
both location). The lock file simply encodes the canonical soure (e.g.
crates.io) rather than the replacement source. In the end this means that
Cargo.lock files can be generated from any replacement source and shipped to
other locations without the lockfile oscillating about where packages came from.

Eventually this support will be extended to `Cargo.toml` itself (which will be
encoded into the lock file), but that support is not implemented today. The
syntax for what was implemented today looks like:

    # .cargo/config
    [source.my-awesome-registry]
    registry = 'https://example.com/path/to/index'

    [source.crates-io]
    replace-with = 'my-awesome-registry'

Each source will have a canonical name and will be configured with the various
keys underneath it (today just 'registry' and 'directory' will be accepted). The
global `crates-io` source represents crates from the standard registry, and this
can be replaced with other mirror sources.

All tests have been modified to use this new infrastructure instead of the old
`registry.index` configuration. This configuration is now also deprecated and
will emit an unconditional warning about how it will no longer be used in the
future.

Finally, all subcommands now use this "source map" except for `cargo publish`,
which will always publish to the default registry (in this case crates.io).
  • Loading branch information
alexcrichton committed Aug 1, 2016
1 parent 2b19333 commit 8214bb9
Show file tree
Hide file tree
Showing 29 changed files with 639 additions and 172 deletions.
2 changes: 1 addition & 1 deletion src/bin/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
} else if options.arg_crate == None {
try!(SourceId::for_path(&config.cwd()))
} else {
try!(SourceId::for_central(config))
try!(SourceId::crates_io(config))
};

let krate = options.arg_crate.as_ref().map(|s| &s[..]);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
let token = match options.arg_token.clone() {
Some(token) => token,
None => {
let src = try!(SourceId::for_central(config));
let src = try!(SourceId::crates_io(config));
let mut src = RegistrySource::new(&src, config);
try!(src.update());
let config = try!(src.config());
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/core/package_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,12 @@ impl fmt::Debug for PackageId {
mod tests {
use super::PackageId;
use core::source::SourceId;
use sources::RegistrySource;
use sources::CRATES_IO;
use util::ToUrl;

#[test]
fn invalid_version_handled_nicely() {
let loc = RegistrySource::default_url().to_url().unwrap();
let loc = CRATES_IO.to_url().unwrap();
let repo = SourceId::for_registry(&loc);

assert!(PackageId::new("foo", "1.0", &repo).is_err());
Expand Down
16 changes: 9 additions & 7 deletions src/cargo/core/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::{HashSet, HashMap};
use core::{Source, SourceId, SourceMap, Summary, Dependency, PackageId, Package};
use core::PackageSet;
use util::{CargoResult, ChainError, Config, human, profile};
use sources::config::SourceConfigMap;

/// Source of information about a group of packages.
///
Expand Down Expand Up @@ -47,7 +48,6 @@ impl<'a, T: ?Sized + Registry + 'a> Registry for Box<T> {
/// operations if necessary) and is ready to be queried for packages.
pub struct PackageRegistry<'cfg> {
sources: SourceMap<'cfg>,
config: &'cfg Config,

// A list of sources which are considered "overrides" which take precedent
// when querying for packages.
Expand All @@ -71,6 +71,7 @@ pub struct PackageRegistry<'cfg> {
source_ids: HashMap<SourceId, (SourceId, Kind)>,

locked: HashMap<SourceId, HashMap<String, Vec<(PackageId, Vec<PackageId>)>>>,
source_config: SourceConfigMap<'cfg>,
}

#[derive(PartialEq, Eq, Clone, Copy)]
Expand All @@ -81,14 +82,15 @@ enum Kind {
}

impl<'cfg> PackageRegistry<'cfg> {
pub fn new(config: &'cfg Config) -> PackageRegistry<'cfg> {
PackageRegistry {
pub fn new(config: &'cfg Config) -> CargoResult<PackageRegistry<'cfg>> {
let source_config = try!(SourceConfigMap::new(config));
Ok(PackageRegistry {
sources: SourceMap::new(),
source_ids: HashMap::new(),
overrides: Vec::new(),
config: config,
source_config: source_config,
locked: HashMap::new(),
}
})
}

pub fn get(self, package_ids: &[PackageId]) -> PackageSet<'cfg> {
Expand Down Expand Up @@ -164,8 +166,8 @@ impl<'cfg> PackageRegistry<'cfg> {

fn load(&mut self, source_id: &SourceId, kind: Kind) -> CargoResult<()> {
(|| {
// Save off the source
let source = source_id.load(self.config);
let source = try!(self.source_config.load(source_id));

if kind == Kind::Override {
self.overrides.push(source_id.clone());
}
Expand Down
27 changes: 22 additions & 5 deletions src/cargo/core/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ use std::fmt::{self, Formatter};
use std::hash;
use std::path::Path;
use std::sync::Arc;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
use std::sync::atomic::Ordering::SeqCst;

use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use url::Url;

use core::{Package, PackageId, Registry};
use sources::{PathSource, GitSource, RegistrySource};
use ops;
use sources::git;
use sources::{PathSource, GitSource, RegistrySource, CRATES_IO};
use util::{human, Config, CargoResult, ToUrl};

/// A Source finds and downloads remote packages based on names and
Expand Down Expand Up @@ -185,8 +188,22 @@ impl SourceId {
///
/// This is the main cargo registry by default, but it can be overridden in
/// a `.cargo/config`.
pub fn for_central(config: &Config) -> CargoResult<SourceId> {
Ok(SourceId::for_registry(&try!(RegistrySource::url(config))))
pub fn crates_io(config: &Config) -> CargoResult<SourceId> {
let cfg = try!(ops::registry_configuration(config));
let url = if let Some(ref index) = cfg.index {
static WARNED: AtomicBool = ATOMIC_BOOL_INIT;
if !WARNED.swap(true, SeqCst) {
try!(config.shell().warn("custom registry support via \
the `registry.index` configuration is \
being removed, this functionality \
will not work in the future"));
}
&index[..]
} else {
CRATES_IO
};
let url = try!(url.to_url());
Ok(SourceId::for_registry(&url))
}

pub fn url(&self) -> &Url {
Expand Down Expand Up @@ -247,7 +264,7 @@ impl SourceId {
Kind::Registry => {}
_ => return false,
}
self.inner.url.to_string() == RegistrySource::default_url()
self.inner.url.to_string() == CRATES_IO
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn clean(ws: &Workspace, opts: &CleanOptions) -> CargoResult<()> {
return rm_rf(&target_dir);
}

let mut registry = PackageRegistry::new(opts.config);
let mut registry = try!(PackageRegistry::new(opts.config));
let resolve = try!(ops::resolve_ws(&mut registry, ws));
let packages = ops::get_resolved_packages(&resolve, registry);

Expand Down
15 changes: 8 additions & 7 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn resolve_dependencies<'a>(ws: &Workspace<'a>,
no_default_features: bool)
-> CargoResult<(PackageSet<'a>, Resolve)> {

let mut registry = PackageRegistry::new(ws.config());
let mut registry = try!(PackageRegistry::new(ws.config()));

if let Some(source) = source {
registry.add_preloaded(try!(ws.current()).package_id().source_id(),
Expand Down Expand Up @@ -389,6 +389,7 @@ fn add_overrides<'a>(registry: &mut PackageRegistry<'a>,
None => return Ok(())
};
let current = try!(ws.current());

let paths = paths.val.iter().map(|&(ref s, ref p)| {
// The path listed next to the string is the config file in which the
// key was located, so we want to pop off the `.cargo/config` component
Expand Down Expand Up @@ -482,11 +483,11 @@ fn scrape_target_config(config: &Config, triple: &str)
rerun_if_changed: Vec::new(),
warnings: Vec::new(),
};
for (k, value) in try!(value.table()).0 {
for (k, value) in try!(value.table(&lib_name)).0 {
let key = format!("{}.{}", key, k);
match &k[..] {
"rustc-flags" => {
let (flags, definition) = try!(value.string());
let (flags, definition) = try!(value.string(&k));
let whence = format!("in `{}` (in {})", key,
definition.display());
let (paths, links) = try!(
Expand All @@ -496,22 +497,22 @@ fn scrape_target_config(config: &Config, triple: &str)
output.library_links.extend(links);
}
"rustc-link-lib" => {
let list = try!(value.list());
let list = try!(value.list(&k));
output.library_links.extend(list.iter()
.map(|v| v.0.clone()));
}
"rustc-link-search" => {
let list = try!(value.list());
let list = try!(value.list(&k));
output.library_paths.extend(list.iter().map(|v| {
PathBuf::from(&v.0)
}));
}
"rustc-cfg" => {
let list = try!(value.list());
let list = try!(value.list(&k));
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
}
_ => {
let val = try!(value.string()).0;
let val = try!(value.string(&k)).0;
output.metadata.push((k.clone(), val.to_string()));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use util::CargoResult;

/// Executes `cargo fetch`.
pub fn fetch<'a>(ws: &Workspace<'a>) -> CargoResult<(Resolve, PackageSet<'a>)> {
let mut registry = PackageRegistry::new(ws.config());
let mut registry = try!(PackageRegistry::new(ws.config()));
let resolve = try!(ops::resolve_ws(&mut registry, ws));
let packages = get_resolved_packages(&resolve, registry);
for id in resolve.iter() {
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/ops/cargo_generate_lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct UpdateOptions<'a> {
}

pub fn generate_lockfile(ws: &Workspace) -> CargoResult<()> {
let mut registry = PackageRegistry::new(ws.config());
let mut registry = try!(PackageRegistry::new(ws.config()));
let resolve = try!(ops::resolve_with_previous(&mut registry, ws,
Method::Everything,
None, None));
Expand All @@ -35,7 +35,7 @@ pub fn update_lockfile(ws: &Workspace, opts: &UpdateOptions)
Some(resolve) => resolve,
None => return generate_lockfile(ws),
};
let mut registry = PackageRegistry::new(opts.config);
let mut registry = try!(PackageRegistry::new(opts.config));
let mut to_avoid = HashSet::new();

if opts.to_update.is_empty() {
Expand Down
5 changes: 3 additions & 2 deletions src/cargo/ops/cargo_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use toml;
use core::{SourceId, Source, Package, Dependency, PackageIdSpec};
use core::{PackageId, Workspace};
use ops::{self, CompileFilter};
use sources::{GitSource, PathSource, RegistrySource};
use sources::{GitSource, PathSource, SourceConfigMap};
use util::{CargoResult, ChainError, Config, human, internal};
use util::{Filesystem, FileLock};

Expand Down Expand Up @@ -54,6 +54,7 @@ pub fn install(root: Option<&str>,
force: bool) -> CargoResult<()> {
let config = opts.config;
let root = try!(resolve_root(root, config));
let map = try!(SourceConfigMap::new(config));
let (pkg, source) = if source_id.is_git() {
try!(select_pkg(GitSource::new(source_id, config), source_id,
krate, vers, &mut |git| git.read_packages()))
Expand All @@ -70,7 +71,7 @@ pub fn install(root: Option<&str>,
source_id, krate, vers,
&mut |path| path.read_packages()))
} else {
try!(select_pkg(RegistrySource::new(source_id, config),
try!(select_pkg(try!(map.load(source_id)),
source_id, krate, vers,
&mut |_| Err(human("must specify a crate to install from \
crates.io, or use --path or --git to \
Expand Down
8 changes: 4 additions & 4 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,21 +247,21 @@ fn run_verify(ws: &Workspace, tar: &File, opts: &PackageOpts) -> CargoResult<()>
try!(archive.unpack(dst.parent().unwrap()));
let manifest_path = dst.join("Cargo.toml");

// When packages are uploaded to the registry, all path dependencies are
// implicitly converted to registry-based dependencies, so we rewrite those
// When packages are uploaded to a registry, all path dependencies are
// implicitly converted to registry dependencies, so we rewrite those
// dependencies here.
//
// We also make sure to point all paths at `dst` instead of the previous
// location that the package was originally read from. In locking the
// `SourceId` we're telling it that the corresponding `PathSource` will be
// considered updated and we won't actually read any packages.
let registry = try!(SourceId::for_central(config));
let cratesio = try!(SourceId::crates_io(config));
let precise = Some("locked".to_string());
let new_src = try!(SourceId::for_path(&dst)).with_precise(precise);
let new_pkgid = try!(PackageId::new(pkg.name(), pkg.version(), &new_src));
let new_summary = pkg.summary().clone().map_dependencies(|d| {
if !d.source_id().is_path() { return d }
d.clone_inner().set_source_id(registry.clone()).into_dependency()
d.clone_inner().set_source_id(cratesio.clone()).into_dependency()
});
let mut new_manifest = pkg.manifest().clone();
new_manifest.set_summary(new_summary.override_id(new_pkgid));
Expand Down
11 changes: 6 additions & 5 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,17 @@ pub fn registry(config: &Config,
// Parse all configuration options
let RegistryConfig {
token: token_config,
index: index_config,
index: _index_config,
} = try!(registry_configuration(config));
let token = token.or(token_config);
let index = index.or(index_config).unwrap_or(RegistrySource::default_url());
let index = try!(index.to_url());
let sid = SourceId::for_registry(&index);
let sid = match index {
Some(index) => SourceId::for_registry(&try!(index.to_url())),
None => try!(SourceId::crates_io(config)),
};
let api_host = {
let mut src = RegistrySource::new(&sid, config);
try!(src.update().chain_error(|| {
human(format!("failed to update registry {}", index))
human(format!("failed to update {}", sid))
}));
(try!(src.config())).api
};
Expand Down
Loading

0 comments on commit 8214bb9

Please sign in to comment.