Allow path + registry dependencies
authorSteven Fackler <sfackler@gmail.com>
Sat, 20 Jan 2018 06:31:11 +0000 (22:31 -0800)
committerSteven Fackler <sfackler@gmail.com>
Sat, 20 Jan 2018 06:31:11 +0000 (22:31 -0800)
Closes #4843

src/cargo/core/dependency.rs
src/cargo/ops/registry.rs
src/cargo/util/toml/mod.rs
tests/alt-registry.rs

index 2f75a0590ca7614e055afa7cf9a1211c48f38cdc..ca944dc19adcbd3b4d666b804911fd4b7f874203 100644 (file)
@@ -22,6 +22,7 @@ pub struct Dependency {
 struct Inner {
     name: String,
     source_id: SourceId,
+    registry_id: Option<SourceId>,
     req: VersionReq,
     specified_req: bool,
     kind: Kind,
@@ -172,6 +173,7 @@ impl Dependency {
             inner: Rc::new(Inner {
                 name: name.to_string(),
                 source_id: source_id.clone(),
+                registry_id: None,
                 req: VersionReq::any(),
                 kind: Kind::Normal,
                 only_match_name: true,
@@ -196,6 +198,15 @@ impl Dependency {
         &self.inner.source_id
     }
 
+    pub fn registry_id(&self) -> Option<&SourceId> {
+        self.inner.registry_id.as_ref()
+    }
+
+    pub fn set_registry_id(&mut self, registry_id: &SourceId) -> &mut Dependency {
+        Rc::make_mut(&mut self.inner).registry_id = Some(registry_id.clone());
+        self
+    }
+
     pub fn kind(&self) -> Kind {
         self.inner.kind
     }
index 4f6acd39afcbc9ca4272bc7013ec79bdf34a70ec..530519f60156613d4cb53258adcf97232ef7b484 100644 (file)
@@ -130,13 +130,17 @@ fn transmit(config: &Config,
 
         // If the dependency is from a different registry, then include the
         // registry in the dependency.
-        let dep_registry = if dep.source_id() != registry_id {
-            Some(dep.source_id().url().to_string())
+        let dep_registry_id = match dep.registry_id() {
+            Some(id) => id,
+            None => bail!("dependency missing registry ID"),
+        };
+        let dep_registry = if dep_registry_id != registry_id {
+            Some(dep_registry_id.url().to_string())
         } else {
             None
         };
 
-        NewCrateDependency {
+        Ok(NewCrateDependency {
             optional: dep.is_optional(),
             default_features: dep.uses_default_features(),
             name: dep.name().to_string(),
@@ -149,8 +153,8 @@ fn transmit(config: &Config,
                 Kind::Development => "dev",
             }.to_string(),
             registry: dep_registry,
-        }
-    }).collect::<Vec<NewCrateDependency>>();
+        })
+    }).collect::<CargoResult<Vec<NewCrateDependency>>>()?;
     let manifest = pkg.manifest();
     let ManifestMetadata {
         ref authors, ref description, ref homepage, ref documentation,
index 9e29419ecdcfbff5a1c9ec66d99308f10a50c161..2515b1c5de461ba64bb4630f461546e304d1a97d 100644 (file)
@@ -925,11 +925,17 @@ impl TomlDependency {
             }
         }
 
+        let registry_id = match details.registry {
+            Some(ref registry) => {
+                cx.features.require(Feature::alternative_registries())?;
+                SourceId::alt_registry(cx.config, registry)?
+            }
+            None => SourceId::crates_io(cx.config)?
+        };
+
         let new_source_id = match (details.git.as_ref(), details.path.as_ref(), details.registry.as_ref()) {
             (Some(_), _, Some(_)) => bail!("dependency ({}) specification is ambiguous. \
                                             Only one of `git` or `registry` is allowed.", name),
-            (_, Some(_), Some(_)) => bail!("dependency ({}) specification is ambiguous. \
-                                            Only one of `path` or `registry` is allowed.", name),
             (Some(git), maybe_path, _) => {
                 if maybe_path.is_some() {
                     let msg = format!("dependency ({}) specification is ambiguous. \
@@ -975,10 +981,7 @@ impl TomlDependency {
                     cx.source_id.clone()
                 }
             },
-            (None, None, Some(registry)) => {
-                cx.features.require(Feature::alternative_registries())?;
-                SourceId::alt_registry(cx.config, registry)?
-            }
+            (None, None, Some(registry)) => SourceId::alt_registry(cx.config, registry)?,
             (None, None, None) => SourceId::crates_io(cx.config)?,
         };
 
@@ -995,7 +998,8 @@ impl TomlDependency {
                                         .or(details.default_features2)
                                         .unwrap_or(true))
            .set_optional(details.optional.unwrap_or(false))
-           .set_platform(cx.platform.clone());
+           .set_platform(cx.platform.clone())
+           .set_registry_id(&registry_id);
         if let Some(kind) = kind {
             dep.set_kind(kind);
         }
index a80ca5c4668755925cfd699fbb5c12fee357369e..c73de4e0c1c32faf1013d3817adf42debdc11381 100644 (file)
@@ -180,7 +180,9 @@ fn depend_on_alt_registry_depends_on_crates_io() {
 }
 
 #[test]
-fn registry_incompatible_with_path() {
+fn registry_and_path_dep_works() {
+    registry::init();
+
     let p = project("foo")
         .file("Cargo.toml", r#"
             cargo-features = ["alternative-registries"]
@@ -191,19 +193,33 @@ fn registry_incompatible_with_path() {
             authors = []
 
             [dependencies.bar]
-            path = ""
+            path = "bar"
             registry = "alternative"
         "#)
         .file("src/main.rs", "fn main() {}")
+        .file("bar/Cargo.toml", r#"
+            [project]
+            name = "bar"
+            version = "0.0.1"
+            authors = []
+        "#)
+        .file("bar/src/lib.rs", "")
         .build();
 
     assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
-                execs().with_status(101)
-                .with_stderr_contains("  dependency (bar) specification is ambiguous. Only one of `path` or `registry` is allowed."));
+                execs().with_status(0)
+                .with_stderr(&format!("\
+[COMPILING] bar v0.0.1 ({dir}/bar)
+[COMPILING] foo v0.0.1 ({dir})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
+",
+        dir = p.url())));
 }
 
 #[test]
 fn registry_incompatible_with_git() {
+    registry::init();
+
     let p = project("foo")
         .file("Cargo.toml", r#"
             cargo-features = ["alternative-registries"]