diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index e0b8d36016d..85c0fe118be 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -27,6 +27,7 @@ pub struct Manifest { publish: bool, replace: Vec<(PackageIdSpec, Dependency)>, workspace: WorkspaceConfig, + registry: Option, } #[derive(Clone, Debug)] @@ -222,7 +223,8 @@ impl Manifest { profiles: Profiles, publish: bool, replace: Vec<(PackageIdSpec, Dependency)>, - workspace: WorkspaceConfig) -> Manifest { + workspace: WorkspaceConfig, + registry: Option) -> Manifest { Manifest { summary: summary, targets: targets, @@ -235,6 +237,7 @@ impl Manifest { publish: publish, replace: replace, workspace: workspace, + registry: registry, } } @@ -251,6 +254,7 @@ impl Manifest { pub fn profiles(&self) -> &Profiles { &self.profiles } pub fn publish(&self) -> bool { self.publish } pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] { &self.replace } + pub fn registry(&self) -> &Option { &self.registry } pub fn links(&self) -> Option<&str> { self.links.as_ref().map(|s| &s[..]) } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 898745460f9..6cfa6f8e806 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -37,6 +37,7 @@ struct SerializedPackage<'a> { targets: &'a [Target], features: &'a HashMap>, manifest_path: &'a str, + registry: &'a Option, } impl ser::Serialize for Package { @@ -49,6 +50,7 @@ impl ser::Serialize for Package { let license = manmeta.license.as_ref().map(String::as_ref); let license_file = manmeta.license_file.as_ref().map(String::as_ref); let description = manmeta.description.as_ref().map(String::as_ref); + let registry = self.manifest.registry(); SerializedPackage { name: &package_id.name(), @@ -62,6 +64,7 @@ impl ser::Serialize for Package { targets: &self.manifest.targets(), features: summary.features(), manifest_path: &self.manifest_path.display().to_string(), + registry: registry, }.serialize(s) } } @@ -94,6 +97,7 @@ impl Package { pub fn version(&self) -> &Version { self.package_id().version() } pub fn authors(&self) -> &Vec { &self.manifest.metadata().authors } pub fn publish(&self) -> bool { self.manifest.publish() } + pub fn registry(&self) -> &Option { &self.manifest.registry() } pub fn has_custom_build(&self) -> bool { self.targets().iter().any(|t| t.is_custom_build()) diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index c2915afcf55..90069e3e104 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -18,7 +18,7 @@ use core::{Package, SourceId, Workspace}; use core::dependency::Kind; use core::manifest::ManifestMetadata; use ops; -use sources::{RegistrySource}; +use sources::RegistrySource; use util::config; use util::paths; use util::{CargoResult, human, ChainError, ToUrl}; @@ -51,6 +51,17 @@ pub fn publish(ws: &Workspace, opts: &PublishOpts) -> CargoResult<()> { let (mut registry, reg_id) = registry(opts.config, opts.token.clone(), opts.index.clone())?; + + if let &Some(ref package_registry) = pkg.registry() { + if let Some(ref index) = opts.index { + if index != package_registry { + bail!("Package registry does not match current registry"); + } + } else { + bail!("Custom registry in package definiton, but host not overridden"); + } + } + verify_dependencies(pkg, ®_id)?; // Prepare a tarball, with a non-surpressable warning if metadata @@ -80,12 +91,14 @@ fn verify_dependencies(pkg: &Package, registry_src: &SourceId) when publishing.\ndependency `{}` does not specify \ a version", dep.name()) } - } else if dep.source_id() != registry_src { - bail!("crates cannot be published to crates.io with dependencies sourced from \ - a repository\neither publish `{}` as its own crate on crates.io and \ - specify a crates.io version as a dependency or pull it into this \ - repository and specify it with a path and version\n(crate `{}` has \ - repository path `{}`)", dep.name(), dep.name(), dep.source_id()); + } else if !dep.source_id().is_default_registry() { + if dep.source_id() != registry_src { + bail!("crates cannot be published to crates.io with dependencies sourced from \ + a repository\neither publish `{}` as its own crate on crates.io and \ + specify a crates.io version as a dependency or pull it into this \ + repository and specify it with a path and version\n(crate `{}` has \ + repository path `{}`)", dep.name(), dep.name(), dep.source_id()); + } } } Ok(()) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 771f48ddfda..20cf3532cad 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -243,6 +243,7 @@ pub struct DetailedTomlDependency { default_features: Option, #[serde(rename = "default_features")] default_features2: Option, + registry: Option, } #[derive(Deserialize)] @@ -435,6 +436,7 @@ pub struct TomlProject { #[serde(rename = "license-file")] license_file: Option, repository: Option, + registry: Option, } #[derive(Deserialize)] @@ -810,7 +812,8 @@ impl TomlManifest { profiles, publish, replace, - workspace_config); + workspace_config, + project.registry.clone()); if project.license_file.is_some() && project.license.is_some() { manifest.add_warning("only one of `license` or \ `license-file` is necessary".to_string()); @@ -1046,7 +1049,14 @@ impl TomlDependency { cx.source_id.clone() } }, - (None, None) => SourceId::crates_io(cx.config)?, + (None, None) => { + if let Some(registry) = details.registry { + let url = registry.to_url()?; + SourceId::for_registry(&url) + } else { + SourceId::crates_io(cx.config)? + } + }, }; let version = details.version.as_ref().map(|v| &v[..]); diff --git a/src/doc/manifest.md b/src/doc/manifest.md index 29ee4026254..0d91e7a96c6 100644 --- a/src/doc/manifest.md +++ b/src/doc/manifest.md @@ -150,6 +150,11 @@ license = "..." # (similar to the readme key). license-file = "..." +# This optional URL points to a registry index. The package will then be +# published to the registry specified rather than the default. When publishing, +# this index must be given as the host. +registry = "..." + # Optional specification of badges to be displayed on crates.io. The badges # currently available are Travis CI, Appveyor, and GitLab latest build status, # specified using the following parameters: diff --git a/src/doc/specifying-dependencies.md b/src/doc/specifying-dependencies.md index 248d4fe024f..b21ba04e56e 100644 --- a/src/doc/specifying-dependencies.md +++ b/src/doc/specifying-dependencies.md @@ -99,6 +99,17 @@ Here are some examples of inequality requirements: Multiple version requirements can also be separated with a comma, e.g. `>= 1.2, < 1.5`. +# Specifying dependencies from a custom registry + +To use a custom registry (rather than crates.io) for a dependency, specify the +url of the index: + +```toml +[dependencies.rand] +version = "0.1.11" +registry = "https://github.com/my_awesome_fork/crates.io-index" +``` + # Specifying dependencies from `git` repositories To depend on a library located in a `git` repository, the minimum information diff --git a/tests/metadata.rs b/tests/metadata.rs index 25a0edf01e5..78859fc791a 100644 --- a/tests/metadata.rs +++ b/tests/metadata.rs @@ -23,6 +23,7 @@ fn cargo_metadata_simple() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ @@ -94,6 +95,7 @@ crate-type = ["lib", "staticlib"] "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ @@ -164,6 +166,7 @@ fn cargo_metadata_with_deps_and_version() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ @@ -199,6 +202,7 @@ fn cargo_metadata_with_deps_and_version() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ @@ -234,6 +238,7 @@ fn cargo_metadata_with_deps_and_version() { "license": "MIT", "license_file": null, "description": "foo", + "registry": null, "targets": [ { "kind": [ @@ -302,6 +307,7 @@ name = "ex" "description": null, "source": null, "dependencies": [], + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -364,6 +370,7 @@ crate-type = ["rlib", "dylib"] "description": null, "source": null, "dependencies": [], + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -423,6 +430,7 @@ fn workspace_metadata() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -443,6 +451,7 @@ fn workspace_metadata() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -498,6 +507,7 @@ fn workspace_metadata_no_deps() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -518,6 +528,7 @@ fn workspace_metadata_no_deps() { "license": null, "license_file": null, "description": null, + "registry": null, "targets": [ { "kind": [ "lib" ], @@ -562,6 +573,7 @@ const MANIFEST_OUTPUT: &'static str= "license": null, "license_file": null, "description": null, + "registry": null, "targets":[{ "kind":["bin"], "crate_types":["bin"], diff --git a/tests/read-manifest.rs b/tests/read-manifest.rs index f656ab2108c..a80daf188a0 100644 --- a/tests/read-manifest.rs +++ b/tests/read-manifest.rs @@ -14,6 +14,7 @@ static MANIFEST_OUTPUT: &'static str = r#" "description": null, "source":null, "dependencies":[], + "registry": null, "targets":[{ "kind":["bin"], "crate_types":["bin"],