Refactor links validation to not use PackageSet
authorAlex Crichton <alex@alexcrichton.com>
Fri, 19 Feb 2016 19:02:17 +0000 (11:02 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 19 Feb 2016 19:02:17 +0000 (11:02 -0800)
Eventually we may not have the entire set of packages resident in memory, so
refactor the implementation to validate the `links` attribute in a demand driven
way rather than all at once up front.

src/cargo/ops/cargo_rustc/context.rs
src/cargo/ops/cargo_rustc/links.rs
src/cargo/ops/cargo_rustc/mod.rs

index 40a0b1e6f597bda28ffd05cecc275963103262cc..a3d7fbd7beabe6eaa9fe7bc74d8113947b55ab5d 100644 (file)
@@ -14,6 +14,7 @@ use super::TargetConfig;
 use super::custom_build::{BuildState, BuildScripts};
 use super::fingerprint::Fingerprint;
 use super::layout::{Layout, LayoutProxy};
+use super::links::Links;
 use super::{Kind, Compilation, BuildConfig};
 use super::{ProcessEngine, ExecEngine};
 
@@ -37,6 +38,7 @@ pub struct Context<'a, 'cfg: 'a> {
     pub compiled: HashSet<Unit<'a>>,
     pub build_config: BuildConfig,
     pub build_scripts: HashMap<Unit<'a>, Arc<BuildScripts>>,
+    pub links: Links<'a>,
 
     host: Layout,
     target: Option<Layout>,
@@ -94,6 +96,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
             compiled: HashSet::new(),
             build_scripts: HashMap::new(),
             build_explicit_deps: HashMap::new(),
+            links: Links::new(),
         })
     }
 
index 0609413460b97cf00fd944f312842f16217e5931..779cd13739bb34b1686815cd98659e809a31073f 100644 (file)
@@ -1,38 +1,49 @@
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
-use core::{PackageId, PackageSet};
+use core::PackageId;
 use util::CargoResult;
+use super::Unit;
 
-// Validate that there are no duplicated native libraries among packages and
-// that all packages with `links` also have a build script.
-pub fn validate(deps: &PackageSet) -> CargoResult<()> {
-    let mut map: HashMap<_, &PackageId> = HashMap::new();
+pub struct Links<'a> {
+    validated: HashSet<&'a PackageId>,
+    links: HashMap<String, &'a PackageId>,
+}
+
+impl<'a> Links<'a> {
+    pub fn new() -> Links<'a> {
+        Links {
+            validated: HashSet::new(),
+            links: HashMap::new(),
+        }
+    }
 
-    for dep in deps.packages() {
-        let lib = match dep.manifest().links() {
+    pub fn validate(&mut self, unit: &Unit<'a>) -> CargoResult<()> {
+        if !self.validated.insert(unit.pkg.package_id()) {
+            return Ok(())
+        }
+        let lib = match unit.pkg.manifest().links() {
             Some(lib) => lib,
-            None => continue,
+            None => return Ok(()),
         };
-        if let Some(prev) = map.get(&lib) {
-            let dep = dep.package_id();
-            if prev.name() == dep.name() && prev.source_id() == dep.source_id() {
+        if let Some(prev) = self.links.get(lib) {
+            let pkg = unit.pkg.package_id();
+            if prev.name() == pkg.name() && prev.source_id() == pkg.source_id() {
                 bail!("native library `{}` is being linked to by more \
                        than one version of the same package, but it can \
                        only be linked once; try updating or pinning your \
                        dependencies to ensure that this package only shows \
-                       up once\n\n  {}\n  {}", lib, prev, dep)
+                       up once\n\n  {}\n  {}", lib, prev, pkg)
             } else {
                 bail!("native library `{}` is being linked to by more than \
                        one package, and can only be linked to by one \
-                       package\n\n  {}\n  {}", lib, prev, dep)
+                       package\n\n  {}\n  {}", lib, prev, pkg)
             }
         }
-        if !dep.manifest().targets().iter().any(|t| t.is_custom_build()) {
+        if !unit.pkg.manifest().targets().iter().any(|t| t.is_custom_build()) {
             bail!("package `{}` specifies that it links to `{}` but does not \
-                   have a custom build script", dep.package_id(), lib)
+                   have a custom build script", unit.pkg.package_id(), lib)
         }
-        map.insert(lib, dep.package_id());
+        self.links.insert(lib.to_string(), unit.pkg.package_id());
+        Ok(())
     }
-
-    Ok(())
 }
index 8f2b629de227dc1fc494621dd943aa80cc6cfff9..8268eb50db7911e98e86240f1018286dc2f2f745 100644 (file)
@@ -77,7 +77,6 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>,
             }
         })
     }).collect::<Vec<_>>();
-    try!(links::validate(packages));
 
     let dest = if build_config.release {"release"} else {"debug"};
     let root = packages.packages().find(|p| {
@@ -179,6 +178,7 @@ fn compile<'a, 'cfg: 'a>(cx: &mut Context<'a, 'cfg>,
     let p = profile::start(format!("preparing: {}/{}", unit.pkg,
                                    unit.target.name()));
     try!(fingerprint::prepare_init(cx, unit));
+    try!(cx.links.validate(unit));
 
     let (dirty, fresh, freshness) = if unit.profile.run_custom_build {
         try!(custom_build::prepare(cx, unit))