Fix optional dependencies and required dev-deps
authorAlex Crichton <alex@alexcrichton.com>
Wed, 2 May 2018 00:03:23 +0000 (17:03 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 2 May 2018 00:03:23 +0000 (17:03 -0700)
This fixes an accidental bug introduced in #5300 by ensuring a local map keeps
track of the fact that there can be multiple dependencies for one name

Closes #5453

src/cargo/core/resolver/mod.rs
src/cargo/core/summary.rs
src/cargo/sources/registry/index.rs
tests/testsuite/features.rs

index 47697d49568fc9cd5445dc6e7e003a1ffdd005c3..e153daf088a71884f6873b924df485ce442dc109 100644 (file)
@@ -340,15 +340,18 @@ fn activate_deps_loop(
                         backtracked = true;
                         Ok((candidate, has_another))
                     }
-                    None => Err(activation_error(
-                        &cx,
-                        registry.registry,
-                        &parent,
-                        &dep,
-                        &conflicting_activations,
-                        &candidates,
-                        config,
-                    )),
+                    None => {
+                        debug!("no candidates found");
+                        Err(activation_error(
+                            &cx,
+                            registry.registry,
+                            &parent,
+                            &dep,
+                            &conflicting_activations,
+                            &candidates,
+                            config,
+                        ))
+                    }
                 }
             })?;
 
index 22c923ad904c603a7e1d61d117c1aa8592d67836..b7c36d8dd68fe446443026825d7d69f47fd0c5d6 100644 (file)
@@ -140,10 +140,12 @@ fn build_feature_map(
     namespaced: bool,
 ) -> CargoResult<FeatureMap> {
     use self::FeatureValue::*;
-    let dep_map: HashMap<_, _> = dependencies
-        .iter()
-        .map(|d| (d.name().as_str(), d))
-        .collect();
+    let mut dep_map = HashMap::new();
+    for dep in dependencies.iter() {
+        dep_map.entry(dep.name().as_str())
+            .or_insert(Vec::new())
+            .push(dep);
+    }
 
     let mut map = BTreeMap::new();
     for (feature, list) in features.iter() {
@@ -159,7 +161,7 @@ fn build_feature_map(
         let mut dependency_found = if namespaced {
             match dep_map.get(feature.as_str()) {
                 Some(ref dep_data) => {
-                    if !dep_data.is_optional() {
+                    if !dep_data.iter().any(|d| d.is_optional()) {
                         bail!(
                             "Feature `{}` includes the dependency of the same name, but this is \
                              left implicit in the features included by this feature.\n\
@@ -196,7 +198,9 @@ fn build_feature_map(
                     }
                 }
             };
-            let is_optional_dep = dep_data.map_or(false, |d| d.is_optional());
+            let is_optional_dep = dep_data.iter()
+                .flat_map(|d| d.iter())
+                .any(|d| d.is_optional());
             if let FeatureValue::Crate(ref dep_name) = val {
                 // If we have a dependency value, check if this is the dependency named
                 // the same as the feature that we were looking for.
index a8e887d96165d3b58bd72c431eea71971cea4a52..878def113912f4b7042d85b013b74c2ee4db319d 100644 (file)
@@ -113,13 +113,19 @@ impl<'cfg> RegistryIndex<'cfg> {
             // interpretation of each line here and older cargo will simply
             // ignore the new lines.
             ret.extend(lines.filter_map(|line| {
-                self.parse_registry_package(line).ok().and_then(|v| {
-                    if online || load.is_crate_downloaded(v.0.package_id()) {
-                        Some(v)
-                    } else {
-                        None
+                let (summary, locked) = match self.parse_registry_package(line) {
+                    Ok(p) => p,
+                    Err(e) => {
+                        info!("failed to parse `{}` registry package: {}", name, e);
+                        trace!("line: {}", line);
+                        return None
                     }
-                })
+                };
+                if online || load.is_crate_downloaded(summary.package_id()) {
+                    Some((summary, locked))
+                } else {
+                    None
+                }
             }));
 
             Ok(())
index 4030985ccea9935ba3d74fd6ee590bcca0812049..ceb09bb56a4ee8c71c50e932064c4578ac68c37d 100644 (file)
@@ -1999,3 +1999,35 @@ fn namespaced_same_name() {
         execs().with_status(0),
     );
 }
+
+#[test]
+fn only_dep_is_optional() {
+    Package::new("bar", "0.1.0").publish();
+
+    let p = project("foo")
+        .file(
+            "Cargo.toml",
+            r#"
+                [project]
+                name = "foo"
+                version = "0.0.1"
+                authors = []
+
+                [features]
+                foo = ['bar']
+
+                [dependencies]
+                bar = { version = "0.1", optional = true }
+
+                [dev-dependencies]
+                bar = "0.1"
+            "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    assert_that(
+        p.cargo("build"),
+        execs().with_status(0),
+    );
+}