]> git.proxmox.com Git - cargo.git/commitdiff
Beginnings of a dependency resolver
authorCarl Lerche <me@carllerche.com>
Thu, 10 Apr 2014 01:07:47 +0000 (18:07 -0700)
committerCarlhuda <carlhuda@tilde.io>
Fri, 11 Apr 2014 22:11:10 +0000 (15:11 -0700)
Makefile
libs/hamcrest-rust
src/cargo/core/dependency.rs [new file with mode: 0644]
src/cargo/core/mod.rs
src/cargo/core/package.rs [new file with mode: 0644]
src/cargo/core/registry.rs [new file with mode: 0644]
src/cargo/core/resolver.rs [new file with mode: 0644]
src/cargo/mod.rs
tests/support.rs
tests/test_cargo_compile.rs

index 6d50d154d7349e0c0180b57850cb7be57a4e3bfa..683f4ecfd0edeb0b55ffa125a4856c1443e231f2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ $(HAMMER): $(wildcard libs/hammer.rs/src/*.rs)
 $(TOML): $(wildcard libs/rust-toml/src/toml/*.rs)
        cd libs/rust-toml && make
 
-$(HAMCREST): $(wildcard libs/hamcrest-rust/src/hamcrest/*.rs)
+$(HAMCREST): $(shell find libs/hamcrest-rust/src/hamcrest -name '*.rs')
        cd libs/hamcrest-rust && make
 
 # === Cargo
@@ -49,13 +49,20 @@ $(BIN_TARGETS): target/%: src/bin/%.rs $(HAMMER) $(TOML) $(LIBCARGO)
 TEST_SRC = $(wildcard tests/*.rs)
 TEST_DEPS = $(DEPS) -L libs/hamcrest-rust/target
 
-target/tests: $(BIN_TARGETS) $(HAMCREST) $(TEST_SRC)
-       $(RUSTC) --test --crate-type=lib $(TEST_DEPS) -Ltarget --out-dir target tests/tests.rs
+target/tests/test-integration: $(BIN_TARGETS) $(HAMCREST) $(TEST_SRC)
+       $(RUSTC) --test --crate-type=lib $(TEST_DEPS) -Ltarget -o $@  tests/tests.rs
 
-test-integration: target/tests
+target/tests/test-unit: $(HAMCREST) $(SRC) $(HAMMER)
+       mkdir -p target/tests
+       $(RUSTC) --test $(RUSTC_FLAGS) $(TEST_DEPS) -o $@ src/cargo/mod.rs
+
+test-unit: target/tests/test-unit
+       target/tests/test-unit
+
+test-integration: target/tests/test-integration
        CARGO_BIN_PATH=$(PWD)/target/ $<
 
-test: test-integration
+test: test-unit test-integration
 
 clean:
        rm -rf target
@@ -66,7 +73,7 @@ distclean: clean
        cd libs/rust-toml && make clean
 
 # Setup phony tasks
-.PHONY: all clean distclean test test-integration libcargo
+.PHONY: all clean distclean test test-unit test-integration libcargo
 
 # Disable unnecessary built-in rules
 .SUFFIXES:
index 634495ea08f3c3b019dc4e6d464ada83b00f926f..54ef9a3064d85c9756a9c183087a9e4e28056651 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 634495ea08f3c3b019dc4e6d464ada83b00f926f
+Subproject commit 54ef9a3064d85c9756a9c183087a9e4e28056651
diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs
new file mode 100644 (file)
index 0000000..4425af0
--- /dev/null
@@ -0,0 +1,16 @@
+
+// TODO: add version restrictions
+#[deriving(Clone,Eq,Show)]
+pub struct Dependency {
+  name: ~str,
+}
+
+impl Dependency {
+  pub fn new(name: &str) -> Dependency {
+    Dependency { name: name.to_owned() }
+  }
+
+  pub fn get_name<'a>(&'a self) -> &'a str {
+    self.name.as_slice()
+  }
+}
index e13802c892e1b8733dc780486688cc28bd753e11..56b552a66cdcd2dbe8ec4a7a51f5cb9b6b89b04e 100644 (file)
@@ -1,8 +1,19 @@
 
+pub use self::dependency::Dependency;
+pub use self::registry::{
+  Registry,
+  MemRegistry};
+
 pub use self::manifest::{
   Manifest,
   Project,
   LibTarget,
   ExecTarget};
 
+pub use self::package::Package;
+
+mod dependency;
 mod manifest;
+mod package;
+mod registry;
+mod resolver;
diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs
new file mode 100644 (file)
index 0000000..9bd4a21
--- /dev/null
@@ -0,0 +1,25 @@
+use std::vec::Vec;
+use core;
+
+/**
+ * Represents a rust library internally to cargo. This will things like where
+ * on the local system the code is located, it's remote location, dependencies,
+ * etc..
+ *
+ * This differs from core::Project
+ */
+#[deriving(Clone,Eq,Show)]
+pub struct Package {
+  name: ~str,
+  deps: Vec<core::Dependency>
+}
+
+impl Package {
+  pub fn new(name: &str, deps: &Vec<core::Dependency>) -> Package {
+    Package { name: name.to_owned(), deps: deps.clone() }
+  }
+
+  pub fn get_name<'a>(&'a self) -> &'a str {
+    self.name.as_slice()
+  }
+}
diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs
new file mode 100644 (file)
index 0000000..a5efe14
--- /dev/null
@@ -0,0 +1,37 @@
+use std::vec::Vec;
+
+use core::{
+  // Dependency,
+  Package};
+
+pub trait Registry {
+  fn query<'a>(&'a self, name: &str) -> Vec<&'a Package>;
+}
+
+/*
+ *
+ * ===== Temporary for convenience =====
+ *
+ */
+
+pub struct MemRegistry {
+  packages: Vec<Package>
+}
+
+impl MemRegistry {
+  pub fn new(packages: &Vec<Package>) -> MemRegistry {
+    MemRegistry { packages: packages.clone() }
+  }
+
+  pub fn empty() -> MemRegistry {
+    MemRegistry { packages: Vec::new() }
+  }
+}
+
+impl Registry for MemRegistry {
+  fn query<'a>(&'a self, name: &str) -> Vec<&'a Package> {
+    self.packages.iter()
+      .filter(|pkg| name == pkg.get_name())
+      .collect()
+  }
+}
diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs
new file mode 100644 (file)
index 0000000..fcf167e
--- /dev/null
@@ -0,0 +1,90 @@
+use collections::HashMap;
+use core;
+use {CargoResult};
+
+#[allow(dead_code)]
+pub fn resolve(deps: &Vec<core::Dependency>, registry: &core::Registry) -> CargoResult<Vec<core::Package>> {
+  let mut remaining = deps.clone();
+  let mut resolve = HashMap::<&str, &core::Package>::new();
+
+  loop {
+    let curr = match remaining.pop() {
+      Some(curr) => curr,
+      None => return Ok(resolve.values().map(|v| (*v).clone()).collect())
+    };
+
+    let opts = registry.query(curr.get_name());
+
+    assert!(!resolve.contains_key_equiv(&curr.get_name()), "already traversed {}", curr.get_name());
+    // Temporary, but we must have exactly one option to satisfy the dep
+    assert!(opts.len() == 1, "invalid num of results {}", opts.len());
+
+    let pkg = opts.get(0);
+    resolve.insert(pkg.get_name(), *pkg);
+  }
+}
+
+#[cfg(test)]
+mod test {
+
+  use hamcrest::{
+    assert_that,
+    equal_to,
+    of_len,
+    contains
+  };
+
+  use core::{
+    MemRegistry,
+    Dependency,
+    Package
+  };
+
+  use super::{
+    resolve
+  };
+
+  fn pkg(name: &str) -> Package {
+    Package::new(name, &Vec::<Dependency>::new())
+  }
+
+  fn dep(name: &str) -> Dependency {
+    Dependency::new(name)
+  }
+
+  fn registry(pkgs: Vec<Package>) -> MemRegistry {
+    MemRegistry::new(&pkgs)
+  }
+
+  #[test]
+  pub fn test_resolving_empty_dependency_list() {
+    let res = resolve(&vec!(), &registry(vec!())).unwrap();
+
+    assert_that(&res, equal_to(&Vec::<Package>::new()));
+  }
+
+  #[test]
+  pub fn test_resolving_only_package() {
+    let reg = registry(vec!(pkg("foo")));
+    let res = resolve(&vec!(dep("foo")), &reg);
+
+    assert_that(&res.unwrap(), equal_to(&vec!(pkg("foo"))));
+  }
+
+  #[test]
+  pub fn test_resolving_one_dep() {
+    let reg = registry(vec!(pkg("foo"), pkg("bar")));
+    let res = resolve(&vec!(dep("foo")), &reg);
+
+    assert_that(&res.unwrap(), equal_to(&vec!(pkg("foo"))));
+  }
+
+  #[test]
+  pub fn test_resolving_multiple_deps() {
+    let reg = registry(vec!(pkg("foo"), pkg("bar"), pkg("baz")));
+    let res = resolve(&vec!(dep("foo"), dep("baz")), &reg).unwrap();
+
+    assert_that(&res, of_len(2));
+    assert_that(&res, contains(vec!(pkg("foo"), pkg("baz"))).exactly());
+  }
+}
index 43701c7017e2f16b11597cf3b29a52db7f78f7e9..c26e4b412d07f35ec1fdc259e3f123e14e79e2df 100644 (file)
@@ -3,8 +3,12 @@
 
 #![allow(deprecated_owned_vector)]
 
-extern crate serialize;
+extern crate collections;
 extern crate hammer;
+extern crate serialize;
+
+#[cfg(test)]
+extern crate hamcrest;
 
 use serialize::{Decoder,Encoder,Decodable,Encodable,json};
 use std::io;
@@ -12,6 +16,7 @@ use std::fmt;
 use std::fmt::{Show,Formatter};
 use hammer::{FlagDecoder,FlagConfig,HammerError};
 
+
 pub mod core;
 pub mod util;
 
index bfce652544a2694660f27b827288ca420fd5eec9..ac5d6587d1cfd4a3fbdd27119fd6cad8af841b77 100644 (file)
@@ -161,7 +161,7 @@ struct Execs {
 
 impl Execs {
 
-  pub fn with_stdout(mut self, expected: &str) -> Execs {
+  pub fn with_stdout(mut ~self, expected: &str) -> ~Execs {
     self.expect_stdout = Some(expected.to_owned());
     self
   }
@@ -204,7 +204,7 @@ impl ham::SelfDescribing for Execs {
 }
 
 impl ham::Matcher<ProcessBuilder> for Execs {
-  fn matches(&self, process: &ProcessBuilder) -> ham::MatchResult {
+  fn matches(&self, process: ProcessBuilder) -> ham::MatchResult {
     let res = process.exec_with_output();
 
     match res {
@@ -214,8 +214,8 @@ impl ham::Matcher<ProcessBuilder> for Execs {
   }
 }
 
-pub fn execs() -> Execs {
-  Execs {
+pub fn execs() -> ~Execs {
+  ~Execs {
     expect_stdout: None,
     expect_stdin: None,
     expect_exit_code: None
index 02b1cc4a3e322dc18827a3515696fc1ccb1bb947..c30e997e0927466e8712cab481603a564f315696 100644 (file)
@@ -32,7 +32,7 @@ test!(cargo_compile_with_explicit_manifest_path {
     assert_that(&p.root().join("target/foo"), existing_file());
 
     assert_that(
-      &cargo::util::process("foo").extra_path(p.root().join("target")),
+      cargo::util::process("foo").extra_path(p.root().join("target")),
       execs().with_stdout("i am foo\n"));
 })