about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-02-15 18:53:18 -0800
committerbors <bors@rust-lang.org>2013-02-15 18:53:18 -0800
commit354da4108a483ece3b6424ea7d92e3b6e91d4239 (patch)
tree086b516f606d598da7d2fee28193e550ace8fbbf
parent3e97cce27d55bb123fbf8c69f4bb2bd0a3ba9c08 (diff)
parent585d6f7b00eab09099504924e70837966f5fe678 (diff)
downloadrust-354da4108a483ece3b6424ea7d92e3b6e91d4239.tar.gz
rust-354da4108a483ece3b6424ea7d92e3b6e91d4239.zip
auto merge of #4799 : graydon/rust/rustpkg, r=graydon
Taking over where #4610 left off. Much rebasing and tidying.
-rw-r--r--AUTHORS.txt2
-rw-r--r--Makefile.in12
-rw-r--r--README.md2
-rw-r--r--mk/clean.mk12
-rw-r--r--mk/dist.mk2
-rw-r--r--mk/install.mk12
-rw-r--r--mk/pp.mk2
-rw-r--r--mk/tests.mk6
-rw-r--r--mk/tools.mk32
-rw-r--r--src/README.txt2
-rw-r--r--src/driver/driver.rs4
-rw-r--r--src/libcargo/cargo.rc1981
-rw-r--r--src/libcargo/pgp.rs115
-rw-r--r--src/libcargo/sources.json14
-rw-r--r--src/libcore/core.rc1
-rw-r--r--src/libcore/option.rs30
-rw-r--r--src/librustc/driver/driver.rs28
-rw-r--r--src/librustc/metadata/filesearch.rs54
-rw-r--r--src/librustpkg/rustpkg.rc1038
-rw-r--r--src/librustpkg/usage.rs121
-rw-r--r--src/librustpkg/util.rs803
-rw-r--r--src/libstd/semver.rs395
-rw-r--r--src/libstd/std.rc1
23 files changed, 2477 insertions, 2192 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 628fa4c86da..92903a26093 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -161,4 +161,4 @@ Wade Mealing <wmealing@gmail.com>
 William Ting <william.h.ting@gmail.com>
 Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
 Youngsoo Son <ysson83@gmail.com>
-Zack Corr <zackcorr95@gmail.com>
+Zack Corr <zack@z0w0.me>
diff --git a/Makefile.in b/Makefile.in
index e476ac1dba2..cf6fcd42021 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -131,7 +131,7 @@ CFG_STDLIB :=$(call CFG_LIB_NAME,std)
 CFG_LIBRUSTC :=$(call CFG_LIB_NAME,rustc)
 CFG_LIBSYNTAX :=$(call CFG_LIB_NAME,syntax)
 CFG_LIBFUZZER :=$(call CFG_LIB_NAME,fuzzer)
-CFG_LIBCARGO :=$(call CFG_LIB_NAME,cargo)
+CFG_LIBRUSTPKG :=$(call CFG_LIB_NAME,rustpkg)
 CFG_LIBRUSTDOC :=$(call CFG_LIB_NAME,rustdoc)
 CFG_LIBRUSTI :=$(call CFG_LIB_NAME,rusti)
 
@@ -140,7 +140,7 @@ CORELIB_GLOB :=$(call CFG_LIB_GLOB,core)
 LIBRUSTC_GLOB :=$(call CFG_LIB_GLOB,rustc)
 LIBSYNTAX_GLOB :=$(call CFG_LIB_GLOB,syntax)
 LIBFUZZER_GLOB :=$(call CFG_LIB_GLOB,fuzzer)
-LIBCARGO_GLOB :=$(call CFG_LIB_GLOB,cargo)
+LIBRUSTPKG_GLOB :=$(call CFG_LIB_GLOB,rustpkg)
 LIBRUSTDOC_GLOB :=$(call CFG_LIB_GLOB,rustdoc)
 LIBRUSTI_GLOB :=$(call CFG_LIB_GLOB,rusti)
 STDLIB_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,std)
@@ -148,7 +148,7 @@ CORELIB_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,core)
 LIBRUSTC_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustc)
 LIBSYNTAX_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,syntax)
 LIBFUZZER_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,fuzzer)
-LIBCARGO_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,cargo)
+LIBRUSTPKG_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustpkg)
 LIBRUSTDOC_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustdoc)
 LIBRUSTI_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rusti)
 
@@ -371,11 +371,11 @@ SREQ$(1)_T_$(2)_H_$(3) = \
 CSREQ$(1)_T_$(2)_H_$(3) = \
 	$$(TSREQ$(1)_T_$(2)_H_$(3)) \
 	$$(HBIN$(1)_H_$(3))/fuzzer$$(X) \
-	$$(HBIN$(1)_H_$(3))/cargo$$(X) \
+	$$(HBIN$(1)_H_$(3))/rustpkg$$(X) \
 	$$(HBIN$(1)_H_$(3))/rustdoc$$(X) \
 	$$(HBIN$(1)_H_$(3))/rusti$$(X) \
 	$$(HLIB$(1)_H_$(3))/$$(CFG_LIBFUZZER) \
-	$$(HLIB$(1)_H_$(3))/$$(CFG_LIBCARGO) \
+	$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTPKG) \
 	$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTDOC) \
 	$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTI) \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_CORELIB) \
@@ -383,7 +383,7 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX)  \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC) \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBFUZZER) \
-	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBCARGO) \
+	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTPKG) \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTDOC) \
 	$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTI)
 
diff --git a/README.md b/README.md
index 27b63c1080b..a34f8814f02 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ for more information on them.
 
 When complete, `make install` will place several programs into
 `/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
-API-documentation tool, and `cargo`, the Rust package manager.
+API-documentation tool, and `rustpkg`, the Rust package manager and build system.
 
 [wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
 [tarball]: http://static.rust-lang.org/dist/rust-0.5.tar.gz
diff --git a/mk/clean.mk b/mk/clean.mk
index 57c14b0afc8..3b35071c818 100644
--- a/mk/clean.mk
+++ b/mk/clean.mk
@@ -64,12 +64,12 @@ define CLEAN_HOST_STAGE_N
 clean$(1)_H_$(2):
 	$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustc$(X)
 	$(Q)rm -f $$(HBIN$(1)_H_$(2))/fuzzer$(X)
-	$(Q)rm -f $$(HBIN$(1)_H_$(2))/cargo$(X)
+	$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X)
 	$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X)
 	$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X)
 	$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBFUZZER)
-	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBCARGO)
+	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_CORELIB)
@@ -82,7 +82,7 @@ clean$(1)_H_$(2):
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBFUZZER_GLOB)
-	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBCARGO_GLOB)
+	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB)
 	$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM)
@@ -99,11 +99,11 @@ define CLEAN_TARGET_STAGE_N
 clean$(1)_T_$(2)_H_$(3):
 	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$(X)
 	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/fuzzer$(X)
-	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/cargo$(X)
+	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X)
 	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X)
 	$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBFUZZER)
-	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBCARGO)
+	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB)
@@ -115,7 +115,7 @@ clean$(1)_T_$(2)_H_$(3):
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBFUZZER_GLOB)
-	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBCARGO_GLOB)
+	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM)
 	$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
diff --git a/mk/dist.mk b/mk/dist.mk
index dd9b2011707..5b6740461e6 100644
--- a/mk/dist.mk
+++ b/mk/dist.mk
@@ -25,7 +25,7 @@ PKG_FILES := \
     $(addprefix $(S)src/,                      \
       README.txt                               \
       driver                                   \
-      libcargo                                 \
+      librustpkg                               \
       librusti                                 \
       librustc                                 \
       compiletest                              \
diff --git a/mk/install.mk b/mk/install.mk
index 555b28e9697..7f3ec816e02 100644
--- a/mk/install.mk
+++ b/mk/install.mk
@@ -55,7 +55,7 @@ install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
 	$$(Q)$$(call INSTALL_LIB, \
 		$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBSYNTAX_GLOB))
 	$$(Q)$$(call INSTALL_LIB, \
-		$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBCARGO_GLOB))
+		$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTPKG_GLOB))
 	$$(Q)$$(call INSTALL_LIB, \
 		$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTDOC_GLOB))
 	$$(Q)$$(call INSTALL_LIB, \
@@ -87,11 +87,11 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_HOST_TRIPLE)_H_$(CFG_HOST_TRIPLE))
 	$(Q)mkdir -p $(PREFIX_LIB)
 	$(Q)mkdir -p $(PREFIX_ROOT)/share/man/man1
 	$(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X))
-	$(Q)$(call INSTALL,$(HB2),$(PHB),cargo$(X))
+	$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X))
 	$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X))
 	$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X))
 	$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTC))
-	$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBCARGO))
+	$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTPKG))
 	$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTDOC))
 	$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTI))
 	$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(CORELIB_GLOB))
@@ -112,11 +112,11 @@ HOST_LIB_FROM_HL_GLOB = \
 
 uninstall:
 	$(Q)rm -f $(PHB)/rustc$(X)
-	$(Q)rm -f $(PHB)/cargo$(X)
+	$(Q)rm -f $(PHB)/rustpkg$(X)
 	$(Q)rm -f $(PHB)/rusti$(X)
 	$(Q)rm -f $(PHB)/rustdoc$(X)
 	$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM)
-	$(Q)rm -f $(PHL)/$(CFG_LIBCARGO)
+	$(Q)rm -f $(PHL)/$(CFG_LIBRUSTPKG)
 	$(Q)rm -f $(PHL)/$(CFG_LIBRUSTC)
 	$(Q)rm -f $(PHL)/$(CFG_LIBRUSTDOC)
 	$(Q)rm -f $(PHL)/$(CFG_LIBRUSTI)
@@ -126,7 +126,7 @@ uninstall:
           $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB)) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB)) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB)) \
-          $(call HOST_LIB_FROM_HL_GLOB,$(LIBCARGO_GLOB)) \
+          $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB)) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB)) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB)) \
         ; \
diff --git a/mk/pp.mk b/mk/pp.mk
index 4d8baa2ea32..772365b1058 100644
--- a/mk/pp.mk
+++ b/mk/pp.mk
@@ -18,7 +18,7 @@ else
               $(wildcard $(S)src/test/*/*.rs    \
                          $(S)src/test/*/*/*.rs) \
               $(wildcard $(S)src/fuzzer/*.rs)   \
-              $(wildcard $(S)src/cargo/*.rs) \
+              $(wildcard $(S)src/rustpkg/*.rs) \
               $(wildcard $(S)src/rusti/*.rs)
 
   PP_INPUTS_FILTERED = $(shell echo $(PP_INPUTS) | xargs grep -L \
diff --git a/mk/tests.mk b/mk/tests.mk
index abe9ba60ecd..8bcf5d5ad10 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -14,7 +14,7 @@
 ######################################################################
 
 # The names of crates that must be tested
-TEST_CRATES = core std syntax rustc rustdoc rusti cargo
+TEST_CRATES = core std syntax rustc rustdoc rusti rustpkg
 
 # Markdown files under doc/ that should have their code extracted and run
 DOC_TEST_NAMES = tutorial tutorial-ffi tutorial-macros tutorial-borrowed-ptr tutorial-tasks rust
@@ -229,8 +229,8 @@ $(3)/test/rustctest.stage$(1)-$(2)$$(X):					\
 	@$$(call E, compile_and_link: $$@)
 	$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
 
-$(3)/test/cargotest.stage$(1)-$(2)$$(X):					\
-		$$(CARGO_LIB) $$(CARGO_INPUTS)		\
+$(3)/test/rustpkgtest.stage$(1)-$(2)$$(X):					\
+		$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS)		\
 		$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC)
 	@$$(call E, compile_and_link: $$@)
 	$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
diff --git a/mk/tools.mk b/mk/tools.mk
index 31956eda246..1554d760a49 100644
--- a/mk/tools.mk
+++ b/mk/tools.mk
@@ -14,13 +14,13 @@
 FUZZER_LIB := $(S)src/libfuzzer/fuzzer.rc
 FUZZER_INPUTS := $(wildcard $(addprefix $(S)src/libfuzzer/, *.rs))
 
-# The test runner that runs the cfail/rfail/rpass and bench tests
+# The test runner that runs the cfail/rfail/rpass and bxench tests
 COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rc
 COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*rs)
 
-# Cargo, the package manager
-CARGO_LIB := $(S)src/libcargo/cargo.rc
-CARGO_INPUTS := $(wildcard $(S)src/libcargo/*rs)
+# Rustpkg, the package manager and build system
+RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rc
+RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*rs)
 
 # Rustdoc, the documentation tool
 RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rc
@@ -57,8 +57,8 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X):			\
 	@$$(call E, compile_and_link: $$@)
 	$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
 
-$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBCARGO):		\
-		$$(CARGO_LIB) $$(CARGO_INPUTS)				\
+$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUSTPKG):		\
+		$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS)		    \
 		$$(TSREQ$(1)_T_$(4)_H_$(3))					\
 		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_CORELIB)	\
 		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_STDLIB)	\
@@ -66,11 +66,11 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBCARGO):		\
 	@$$(call E, compile_and_link: $$@)
 	$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
 
-$$(TBIN$(1)_T_$(4)_H_$(3))/cargo$$(X):				\
+$$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X):				\
 		$$(DRIVER_CRATE) 							\
-		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBCARGO)
+		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUSTPKG)
 	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg cargo -o $$@ $$<
+	$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustpkg -o $$@ $$<
 
 $$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUSTDOC):		\
 		$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS)			\
@@ -134,19 +134,19 @@ $$(HBIN$(2)_H_$(4))/compiletest$$(X):				\
 	$$(Q)cp $$< $$@
 
 
-$$(HLIB$(2)_H_$(4))/$$(CFG_LIBCARGO):				\
-		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBCARGO)	\
+$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUSTPKG):				\
+		$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUSTPKG)	\
 		$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUSTC)		\
 		$$(HSREQ$(2)_H_$(4))
 	@$$(call E, cp: $$@)
 	$$(Q)cp $$< $$@
-	$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBCARGO_GLOB) \
-		$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBCARGO_DSYM_GLOB)) \
+	$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTPKG_GLOB) \
+		$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTPKG_DSYM_GLOB)) \
 	        $$(HLIB$(2)_H_$(4))
 
-$$(HBIN$(2)_H_$(4))/cargo$$(X):					\
-		$$(TBIN$(1)_T_$(4)_H_$(3))/cargo$$(X)	\
-		$$(HLIB$(2)_H_$(4))/$$(CFG_LIBCARGO)	\
+$$(HBIN$(2)_H_$(4))/rustpkg$$(X):				\
+		$$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X)	\
+		$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUSTPKG)	\
 		$$(HSREQ$(2)_H_$(4))
 	@$$(call E, cp: $$@)
 	$$(Q)cp $$< $$@
diff --git a/src/README.txt b/src/README.txt
index c8029098cfa..1b06c4259fc 100644
--- a/src/README.txt
+++ b/src/README.txt
@@ -29,7 +29,7 @@ test/auxiliary     - Dependencies of tests
 
 compiletest/       The test runner
 
-libcargo/          The package manager
+librustpkg/        The package manager and build system
 
 librusti/          The JIT REPL
 
diff --git a/src/driver/driver.rs b/src/driver/driver.rs
index 0c1cc566fe2..b2c4f69d302 100644
--- a/src/driver/driver.rs
+++ b/src/driver/driver.rs
@@ -11,8 +11,8 @@
 #[no_core];
 extern mod core(vers = "0.6");
 
-#[cfg(cargo)]
-extern mod this(name = "cargo", vers = "0.6");
+#[cfg(rustpkg)]
+extern mod this(name = "rustpkg", vers = "0.6");
 
 #[cfg(fuzzer)]
 extern mod this(name = "fuzzer", vers = "0.6");
diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc
deleted file mode 100644
index dceeb96800f..00000000000
--- a/src/libcargo/cargo.rc
+++ /dev/null
@@ -1,1981 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-// cargo.rs - Rust package manager
-
-// Local Variables:
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-
-#[link(name = "cargo",
-       vers = "0.6",
-       uuid = "9ff87a04-8fed-4295-9ff8-f99bb802650b",
-       url = "https://github.com/mozilla/rust/tree/master/src/cargo")];
-
-#[crate_type = "lib"];
-
-#[no_core];
-
-#[legacy_modes];
-
-#[allow(vecs_implicitly_copyable,
-        non_implicitly_copyable_typarams)];
-#[allow(non_camel_case_types)];
-#[allow(deprecated_mode)];
-#[allow(deprecated_pattern)];
-#[allow(deprecated_self)];
-
-extern mod core(vers = "0.6");
-extern mod std(vers = "0.6");
-extern mod rustc(vers = "0.6");
-extern mod syntax(vers = "0.6");
-
-mod pgp;
-
-use rustc::metadata::filesearch::{get_cargo_root, get_cargo_root_nearest};
-use rustc::metadata::filesearch::{get_cargo_sysroot, libdir};
-
-use core::*;
-
-use core::dvec::DVec;
-use core::io::WriterUtil;
-use core::result::{Ok, Err};
-use core::hashmap::linear::LinearMap;
-use std::getopts::{optflag, optopt, opt_present};
-use std::oldmap::HashMap;
-use std::{oldmap, json, tempfile, term, sort, getopts};
-use syntax::codemap::span;
-use syntax::diagnostic::span_handler;
-use syntax::diagnostic;
-use syntax::{ast, codemap, parse, visit, attr};
-
-pub struct Package {
-    name: ~str,
-    uuid: ~str,
-    url: ~str,
-    method: ~str,
-    description: ~str,
-    reference: Option<~str>,
-    tags: ~[~str],
-    versions: ~[(~str, ~str)]
-}
-
-pub impl cmp::Ord for Package {
-    pure fn lt(&self, other: &Package) -> bool {
-        if (*self).name.lt(&(*other).name) { return true; }
-        if (*other).name.lt(&(*self).name) { return false; }
-        if (*self).uuid.lt(&(*other).uuid) { return true; }
-        if (*other).uuid.lt(&(*self).uuid) { return false; }
-        if (*self).url.lt(&(*other).url) { return true; }
-        if (*other).url.lt(&(*self).url) { return false; }
-        if (*self).method.lt(&(*other).method) { return true; }
-        if (*other).method.lt(&(*self).method) { return false; }
-        if (*self).description.lt(&(*other).description) { return true; }
-        if (*other).description.lt(&(*self).description) { return false; }
-        if (*self).tags.lt(&(*other).tags) { return true; }
-        if (*other).tags.lt(&(*self).tags) { return false; }
-        if (*self).versions.lt(&(*other).versions) { return true; }
-        return false;
-    }
-    pure fn le(&self, other: &Package) -> bool { !(*other).lt(&(*self)) }
-    pure fn ge(&self, other: &Package) -> bool { !(*self).lt(other)     }
-    pure fn gt(&self, other: &Package) -> bool { (*other).lt(&(*self))  }
-}
-
-pub struct Source {
-    name: ~str,
-    mut url: ~str,
-    mut method: ~str,
-    mut key: Option<~str>,
-    mut keyfp: Option<~str>,
-    packages: DVec<Package>
-}
-
-pub struct Cargo {
-    pgp: bool,
-    root: Path,
-    installdir: Path,
-    bindir: Path,
-    libdir: Path,
-    workdir: Path,
-    sourcedir: Path,
-    sources: oldmap::HashMap<~str, @Source>,
-    mut current_install: ~str,
-    dep_cache: oldmap::HashMap<~str, bool>,
-    opts: Options
-}
-
-pub struct Crate {
-    name: ~str,
-    vers: ~str,
-    uuid: ~str,
-    desc: Option<~str>,
-    sigs: Option<~str>,
-    crate_type: Option<~str>,
-    deps: ~[~str]
-}
-
-pub struct Options {
-    test: bool,
-    mode: Mode,
-    free: ~[~str],
-    help: bool,
-}
-
-#[deriving_eq]
-pub enum Mode { SystemMode, UserMode, LocalMode }
-
-pub fn opts() -> ~[getopts::Opt] {
-    ~[optflag(~"g"), optflag(~"G"), optflag(~"test"),
-     optflag(~"h"), optflag(~"help")]
-}
-
-pub fn info(msg: ~str) {
-    let out = io::stdout();
-
-    if term::color_supported() {
-        term::fg(out, term::color_green);
-        out.write_str(~"info: ");
-        term::reset(out);
-        out.write_line(msg);
-    } else { out.write_line(~"info: " + msg); }
-}
-
-pub fn warn(msg: ~str) {
-    let out = io::stdout();
-
-    if term::color_supported() {
-        term::fg(out, term::color_yellow);
-        out.write_str(~"warning: ");
-        term::reset(out);
-        out.write_line(msg);
-    }else { out.write_line(~"warning: " + msg); }
-}
-
-pub fn error(msg: ~str) {
-    let out = io::stdout();
-
-    if term::color_supported() {
-        term::fg(out, term::color_red);
-        out.write_str(~"error: ");
-        term::reset(out);
-        out.write_line(msg);
-    }
-    else { out.write_line(~"error: " + msg); }
-}
-
-pub fn is_uuid(id: ~str) -> bool {
-    let parts = str::split_str(id, ~"-");
-    if vec::len(parts) == 5u {
-        let mut correct = 0u;
-        for vec::eachi(parts) |i, part| {
-            fn is_hex_digit(+ch: char) -> bool {
-                ('0' <= ch && ch <= '9') ||
-                ('a' <= ch && ch <= 'f') ||
-                ('A' <= ch && ch <= 'F')
-            }
-
-            if !part.all(is_hex_digit) {
-                return false;
-            }
-
-            match i {
-                0u => {
-                    if part.len() == 8u {
-                        correct += 1u;
-                    }
-                }
-                1u | 2u | 3u => {
-                    if part.len() == 4u {
-                        correct += 1u;
-                    }
-                }
-                4u => {
-                    if part.len() == 12u {
-                        correct += 1u;
-                    }
-                }
-                _ => { }
-            }
-        }
-        if correct >= 5u {
-            return true;
-        }
-    }
-    return false;
-}
-
-#[test]
-pub fn test_is_uuid() {
-    assert is_uuid(~"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaafAF09");
-    assert !is_uuid(~"aaaaaaaa-aaaa-aaaa-aaaaa-aaaaaaaaaaaa");
-    assert !is_uuid(~"");
-    assert !is_uuid(~"aaaaaaaa-aaa -aaaa-aaaa-aaaaaaaaaaaa");
-    assert !is_uuid(~"aaaaaaaa-aaa!-aaaa-aaaa-aaaaaaaaaaaa");
-    assert !is_uuid(~"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa-a");
-    assert !is_uuid(~"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaป");
-}
-
-// FIXME (#2661): implement url/URL parsing so we don't have to resort
-// to weak checks
-
-pub fn has_archive_extension(p: ~str) -> bool {
-    str::ends_with(p, ~".tar") ||
-    str::ends_with(p, ~".tar.gz") ||
-    str::ends_with(p, ~".tar.bz2") ||
-    str::ends_with(p, ~".tar.Z") ||
-    str::ends_with(p, ~".tar.lz") ||
-    str::ends_with(p, ~".tar.xz") ||
-    str::ends_with(p, ~".tgz") ||
-    str::ends_with(p, ~".tbz") ||
-    str::ends_with(p, ~".tbz2") ||
-    str::ends_with(p, ~".tb2") ||
-    str::ends_with(p, ~".taz") ||
-    str::ends_with(p, ~".tlz") ||
-    str::ends_with(p, ~".txz")
-}
-
-pub fn is_archive_path(u: ~str) -> bool {
-    has_archive_extension(u) && os::path_exists(&Path(u))
-}
-
-pub fn is_archive_url(u: ~str) -> bool {
-    // FIXME (#2661): this requires the protocol bit - if we had proper
-    // url parsing, we wouldn't need it
-
-    match str::find_str(u, ~"://") {
-        option::Some(_) => has_archive_extension(u),
-        _ => false
-    }
-}
-
-pub fn is_git_url(url: ~str) -> bool {
-    if str::ends_with(url, ~"/") { str::ends_with(url, ~".git/") }
-    else {
-        str::starts_with(url, ~"git://") || str::ends_with(url, ~".git")
-    }
-}
-
-pub fn assume_source_method(url: ~str) -> ~str {
-    if is_git_url(url) {
-        return ~"git";
-    }
-    if str::starts_with(url, ~"file://") || os::path_exists(&Path(url)) {
-        return ~"file";
-    }
-
-    ~"curl"
-}
-
-pub fn load_link(mis: ~[@ast::meta_item]) -> (Option<~str>,
-                                              Option<~str>,
-                                              Option<~str>) {
-    let mut name = None;
-    let mut vers = None;
-    let mut uuid = None;
-    for mis.each |a| {
-        match a.node {
-            ast::meta_name_value(v, codemap::spanned { node: ast::lit_str(s),
-                                                   _ }) => {
-                match v {
-                    ~"name" => name = Some(*s),
-                    ~"vers" => vers = Some(*s),
-                    ~"uuid" => uuid = Some(*s),
-                    _ => { }
-                }
-            }
-            _ => fail!(~"load_link: meta items must be name-values")
-        }
-    }
-    (name, vers, uuid)
-}
-
-pub fn load_crate(filename: &Path) -> Option<Crate> {
-    let sess = parse::new_parse_sess(None);
-    let c = parse::parse_crate_from_file(filename, ~[], sess);
-
-    let mut name = None;
-    let mut vers = None;
-    let mut uuid = None;
-    let mut desc = None;
-    let mut sigs = None;
-    let mut crate_type = None;
-
-    for c.node.attrs.each |a| {
-        match a.node.value.node {
-            ast::meta_name_value(v, codemap::spanned { node: ast::lit_str(_),
-                                                   _ }) => {
-                match v {
-                    ~"desc" => desc = Some(v),
-                    ~"sigs" => sigs = Some(v),
-                    ~"crate_type" => crate_type = Some(v),
-                    _ => { }
-                }
-            }
-            ast::meta_list(v, mis) => {
-                if v == ~"link" {
-                    let (n, v, u) = load_link(mis);
-                    name = n;
-                    vers = v;
-                    uuid = u;
-                }
-            }
-            _ => {
-                fail!(~"crate attributes may not contain " +
-                     ~"meta_words");
-            }
-        }
-    }
-
-    struct Env {
-        mut deps: ~[~str]
-    }
-
-    fn goto_view_item(ps: syntax::parse::parse_sess, e: @Env,
-                      i: @ast::view_item) {
-        match i.node {
-            ast::view_item_use(ident, metas, _) => {
-                let name_items =
-                    attr::find_meta_items_by_name(metas, ~"name");
-                let m = if name_items.is_empty() {
-                    metas + ~[attr::mk_name_value_item_str(
-                        ~"name", *ps.interner.get(ident))]
-                } else {
-                    metas
-                };
-                let mut attr_name = ident;
-                let mut attr_vers = ~"";
-                let mut attr_from = ~"";
-
-              for m.each |item| {
-                    match attr::get_meta_item_value_str(*item) {
-                        Some(value) => {
-                            let name = attr::get_meta_item_name(*item);
-
-                            match name {
-                                ~"vers" => attr_vers = value,
-                                ~"from" => attr_from = value,
-                                _ => ()
-                            }
-                        }
-                        None => ()
-                    }
-                }
-
-                let query = if !str::is_empty(attr_from) {
-                    attr_from
-                } else {
-                    if !str::is_empty(attr_vers) {
-                        ps.interner.get(attr_name) + ~"@" + attr_vers
-                    } else { *ps.interner.get(attr_name) }
-                };
-
-                match *ps.interner.get(attr_name) {
-                    ~"std" | ~"core" => (),
-                    _ => e.deps.push(query)
-                }
-            }
-            _ => ()
-        }
-    }
-    fn goto_item(_e: @Env, _i: @ast::item) {
-    }
-
-    let e = @Env {
-        mut deps: ~[]
-    };
-    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
-        visit_view_item: |a| goto_view_item(sess, e, a),
-        visit_item: |a| goto_item(e, a),
-        .. *visit::default_simple_visitor()
-    });
-
-    visit::visit_crate(*c, (), v);
-
-    let deps = copy e.deps;
-
-    match (name, vers, uuid) {
-        (Some(name0), Some(vers0), Some(uuid0)) => {
-            Some(Crate {
-                name: name0,
-                vers: vers0,
-                uuid: uuid0,
-                desc: desc,
-                sigs: sigs,
-                crate_type: crate_type,
-                deps: deps })
-        }
-        _ => return None
-    }
-}
-
-pub fn print(s: ~str) {
-    io::stdout().write_line(s);
-}
-
-pub fn rest(s: ~str, start: uint) -> ~str {
-    if (start >= str::len(s)) {
-        ~""
-    } else {
-        str::slice(s, start, str::len(s))
-    }
-}
-
-pub fn need_dir(s: &Path) {
-    if os::path_is_dir(s) { return; }
-    if !os::make_dir(s, 493_i32 /* oct: 755 */) {
-        fail!(fmt!("can't make_dir %s", s.to_str()));
-    }
-}
-
-pub fn valid_pkg_name(s: &str) -> bool {
-    fn is_valid_digit(+c: char) -> bool {
-        ('0' <= c && c <= '9') ||
-        ('a' <= c && c <= 'z') ||
-        ('A' <= c && c <= 'Z') ||
-        c == '-' ||
-        c == '_'
-    }
-
-    s.all(is_valid_digit)
-}
-
-pub fn parse_source(name: ~str, j: &json::Json) -> @Source {
-    if !valid_pkg_name(name) {
-        fail!(fmt!("'%s' is an invalid source name", name));
-    }
-
-    match *j {
-        json::Object(ref j) => {
-            let mut url = match j.find(&~"url") {
-                Some(&json::String(u)) => copy u,
-                _ => fail!(~"needed 'url' field in source")
-            };
-            let method = match j.find(&~"method") {
-                Some(&json::String(u)) => copy u,
-                _ => assume_source_method(url)
-            };
-            let key = match j.find(&~"key") {
-                Some(&json::String(u)) => Some(copy u),
-                _ => None
-            };
-            let keyfp = match j.find(&~"keyfp") {
-                Some(&json::String(u)) => Some(copy u),
-                _ => None
-            };
-            if method == ~"file" {
-                url = os::make_absolute(&Path(url)).to_str();
-            }
-            return @Source {
-                name: name,
-                mut url: url,
-                mut method: method,
-                mut key: key,
-                mut keyfp: keyfp,
-                packages: DVec() };
-        }
-        _ => fail!(~"needed dict value in source")
-    };
-}
-
-pub fn try_parse_sources(filename: &Path,
-                         sources: oldmap::HashMap<~str, @Source>) {
-    if !os::path_exists(filename)  { return; }
-    let c = io::read_whole_file_str(filename);
-    match json::from_str(c.get()) {
-        Ok(json::Object(j)) => {
-            for j.each |&(k, v)| {
-                sources.insert(copy *k, parse_source(*k, v));
-                debug!("source: %s", *k);
-            }
-        }
-        Ok(_) => fail!(~"malformed sources.json"),
-        Err(e) => fail!(fmt!("%s:%s", filename.to_str(), e.to_str()))
-    }
-}
-
-pub fn load_one_source_package(src: @Source, p: &json::Object) {
-    let name = match p.find(&~"name") {
-        Some(&json::String(n)) => {
-            if !valid_pkg_name(n) {
-                warn(~"malformed source json: "
-                     + src.name + ~", '" + n + ~"'"+
-                     ~" is an invalid name (alphanumeric, underscores and" +
-                     ~" dashes only)");
-                return;
-            }
-            n
-        }
-        _ => {
-            warn(~"malformed source json: " + src.name + ~" (missing name)");
-            return;
-        }
-    };
-
-    let uuid = match p.find(&~"uuid") {
-        Some(&json::String(n)) => {
-            if !is_uuid(n) {
-                warn(~"malformed source json: "
-                     + src.name + ~", '" + n + ~"'"+
-                     ~" is an invalid uuid");
-                return;
-            }
-            copy n
-        }
-        _ => {
-            warn(~"malformed source json: " + src.name + ~" (missing uuid)");
-            return;
-        }
-    };
-
-    let url = match p.find(&~"url") {
-        Some(&json::String(n)) => copy n,
-        _ => {
-            warn(~"malformed source json: " + src.name + ~" (missing url)");
-            return;
-        }
-    };
-
-    let method = match p.find(&~"method") {
-        Some(&json::String(n)) => copy n,
-        _ => {
-            warn(~"malformed source json: "
-                 + src.name + ~" (missing method)");
-            return;
-        }
-    };
-
-    let reference = match p.find(&~"ref") {
-        Some(&json::String(n)) => Some(copy n),
-        _ => None
-    };
-
-    let mut tags = ~[];
-    match p.find(&~"tags") {
-        Some(&json::List(ref js)) => {
-          for js.each |j| {
-                match *j {
-                    json::String(ref j) => tags.grow(1u, j),
-                    _ => ()
-                }
-            }
-        }
-        _ => ()
-    }
-
-    let description = match p.find(&~"description") {
-        Some(&json::String(n)) => copy n,
-        _ => {
-            warn(~"malformed source json: " + src.name
-                 + ~" (missing description)");
-            return;
-        }
-    };
-
-    let newpkg = Package {
-        name: name,
-        uuid: uuid,
-        url: url,
-        method: method,
-        description: description,
-        reference: reference,
-        tags: tags,
-        versions: ~[]
-    };
-
-    match src.packages.position(|pkg| pkg.uuid == uuid) {
-        Some(idx) => {
-            src.packages.set_elt(idx, newpkg);
-            log(debug, ~"  updated package: " + src.name + ~"/" + name);
-        }
-        None => {
-            src.packages.push(newpkg);
-        }
-    }
-
-    log(debug, ~"  loaded package: " + src.name + ~"/" + name);
-}
-
-pub fn load_source_info(c: &Cargo, src: @Source) {
-    let dir = c.sourcedir.push(src.name);
-    let srcfile = dir.push("source.json");
-    if !os::path_exists(&srcfile) { return; }
-    let srcstr = io::read_whole_file_str(&srcfile);
-    match json::from_str(srcstr.get()) {
-        Ok(ref json @ json::Object(_)) => {
-            let o = parse_source(src.name, json);
-
-            src.key = o.key;
-            src.keyfp = o.keyfp;
-        }
-        Ok(_) => {
-            warn(~"malformed source.json: " + src.name +
-                 ~"(source info is not a dict)");
-        }
-        Err(e) => {
-            warn(fmt!("%s:%s", src.name, e.to_str()));
-        }
-    };
-}
-pub fn load_source_packages(c: &Cargo, src: @Source) {
-    log(debug, ~"loading source: " + src.name);
-    let dir = c.sourcedir.push(src.name);
-    let pkgfile = dir.push("packages.json");
-    if !os::path_exists(&pkgfile) { return; }
-    let pkgstr = io::read_whole_file_str(&pkgfile);
-    match json::from_str(pkgstr.get()) {
-        Ok(json::List(ref js)) => {
-          for js.each |j| {
-                match *j {
-                    json::Object(ref p) => {
-                        load_one_source_package(src, *p);
-                    }
-                    _ => {
-                        warn(~"malformed source json: " + src.name +
-                             ~" (non-dict pkg)");
-                    }
-                }
-            }
-        }
-        Ok(_) => {
-            warn(~"malformed packages.json: " + src.name +
-                 ~"(packages is not a list)");
-        }
-        Err(e) => {
-            warn(fmt!("%s:%s", src.name, e.to_str()));
-        }
-    };
-}
-
-pub fn build_cargo_options(argv: ~[~str]) -> Options {
-    let matches = &match getopts::getopts(argv, opts()) {
-        result::Ok(m) => m,
-        result::Err(f) => {
-            fail!(fmt!("%s", getopts::fail_str(f)));
-        }
-    };
-
-    let test = opt_present(matches, ~"test");
-    let G    = opt_present(matches, ~"G");
-    let g    = opt_present(matches, ~"g");
-    let help = opt_present(matches, ~"h") || opt_present(matches, ~"help");
-    let len  = vec::len(matches.free);
-
-    let is_install = len > 1u && matches.free[1] == ~"install";
-    let is_uninstall = len > 1u && matches.free[1] == ~"uninstall";
-
-    if G && g { fail!(~"-G and -g both provided"); }
-
-    if !is_install && !is_uninstall && (g || G) {
-        fail!(~"-g and -G are only valid for `install` and `uninstall|rm`");
-    }
-
-    let mode =
-        if (!is_install && !is_uninstall) || g { UserMode }
-        else if G { SystemMode }
-        else { LocalMode };
-
-    Options {test: test, mode: mode, free: matches.free, help: help}
-}
-
-pub fn configure(opts: Options) -> Cargo {
-    let home = match get_cargo_root() {
-        Ok(home) => home,
-        Err(_err) => get_cargo_sysroot().get()
-    };
-
-    let get_cargo_dir = match opts.mode {
-        SystemMode => get_cargo_sysroot,
-        UserMode => get_cargo_root,
-        LocalMode => get_cargo_root_nearest
-    };
-
-    let p = get_cargo_dir().get();
-
-    let sources = HashMap();
-    try_parse_sources(&home.push("sources.json"), sources);
-    try_parse_sources(&home.push("local-sources.json"), sources);
-
-    let dep_cache = HashMap();
-
-    let mut c = Cargo {
-        pgp: pgp::supported(),
-        root: home,
-        installdir: p,
-        bindir: p.push("bin"),
-        libdir: p.push("lib"),
-        workdir: p.push("work"),
-        sourcedir: home.push("sources"),
-        sources: sources,
-        mut current_install: ~"",
-        dep_cache: dep_cache,
-        opts: opts
-    };
-
-    need_dir(&c.root);
-    need_dir(&c.installdir);
-    need_dir(&c.sourcedir);
-    need_dir(&c.workdir);
-    need_dir(&c.libdir);
-    need_dir(&c.bindir);
-
-    for sources.each_key |&k| {
-        let mut s = sources.get(&k);
-        load_source_packages(&c, s);
-        sources.insert(k, s);
-    }
-
-    if c.pgp {
-        pgp::init(&c.root);
-    } else {
-        warn(~"command `gpg` was not found");
-        warn(~"you have to install gpg from source " +
-             ~" or package manager to get it to work correctly");
-    }
-
-    c
-}
-
-pub fn for_each_package(c: &Cargo, b: fn(s: @Source, p: &Package)) {
-    for c.sources.each_value |&v| {
-        for v.packages.each |p| {
-            b(v, p);
-        }
-    }
-}
-
-// Runs all programs in directory <buildpath>
-pub fn run_programs(buildpath: &Path) {
-    let newv = os::list_dir_path(buildpath);
-    for newv.each |ct| {
-        run::run_program(ct.to_str(), ~[]);
-    }
-}
-
-// Runs rustc in <path + subdir> with the given flags
-// and returns <patho + subdir>
-pub fn run_in_buildpath(what: &str, path: &Path, subdir: &Path, cf: &Path,
-                        extra_flags: ~[~str]) -> Option<Path> {
-    let buildpath = path.push_rel(subdir);
-    need_dir(&buildpath);
-    debug!("%s: %s -> %s", what, cf.to_str(), buildpath.to_str());
-    let p = run::program_output(rustc_sysroot(),
-                                ~[~"--out-dir",
-                                  buildpath.to_str(),
-                                  cf.to_str()] + extra_flags);
-    if p.status != 0 {
-        error(fmt!("rustc failed: %d\n%s\n%s", p.status, p.err, p.out));
-        return None;
-    }
-    Some(buildpath)
-}
-
-pub fn test_one_crate(_c: &Cargo, path: &Path, cf: &Path) {
-    let buildpath = match run_in_buildpath(~"testing", path,
-                                           &Path("test"),
-                                           cf,
-                                           ~[ ~"--test"]) {
-      None => return,
-    Some(bp) => bp
-  };
-  run_programs(&buildpath);
-}
-
-pub fn install_one_crate(c: &Cargo, path: &Path, cf: &Path) {
-    let buildpath = match run_in_buildpath(~"installing", path,
-                                           &Path("build"),
-                                           cf, ~[]) {
-      None => return,
-      Some(bp) => bp
-    };
-    let newv = os::list_dir_path(&buildpath);
-    let exec_suffix = str::from_slice(os::EXE_SUFFIX);
-    for newv.each |ct| {
-        if (exec_suffix != ~"" && str::ends_with(ct.to_str(),
-                                                 exec_suffix)) ||
-            (exec_suffix == ~"" &&
-             !str::starts_with(ct.filename().get(),
-                               ~"lib")) {
-            debug!("  bin: %s", ct.to_str());
-            install_to_dir(*ct, &c.bindir);
-            if c.opts.mode == SystemMode {
-                // FIXME (#2662): Put this file in PATH / symlink it so it can
-                // be used as a generic executable
-                // `cargo install -G rustray` and `rustray file.obj`
-            }
-        } else {
-            debug!("  lib: %s", ct.to_str());
-            install_to_dir(*ct, &c.libdir);
-        }
-    }
-}
-
-
-pub fn rustc_sysroot() -> ~str {
-    match os::self_exe_path() {
-        Some(path) => {
-            let rustc = path.push_many([~"..", ~"bin", ~"rustc"]);
-            debug!("  rustc: %s", rustc.to_str());
-            rustc.to_str()
-        }
-        None => ~"rustc"
-    }
-}
-
-pub fn install_source(c: &mut Cargo, path: &Path) {
-    debug!("source: %s", path.to_str());
-    os::change_dir(path);
-
-    let mut cratefiles = ~[];
-    for os::walk_dir(&Path(".")) |p| {
-        if p.filetype() == Some(~".rc") {
-            cratefiles.push(*p);
-        }
-    }
-
-    if vec::is_empty(cratefiles) {
-        fail!(~"this doesn't look like a rust package (no .rc files)");
-    }
-
-    for cratefiles.each |cf| {
-        match load_crate(cf) {
-            None => loop,
-            Some(crate) => {
-              for crate.deps.each |query| {
-                    // FIXME (#1356): handle cyclic dependencies
-                    // (n.b. #1356 says "Cyclic dependency is an error
-                    // condition")
-
-                    let wd = get_temp_workdir(c);
-                    install_query(c, &wd, *query);
-                }
-
-                os::change_dir(path);
-
-                if c.opts.test {
-                    test_one_crate(c, path, cf);
-                }
-                install_one_crate(c, path, cf);
-            }
-        }
-    }
-}
-
-pub fn install_git(c: &mut Cargo, wd: &Path, url: ~str,
-                   reference: Option<~str>) {
-    run::program_output(~"git", ~[~"clone", url, wd.to_str()]);
-    if reference.is_some() {
-        let r = reference.get();
-        os::change_dir(wd);
-        run::run_program(~"git", ~[~"checkout", r]);
-    }
-
-    install_source(c, wd);
-}
-
-pub fn install_curl(c: &mut Cargo, wd: &Path, url: ~str) {
-    let tarpath = wd.push("pkg.tar");
-    let p = run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o",
-                                         tarpath.to_str(), url]);
-    if p.status != 0 {
-        fail!(fmt!("fetch of %s failed: %s", url, p.err));
-    }
-    run::run_program(~"tar", ~[~"-x", ~"--strip-components=1",
-                               ~"-C", wd.to_str(),
-                               ~"-f", tarpath.to_str()]);
-    install_source(c, wd);
-}
-
-pub fn install_file(c: &mut Cargo, wd: &Path, path: &Path) {
-    run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
-                                  ~"-C", wd.to_str(),
-                                  ~"-f", path.to_str()]);
-    install_source(c, wd);
-}
-
-pub fn install_package(c: &mut Cargo, src: ~str, wd: &Path, pkg: Package) {
-    let url = copy pkg.url;
-    let method = match pkg.method {
-        ~"git" => ~"git",
-        ~"file" => ~"file",
-        _ => ~"curl"
-    };
-
-    info(fmt!("installing %s/%s via %s...", src, pkg.name, method));
-
-    match method {
-        ~"git" => install_git(c, wd, url, copy pkg.reference),
-        ~"file" => install_file(c, wd, &Path(url)),
-        ~"curl" => install_curl(c, wd, url),
-        _ => ()
-    }
-}
-
-pub fn cargo_suggestion(c: &Cargo, fallback: fn()) {
-    if c.sources.is_empty() {
-        error(~"no sources defined - you may wish to run " +
-              ~"`cargo init`");
-        return;
-    }
-    fallback();
-}
-
-pub fn install_uuid(c: &mut Cargo, wd: &Path, uuid: ~str) {
-    let mut ps = ~[];
-    for_each_package(c, |s, p| {
-        if p.uuid == uuid {
-            vec::push(&mut ps, (s.name, copy *p));
-        }
-    });
-    if vec::len(ps) == 1u {
-        let (sname, p) = copy ps[0];
-        install_package(c, sname, wd, p);
-        return;
-    } else if vec::len(ps) == 0u {
-        cargo_suggestion(c, || {
-            error(~"can't find package: " + uuid);
-        });
-        return;
-    }
-    error(~"found multiple packages:");
-    for ps.each |elt| {
-        let (sname,p) = copy *elt;
-        info(~"  " + sname + ~"/" + p.uuid + ~" (" + p.name + ~")");
-    }
-}
-
-pub fn install_named(c: &mut Cargo, wd: &Path, name: ~str) {
-    let mut ps = ~[];
-    for_each_package(c, |s, p| {
-        if p.name == name {
-            vec::push(&mut ps, (s.name, copy *p));
-        }
-    });
-    if vec::len(ps) == 1u {
-        let (sname, p) = copy ps[0];
-        install_package(c, sname, wd, p);
-        return;
-    } else if vec::len(ps) == 0u {
-        cargo_suggestion(c, || {
-            error(~"can't find package: " + name);
-        });
-        return;
-    }
-    error(~"found multiple packages:");
-    for ps.each |elt| {
-        let (sname,p) = copy *elt;
-        info(~"  " + sname + ~"/" + p.uuid + ~" (" + p.name + ~")");
-    }
-}
-
-pub fn install_uuid_specific(c: &mut Cargo, wd: &Path, src: ~str,
-                             uuid: ~str) {
-    match c.sources.find(&src) {
-        Some(s) => {
-            for s.packages.each |p| {
-                if p.uuid == uuid {
-                    install_package(c, src, wd, *p);
-                    return;
-                }
-            }
-        }
-        _ => ()
-    }
-    error(~"can't find package: " + src + ~"/" + uuid);
-}
-
-pub fn install_named_specific(c: &mut Cargo, wd: &Path, src: ~str,
-                              name: ~str) {
-    match c.sources.find(&src) {
-        Some(s) => {
-            for s.packages.each |p| {
-                if p.name == name {
-                    install_package(c, src, wd, *p);
-                    return;
-                }
-            }
-        }
-        _ => ()
-    }
-    error(~"can't find package: " + src + ~"/" + name);
-}
-
-pub fn cmd_uninstall(c: &Cargo) {
-    if vec::len(c.opts.free) < 3u {
-        cmd_usage();
-        return;
-    }
-
-    let lib = &c.libdir;
-    let bin = &c.bindir;
-    let target = c.opts.free[2u];
-
-    // FIXME (#2662): needs stronger pattern matching
-    // FIXME (#2662): needs to uninstall from a specified location in a
-    // cache instead of looking for it (binaries can be uninstalled by
-    // name only)
-
-    fn try_uninstall(p: &Path) -> bool {
-        if os::remove_file(p) {
-            info(~"uninstalled: '" + p.to_str() + ~"'");
-            true
-        } else {
-            error(~"could not uninstall: '" +
-                  p.to_str() + ~"'");
-            false
-        }
-    }
-
-    if is_uuid(target) {
-        for os::list_dir(lib).each |file| {
-            match str::find_str(*file, ~"-" + target + ~"-") {
-              Some(_) => if !try_uninstall(&lib.push(*file)) { return },
-              None => ()
-            }
-        }
-        error(~"can't find package with uuid: " + target);
-    } else {
-        for os::list_dir(lib).each |file| {
-            match str::find_str(*file, ~"lib" + target + ~"-") {
-              Some(_) => if !try_uninstall(&lib.push(*file)) { return },
-              None => ()
-            }
-        }
-        for os::list_dir(bin).each |file| {
-            match str::find_str(*file, target) {
-              Some(_) => if !try_uninstall(&lib.push(*file)) { return },
-              None => ()
-            }
-        }
-
-        error(~"can't find package with name: " + target);
-    }
-}
-
-pub fn install_query(c: &mut Cargo, wd: &Path, target: ~str) {
-    match c.dep_cache.find(&target) {
-        Some(inst) => {
-            if inst {
-                return;
-            }
-        }
-        None => ()
-    }
-
-    c.dep_cache.insert(target, true);
-
-    if is_archive_path(target) {
-        install_file(c, wd, &Path(target));
-        return;
-    } else if is_git_url(target) {
-        let reference = if c.opts.free.len() >= 4u {
-            Some(c.opts.free[3u])
-        } else {
-            None
-        };
-        install_git(c, wd, target, reference);
-    } else if !valid_pkg_name(target) && has_archive_extension(target) {
-        install_curl(c, wd, target);
-        return;
-    } else {
-        let mut ps = copy target;
-
-        match str::find_char(ps, '/') {
-            option::Some(idx) => {
-                let source = str::slice(ps, 0u, idx);
-                ps = str::slice(ps, idx + 1u, str::len(ps));
-                if is_uuid(ps) {
-                    install_uuid_specific(c, wd, source, ps);
-                } else {
-                    install_named_specific(c, wd, source, ps);
-                }
-            }
-            option::None => {
-                if is_uuid(ps) {
-                    install_uuid(c, wd, ps);
-                } else {
-                    install_named(c, wd, ps);
-                }
-            }
-        }
-    }
-
-    // FIXME (#2662): This whole dep_cache and current_install thing is
-    // a bit of a hack. It should be cleaned up in the future.
-
-    if target == c.current_install {
-        c.dep_cache.clear();
-        c.current_install = ~"";
-    }
-}
-
-pub fn get_temp_workdir(c: &Cargo) -> Path {
-    match tempfile::mkdtemp(&c.workdir, "cargo") {
-      Some(wd) => wd,
-      None => fail!(fmt!("needed temp dir: %s",
-                        c.workdir.to_str()))
-    }
-}
-
-pub fn cmd_install(c: &mut Cargo) {
-    unsafe {
-        let wd = get_temp_workdir(c);
-
-        if vec::len(c.opts.free) == 2u {
-            let cwd = os::getcwd();
-            let status = run::run_program(~"cp", ~[~"-R", cwd.to_str(),
-                                                   wd.to_str()]);
-
-            if status != 0 {
-                fail!(fmt!("could not copy directory: %s", cwd.to_str()));
-            }
-
-            install_source(c, &wd);
-            return;
-        }
-
-        sync(c);
-
-        let query = c.opts.free[2];
-        c.current_install = query.to_str();
-
-        install_query(c, &wd, query);
-    }
-}
-
-pub fn sync(c: &Cargo) {
-    for c.sources.each_key |&k| {
-        let mut s = c.sources.get(&k);
-        sync_one(c, s);
-        c.sources.insert(k, s);
-    }
-}
-
-pub fn sync_one_file(c: &Cargo, dir: &Path, src: @Source) -> bool {
-    let name = src.name;
-    let srcfile = dir.push("source.json.new");
-    let destsrcfile = dir.push("source.json");
-    let pkgfile = dir.push("packages.json.new");
-    let destpkgfile = dir.push("packages.json");
-    let keyfile = dir.push("key.gpg");
-    let srcsigfile = dir.push("source.json.sig");
-    let sigfile = dir.push("packages.json.sig");
-    let url = Path(src.url);
-    let mut has_src_file = false;
-
-    if !os::copy_file(&url.push("packages.json"), &pkgfile) {
-        error(fmt!("fetch for source %s (url %s) failed",
-                   name, url.to_str()));
-        return false;
-    }
-
-    if os::copy_file(&url.push("source.json"), &srcfile) {
-        has_src_file = false;
-    }
-
-    os::copy_file(&url.push("source.json.sig"), &srcsigfile);
-    os::copy_file(&url.push("packages.json.sig"), &sigfile);
-
-    match copy src.key {
-        Some(u) => {
-            let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s",
-                                          ~"-o", keyfile.to_str(), u]);
-            if p.status != 0 {
-                error(fmt!("fetch for source %s (key %s) failed", name, u));
-                return false;
-            }
-            pgp::add(&c.root, &keyfile);
-        }
-        _ => ()
-    }
-    match (src.key, src.keyfp) {
-        (Some(_), Some(f)) => {
-            let r = pgp::verify(&c.root, &pkgfile, &sigfile);
-
-            if !r {
-                error(fmt!("signature verification failed for source %s with \
-                            key %s", name, f));
-                return false;
-            }
-
-            if has_src_file {
-                let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
-
-                if !e {
-                    error(fmt!("signature verification failed for source %s \
-                                with key %s", name, f));
-                    return false;
-                }
-            }
-        }
-        _ => ()
-    }
-
-    copy_warn(&pkgfile, &destpkgfile);
-
-    if has_src_file {
-        copy_warn(&srcfile, &destsrcfile);
-    }
-
-    os::remove_file(&keyfile);
-    os::remove_file(&srcfile);
-    os::remove_file(&srcsigfile);
-    os::remove_file(&pkgfile);
-    os::remove_file(&sigfile);
-
-    info(fmt!("synced source: %s", name));
-
-    return true;
-}
-
-pub fn sync_one_git(c: &Cargo, dir: &Path, src: @Source) -> bool {
-    let name = src.name;
-    let srcfile = dir.push("source.json");
-    let pkgfile = dir.push("packages.json");
-    let keyfile = dir.push("key.gpg");
-    let srcsigfile = dir.push("source.json.sig");
-    let sigfile = dir.push("packages.json.sig");
-    let url = src.url;
-
-    fn rollback(name: ~str, dir: &Path, insecure: bool) {
-        fn msg(name: ~str, insecure: bool) {
-            error(fmt!("could not rollback source: %s", name));
-
-            if insecure {
-                warn(~"a past security check failed on source " +
-                     name + ~" and rolling back the source failed -"
-                     + ~" this source may be compromised");
-            }
-        }
-
-        if !os::change_dir(dir) {
-            msg(name, insecure);
-        }
-        else {
-            let p = run::program_output(~"git", ~[~"reset", ~"--hard",
-                                                ~"HEAD@{1}"]);
-
-            if p.status != 0 {
-                msg(name, insecure);
-            }
-        }
-    }
-
-    if !os::path_exists(&dir.push(".git")) {
-        let p = run::program_output(~"git", ~[~"clone", url, dir.to_str()]);
-
-        if p.status != 0 {
-            error(fmt!("fetch for source %s (url %s) failed", name, url));
-            return false;
-        }
-    }
-    else {
-        if !os::change_dir(dir) {
-            error(fmt!("fetch for source %s (url %s) failed", name, url));
-            return false;
-        }
-
-        let p = run::program_output(~"git", ~[~"pull"]);
-
-        if p.status != 0 {
-            error(fmt!("fetch for source %s (url %s) failed", name, url));
-            return false;
-        }
-    }
-
-    let has_src_file = os::path_exists(&srcfile);
-
-    match copy src.key {
-        Some(u) => {
-            let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s",
-                                          ~"-o", keyfile.to_str(), u]);
-            if p.status != 0 {
-                error(fmt!("fetch for source %s (key %s) failed", name, u));
-                rollback(name, dir, false);
-                return false;
-            }
-            pgp::add(&c.root, &keyfile);
-        }
-        _ => ()
-    }
-    match (src.key, src.keyfp) {
-        (Some(_), Some(f)) => {
-            let r = pgp::verify(&c.root, &pkgfile, &sigfile);
-
-            if !r {
-                error(fmt!("signature verification failed for source %s with \
-                            key %s", name, f));
-                rollback(name, dir, false);
-                return false;
-            }
-
-            if has_src_file {
-                let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
-
-                if !e {
-                    error(fmt!("signature verification failed for source %s \
-                                with key %s", name, f));
-                    rollback(name, dir, false);
-                    return false;
-                }
-            }
-        }
-        _ => ()
-    }
-
-    os::remove_file(&keyfile);
-
-    info(fmt!("synced source: %s", name));
-
-    return true;
-}
-
-pub fn sync_one_curl(c: &Cargo, dir: &Path, src: @Source) -> bool {
-    let name = src.name;
-    let srcfile = dir.push("source.json.new");
-    let destsrcfile = dir.push("source.json");
-    let pkgfile = dir.push("packages.json.new");
-    let destpkgfile = dir.push("packages.json");
-    let keyfile = dir.push("key.gpg");
-    let srcsigfile = dir.push("source.json.sig");
-    let sigfile = dir.push("packages.json.sig");
-    let mut url = src.url;
-    let smart = !str::ends_with(src.url, ~"packages.json");
-    let mut has_src_file = false;
-
-    if smart {
-        url += ~"/packages.json";
-    }
-
-    let p = run::program_output(~"curl",
-                                ~[~"-f", ~"-s",
-                                  ~"-o", pkgfile.to_str(), url]);
-
-    if p.status != 0 {
-        error(fmt!("fetch for source %s (url %s) failed", name, url));
-        return false;
-    }
-    if smart {
-        url = src.url + ~"/source.json";
-        let p =
-            run::program_output(~"curl",
-                                ~[~"-f", ~"-s",
-                                  ~"-o", srcfile.to_str(), url]);
-
-        if p.status == 0 {
-            has_src_file = true;
-        }
-    }
-
-    match copy src.key {
-       Some(u) => {
-            let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s",
-                                          ~"-o", keyfile.to_str(), u]);
-            if p.status != 0 {
-                error(fmt!("fetch for source %s (key %s) failed", name, u));
-                return false;
-            }
-            pgp::add(&c.root, &keyfile);
-        }
-        _ => ()
-    }
-    match (src.key, src.keyfp) {
-        (Some(_), Some(f)) => {
-            if smart {
-                url = src.url + ~"/packages.json.sig";
-            }
-            else {
-                url = src.url + ~".sig";
-            }
-
-            let mut p = run::program_output(~"curl",
-                                            ~[~"-f", ~"-s", ~"-o",
-                                              sigfile.to_str(), url]);
-            if p.status != 0 {
-                error(fmt!("fetch for source %s (sig %s) failed", name, url));
-                return false;
-            }
-
-            let r = pgp::verify(&c.root, &pkgfile, &sigfile);
-
-            if !r {
-                error(fmt!("signature verification failed for source %s with \
-                            key %s", name, f));
-                return false;
-            }
-
-            if smart && has_src_file {
-                url = src.url + ~"/source.json.sig";
-
-                p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s", ~"-o",
-                                          srcsigfile.to_str(), url]);
-                if p.status != 0 {
-                    error(fmt!("fetch for source %s (sig %s) failed",
-                          name, url));
-                    return false;
-                }
-
-                let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
-
-                if !e {
-                    error(~"signature verification failed for " +
-                          ~"source " + name + ~" with key " + f);
-                    return false;
-                }
-            }
-        }
-        _ => ()
-    }
-
-    copy_warn(&pkgfile, &destpkgfile);
-
-    if smart && has_src_file {
-        copy_warn(&srcfile, &destsrcfile);
-    }
-
-    os::remove_file(&keyfile);
-    os::remove_file(&srcfile);
-    os::remove_file(&srcsigfile);
-    os::remove_file(&pkgfile);
-    os::remove_file(&sigfile);
-
-    info(fmt!("synced source: %s", name));
-
-    return true;
-}
-
-pub fn sync_one(c: &Cargo, src: @Source) {
-    let name = src.name;
-    let dir = c.sourcedir.push(name);
-
-    info(fmt!("syncing source: %s...", name));
-
-    need_dir(&dir);
-
-    let result = match src.method {
-        ~"git" => sync_one_git(c, &dir, src),
-        ~"file" => sync_one_file(c, &dir, src),
-        _ => sync_one_curl(c, &dir, src)
-    };
-
-    if result {
-        load_source_info(c, src);
-        load_source_packages(c, src);
-    }
-}
-
-pub fn cmd_init(c: &Cargo) {
-    let srcurl = ~"http://www.rust-lang.org/cargo/sources.json";
-    let sigurl = ~"http://www.rust-lang.org/cargo/sources.json.sig";
-
-    let srcfile = c.root.push("sources.json.new");
-    let sigfile = c.root.push("sources.json.sig");
-    let destsrcfile = c.root.push("sources.json");
-
-    let p =
-        run::program_output(~"curl", ~[~"-f", ~"-s",
-                                       ~"-o", srcfile.to_str(), srcurl]);
-    if p.status != 0 {
-        error(fmt!("fetch of sources.json failed: %s", p.out));
-        return;
-    }
-
-    let p =
-        run::program_output(~"curl", ~[~"-f", ~"-s",
-                                       ~"-o", sigfile.to_str(), sigurl]);
-    if p.status != 0 {
-        error(fmt!("fetch of sources.json.sig failed: %s", p.out));
-        return;
-    }
-
-    let r = pgp::verify(&c.root, &srcfile, &sigfile);
-    if !r {
-        error(fmt!("signature verification failed for '%s'",
-                   srcfile.to_str()));
-        return;
-    }
-
-    copy_warn(&srcfile, &destsrcfile);
-    os::remove_file(&srcfile);
-    os::remove_file(&sigfile);
-
-    info(fmt!("initialized .cargo in %s", c.root.to_str()));
-}
-
-pub fn print_pkg(s: @Source, p: &Package) {
-    let mut m = s.name + ~"/" + p.name + ~" (" + p.uuid + ~")";
-    if vec::len(p.tags) > 0u {
-        m = m + ~" [" + str::connect(p.tags, ~", ") + ~"]";
-    }
-    info(m);
-    if p.description != ~"" {
-        print(~"   >> " + p.description + ~"\n")
-    }
-}
-
-pub fn print_source(s: @Source) {
-    info(s.name + ~" (" + s.url + ~")");
-
-    let pks = sort::merge_sort(s.packages.get(), sys::shape_lt);
-    let l = vec::len(pks);
-
-    print(io::with_str_writer(|writer| {
-        let mut list = ~"   >> ";
-
-        for vec::eachi(pks) |i, pk| {
-            if str::len(list) > 78u {
-                writer.write_line(list);
-                list = ~"   >> ";
-            }
-            list += pk.name + (if l - 1u == i { ~"" } else { ~", " });
-        }
-
-        writer.write_line(list);
-    }));
-}
-
-pub fn cmd_list(c: &Cargo) {
-    sync(c);
-
-    if vec::len(c.opts.free) >= 3u {
-        let v = vec::slice(c.opts.free, 2u, vec::len(c.opts.free));
-        for vec::each(v) |name| {
-            if !valid_pkg_name(*name) {
-                error(fmt!("'%s' is an invalid source name", *name));
-            } else {
-                match c.sources.find(name) {
-                    Some(source) => {
-                        print_source(source);
-                    }
-                    None => {
-                        error(fmt!("no such source: %s", *name));
-                    }
-                }
-            }
-        }
-    } else {
-        for c.sources.each_value |&v| {
-            print_source(v);
-        }
-    }
-}
-
-pub fn cmd_search(c: &Cargo) {
-    if vec::len(c.opts.free) < 3u {
-        cmd_usage();
-        return;
-    }
-
-    sync(c);
-
-    let mut n = 0;
-    let name = c.opts.free[2];
-    let tags = vec::slice(c.opts.free, 3u, vec::len(c.opts.free));
-    for_each_package(c, |s, p| {
-        if (str::contains(p.name, name) || name == ~"*") &&
-            vec::all(tags, |t| vec::contains(p.tags, t) ) {
-            print_pkg(s, p);
-            n += 1;
-        }
-    });
-    info(fmt!("found %d packages", n));
-}
-
-pub fn install_to_dir(srcfile: &Path, destdir: &Path) {
-    let newfile = destdir.push(srcfile.filename().get());
-
-    let status = run::run_program(~"cp", ~[~"-r", srcfile.to_str(),
-                                           newfile.to_str()]);
-    if status == 0 {
-        info(fmt!("installed: '%s'", newfile.to_str()));
-    } else {
-        error(fmt!("could not install: '%s'", newfile.to_str()));
-    }
-}
-
-pub fn dump_cache(c: &Cargo) {
-    need_dir(&c.root);
-
-    let out = c.root.push("cache.json");
-    let _root = json::Object(~LinearMap::new());
-
-    if os::path_exists(&out) {
-        copy_warn(&out, &c.root.push("cache.json.old"));
-    }
-}
-
-pub fn dump_sources(c: &Cargo) {
-    if c.sources.is_empty() {
-        return;
-    }
-
-    need_dir(&c.root);
-
-    let out = c.root.push("sources.json");
-
-    if os::path_exists(&out) {
-        copy_warn(&out, &c.root.push("sources.json.old"));
-    }
-
-    match io::buffered_file_writer(&out) {
-        result::Ok(writer) => {
-            let mut hash = ~LinearMap::new();
-
-            for c.sources.each |&k, &v| {
-                let mut chash = ~LinearMap::new();
-
-                chash.insert(~"url", json::String(v.url));
-                chash.insert(~"method", json::String(v.method));
-
-                match copy v.key {
-                    Some(key) => {
-                        chash.insert(~"key", json::String(copy key));
-                    }
-                    _ => ()
-                }
-                match copy v.keyfp {
-                    Some(keyfp) => {
-                        chash.insert(~"keyfp", json::String(copy keyfp));
-                    }
-                    _ => ()
-                }
-
-                hash.insert(copy k, json::Object(chash));
-            }
-
-            json::to_writer(writer, &json::Object(hash))
-        }
-        result::Err(e) => {
-            error(fmt!("could not dump sources: %s", e));
-        }
-    }
-}
-
-pub fn copy_warn(srcfile: &Path, destfile: &Path) {
-    if !os::copy_file(srcfile, destfile) {
-        warn(fmt!("copying %s to %s failed",
-                  srcfile.to_str(), destfile.to_str()));
-    }
-}
-
-pub fn cmd_sources(c: &Cargo) {
-    if vec::len(c.opts.free) < 3u {
-        for c.sources.each_value |&v| {
-            info(fmt!("%s (%s) via %s",
-                      v.name, v.url, v.method));
-        }
-        return;
-    }
-
-    let action = c.opts.free[2u];
-
-    match action {
-        ~"clear" => {
-          for c.sources.each_key |&k| {
-                c.sources.remove(&k);
-            }
-
-            info(~"cleared sources");
-        }
-        ~"add" => {
-            if vec::len(c.opts.free) < 5u {
-                cmd_usage();
-                return;
-            }
-
-            let name = c.opts.free[3u];
-            let url = c.opts.free[4u];
-
-            if !valid_pkg_name(name) {
-                error(fmt!("'%s' is an invalid source name", name));
-                return;
-            }
-
-            if c.sources.contains_key(&name) {
-                error(fmt!("source already exists: %s", name));
-            } else {
-                c.sources.insert(name, @Source {
-                    name: name,
-                    mut url: url,
-                    mut method: assume_source_method(url),
-                    mut key: None,
-                    mut keyfp: None,
-                    packages: DVec()
-                });
-                info(fmt!("added source: %s", name));
-            }
-        }
-        ~"remove" => {
-            if vec::len(c.opts.free) < 4u {
-                cmd_usage();
-                return;
-            }
-
-            let name = c.opts.free[3u];
-
-            if !valid_pkg_name(name) {
-                error(fmt!("'%s' is an invalid source name", name));
-                return;
-            }
-
-            if c.sources.contains_key(&name) {
-                c.sources.remove(&name);
-                info(fmt!("removed source: %s", name));
-            } else {
-                error(fmt!("no such source: %s", name));
-            }
-        }
-        ~"set-url" => {
-            if vec::len(c.opts.free) < 5u {
-                cmd_usage();
-                return;
-            }
-
-            let name = c.opts.free[3u];
-            let url = c.opts.free[4u];
-
-            if !valid_pkg_name(name) {
-                error(fmt!("'%s' is an invalid source name", name));
-                return;
-            }
-
-            match c.sources.find(&name) {
-                Some(source) => {
-                    let old = copy source.url;
-                    let method = assume_source_method(url);
-
-                    source.url = url;
-                    source.method = method;
-
-                    c.sources.insert(name, source);
-
-                    info(fmt!("changed source url: '%s' to '%s'", old, url));
-                }
-                None => {
-                    error(fmt!("no such source: %s", name));
-                }
-            }
-        }
-        ~"set-method" => {
-            if vec::len(c.opts.free) < 5u {
-                cmd_usage();
-                return;
-            }
-
-            let name = c.opts.free[3u];
-            let method = c.opts.free[4u];
-
-            if !valid_pkg_name(name) {
-                error(fmt!("'%s' is an invalid source name", name));
-                return;
-            }
-
-            match c.sources.find(&name) {
-                Some(source) => {
-                    let old = copy source.method;
-
-                    source.method = match method {
-                        ~"git" => ~"git",
-                        ~"file" => ~"file",
-                        _ => ~"curl"
-                    };
-
-                    c.sources.insert(name, source);
-
-                    info(fmt!("changed source method: '%s' to '%s'", old,
-                         method));
-                }
-                None => {
-                    error(fmt!("no such source: %s", name));
-                }
-            }
-        }
-        ~"rename" => {
-            if vec::len(c.opts.free) < 5u {
-                cmd_usage();
-                return;
-            }
-
-            let name = c.opts.free[3u];
-            let newn = c.opts.free[4u];
-
-            if !valid_pkg_name(name) {
-                error(fmt!("'%s' is an invalid source name", name));
-                return;
-            }
-            if !valid_pkg_name(newn) {
-                error(fmt!("'%s' is an invalid source name", newn));
-                return;
-            }
-
-            match c.sources.find(&name) {
-                Some(source) => {
-                    c.sources.remove(&name);
-                    c.sources.insert(newn, source);
-                    info(fmt!("renamed source: %s to %s", name, newn));
-                }
-                None => {
-                    error(fmt!("no such source: %s", name));
-                }
-            }
-        }
-        _ => cmd_usage()
-    }
-}
-
-pub fn cmd_usage() {
-    print(~"Usage: cargo <cmd> [options] [args..]
-e.g. cargo install <name>
-
-Where <cmd> is one of:
-    init, install, list, search, sources,
-    uninstall, usage
-
-Options:
-
-    -h, --help                  Display this message
-    <cmd> -h, <cmd> --help      Display help for <cmd>
-");
-}
-
-pub fn cmd_usage_init() {
-    print(~"cargo init
-
-Re-initialize cargo in ~/.cargo. Clears all sources and then adds the
-default sources from <www.rust-lang.org/sources.json>.");
-}
-
-pub fn cmd_usage_install() {
-    print(~"cargo install
-cargo install [source/]<name>[@version]
-cargo install [source/]<uuid>[@version]
-cargo install <git url> [ref]
-cargo install <tarball url>
-cargo install <tarball file>
-
-Options:
-    --test      Run crate tests before installing
-    -g          Install to the user level (~/.cargo/bin/ instead of
-                locally in ./.cargo/bin/ by default)
-    -G          Install to the system level (/usr/local/lib/cargo/bin/)
-
-Install a crate. If no arguments are supplied, it installs from
-the current working directory. If a source is provided, only install
-from that source, otherwise it installs from any source.");
-}
-
-pub fn cmd_usage_uninstall() {
-    print(~"cargo uninstall [source/]<name>[@version]
-cargo uninstall [source/]<uuid>[@version]
-cargo uninstall <meta-name>[@version]
-cargo uninstall <meta-uuid>[@version]
-
-Options:
-    -g          Remove from the user level (~/.cargo/bin/ instead of
-                locally in ./.cargo/bin/ by default)
-    -G          Remove from the system level (/usr/local/lib/cargo/bin/)
-
-Remove a crate. If a source is provided, only remove
-from that source, otherwise it removes from any source.
-If a crate was installed directly (git, tarball, etc.), you can remove
-it by metadata.");
-}
-
-pub fn cmd_usage_list() {
-    print(~"cargo list [sources..]
-
-If no arguments are provided, list all sources and their packages.
-If source names are provided, list those sources and their packages.
-");
-}
-
-pub fn cmd_usage_search() {
-    print(~"cargo search <query | '*'> [tags..]
-
-Search packages.");
-}
-
-pub fn cmd_usage_sources() {
-    print(~"cargo sources
-cargo sources add <name> <url>
-cargo sources remove <name>
-cargo sources rename <name> <new>
-cargo sources set-url <name> <url>
-cargo sources set-method <name> <method>
-
-If no arguments are supplied, list all sources (but not their packages).
-
-Commands:
-    add             Add a source. The source method will be guessed
-                    from the URL.
-    remove          Remove a source.
-    rename          Rename a source.
-    set-url         Change the URL for a source.
-    set-method      Change the method for a source.");
-}
-
-pub fn main() {
-    let argv = os::args();
-    let o = build_cargo_options(argv);
-
-    if vec::len(o.free) < 2u {
-        cmd_usage();
-        return;
-    }
-    if o.help {
-        match o.free[1] {
-            ~"init" => cmd_usage_init(),
-            ~"install" => cmd_usage_install(),
-            ~"uninstall" => cmd_usage_uninstall(),
-            ~"list" => cmd_usage_list(),
-            ~"search" => cmd_usage_search(),
-            ~"sources" => cmd_usage_sources(),
-            _ => cmd_usage()
-        }
-        return;
-    }
-    if o.free[1] == ~"usage" {
-        cmd_usage();
-        return;
-    }
-
-    let mut c = configure(o);
-    let home = c.root;
-    let first_time = os::path_exists(&home.push("sources.json"));
-
-    if !first_time && o.free[1] != ~"init" {
-        cmd_init(&c);
-
-        // FIXME (#2662): shouldn't need to reconfigure
-        c = configure(o);
-    }
-
-    match o.free[1] {
-        ~"init" => cmd_init(&c),
-        ~"install" => cmd_install(&mut c),
-        ~"uninstall" => cmd_uninstall(&c),
-        ~"list" => cmd_list(&c),
-        ~"search" => cmd_search(&c),
-        ~"sources" => cmd_sources(&c),
-        _ => cmd_usage()
-    }
-
-    dump_cache(&c);
-    dump_sources(&c);
-}
-
diff --git a/src/libcargo/pgp.rs b/src/libcargo/pgp.rs
deleted file mode 100644
index 364effcd32f..00000000000
--- a/src/libcargo/pgp.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use core::os;
-use core::path::Path;
-use core::run;
-
-pub fn gpgv(args: ~[~str]) -> run::ProgramOutput {
-    return run::program_output(~"gpgv", args);
-}
-
-pub fn signing_key() -> ~str {
-    ~"
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: SKS 1.1.0
-
-mQINBE7dQY0BEADYs5pHqXQugXjmgRTj0AzE3F4HAEJAiUBechVOmCgNcnW4dyb6bgj7Ctqs
-Td/ZDSZkFwmsIqpwfGxMr+s9VA3PW+sEMDZPY+p8w3kvFPo/L2eRjSnQ+cPffdUPo+IXl96d
-N/49iXs6/d7PHw+pYszdgCfpPAAo4TtLJLVCWRs1ETSbZBIUOFywgE5P71egYVMgYKndRM5K
-cY0ZUsGUX9InpItuD3R7vFwDL9cUHBonOJoax+rYeM7eLQvNncl4YAwJsUKOVDBy28QK2wmz
-R6MsBTX8+vRkj3ZTCnP1+RBNllViYnq6absnAgHFdQ6OL4T2wKhAaYhukE1foFTNNI1wAm4s
-iYAI20Me+54xMQZa3QvrokL/Wf9+qeajEDOTZWs1T3Sn+H3Dg3T25b8WOH3ULZE7R4FPr0Id
-5u95nxKG2D2fkMXDwc0BeG+VWh3lCdjOBn2kyT+6TwM9d+/VQmY4vZdZFhI6nCUlxeKEg4wk
-HW6kad5QPcUlS/3flNHM0bVLPrmNDb61bm+2sYPpgw0iy7JA5m8MceG57jS7q6Mo001cIya8
-EqrfBLZ0/0eLyIH81/RjFYwEoI54+QWe0ovdsqNTVnQsCcZnIRFTbMQqdInuCqrROIn+00xe
-L0KNMh0iQO4zRaG0XhQaUxt2mIbkA0PuntsM8+I9DUIAqXgttwARAQABtERSdXN0IExhbmd1
-YWdlIChUYWcgYW5kIFJlbGVhc2UgU2lnbmluZyBLZXkpIDxydXN0LWtleUBydXN0LWxhbmcu
-b3JnPokCPgQTAQIAKAUCTt1BjQIbAwUJAeEzgAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
-CgkQCy1qKDAzY3azFg//V+IoiCurdYyS4nckMbr9gTn5SKaAtQUqMWAoJty3/lZ2jLq/9zO0
-TO9Zw0rcoVUORpl4VsGsUu0QIA53KJJLOto4hHGvDBsASm4x1o06Ftsp37YrMozRN+4capIR
-Kx5uM3whSUTGponOQplj9ED3zw/FkFWF4ni2KAZMfRJQy6berIBBHNWbMtY/vneTwv0YZOah
-sS23AQ958mVhOfDYYnmpEzHza9kl6le9RjmxuFX0bOOB+bHE4T3X0OmB2q4RJetwd18qRGGY
-dy/e5xON13Y708gV2v4t3ZC3X+XT/+dwHHjoa6nWIxI5OU59AfnjBJIs09pHq2VYUCfdZiHL
-YRTrMQkUyapjOwWV5tbCtYnCufjILk2vk1YBqj1vjco0tMH7llsEoQ4seg8NrwkZYZ8jccN9
-Aymb0ObZZgSVJCFN3akUESfh9wPDAQjmLjqWAOMNDSpnElIVAxLX1O/HNgRv7tl0Te14Goul
-lhrWzTg5vPpOhSe+1SVUAUVcBwHcZl1opXCHQHfW2vkfe9w1hRBqEMOmr54TBXufxneNc/te
-NuV+ZA4l9QvirmGtmQee4LQwz7d//IFGVxidsbOTVOU9hbijm/USJCK1BPqF36I2rB/8ve7h
-qTwTVbvMRb8qWS2YhwRHsYrngXbun1vwwFouiW2KV5NEFNMt3pj+Rcu5Ag0ETt1BjQEQAMOf
-6oCHj5ASMHCdKzSGF+ofIG3OWH7SUVRDKtJck75LyjbW/14SxNQCF6UvyjwhVWnnGmXiCED6
-cCOo9UdMhF46ojWe//mszSJRZTc0OvUpq9AIe3UA7mLHve4A+8fXBd1mpgciG8qD4vifdO4T
-yvkb4dwxW+hpsenKHaM4hvQJFB1c33loEeGdfE/9svZyCO9T4FA6tdj5niLdtGtcJ6eC/6rp
-53kcg4RLz9hOH39ouitqIHVqO/j+TW2M8kYgh1niBCGQm2kV5jeh7QUMe7TA3KHksAVqAKcJ
-4TO538KswbC8MLz4+cdHpXf+kSUNnRzyndazjIF31XSyT8cDZHdfFHFkCA/4Xr7ebp+gub6R
-qbCeCbds/UQ8L7NOqze9/qGuRBLTarXmvZ0AgELu/z4bPF6GyKcJjFYkMZQoAzYZfFc2pNW+
-WhWCusAz0aw+6NoZVI6bYhfY2w+kf3vebpzuKdD0Qublk5cKFCU9bV6BYqI9PbgBkErUgrgp
-Zrjkc2c2u6uje0sKRxihdczr75Kikhb3M4BKQx3V5GyKdvo+61MhYurwWtyTylgMvlyL+3Bn
-r0bg/vFbdwO4wgdNjR9UkjjABjuTExdnAqvf2+eBnYkuzxG60TH5At3CRTBshNUO9N0q1SGH
-tGJkDOOxEZwAnUmE9jAG9CdeWxJNaUa5ABEBAAGJAiUEGAECAA8FAk7dQY0CGwwFCQHhM4AA
-CgkQCy1qKDAzY3a9NBAAqpQKlFBCJV2h8GJU68OzFdxYIelhzH0KcInm6QREiUtU2+WAAyli
-IbvsEL3c0hH0xykhwZx0wPmj7QQW7h5geOTvfLhNe/XMLsnlIRXBCSZKmlsZ8HfOVAXZTY61
-LM0v11eI6w0lCUC6GqWfzpph+uxUQjJ6YrGomj7nDrvj8Dp4S4UYaJc+1pcVPjO/XmZrZkb1
-6KnTm4RJcIW0iO61g7SDn8JZCmrDf9Ur+9NmRdynEeiWn9DUkbAXTKj09NiRyV+8mVmSGw4F
-Jylqtk+X4WTu7qCm9C0S3ROuSSJOkCQGcE552GaS5RN9wdL/cG1PfqQjSaY0HMQzpBzV+nXa
-2eFk3Bg2/qi4OghjR00Y3SQftDWI4K3opwVdsF7u9YH6PQoX4jl5DJIvtdIwwQJVaHLjVF4r
-koV3ryFlL4Oq70TLwBSUlUhYoii5pokr3GdzloUWuuBa8AK5sM0RG/pybUPWK1PQnDlJJg6H
-JyEC4EFfBWv2+nwt1K+vIRuCX9ZSd5YP9F4RbQjsnz7dimo5ooy3Wj7Fv7lQnQGkaUev0+hs
-t9H7RfQEyREukTMxzXjKEW9EO4lJ20cif3l7Be+bw6OzKaEkVE3reZRnKxO6SejUYA7reye1
-HI1jilzwKSXuV2EmyBk3tKh9NwscT/A78pr30FxxPUg3v72raNgusTo=
-=2z6P
------END PGP PUBLIC KEY BLOCK-----
-"
-}
-
-pub fn signing_key_fp() -> ~str {
-    ~"FE79 EDB0 3DEF B0D8 27D2  6C41 0B2D 6A28 3033 6376"
-}
-
-pub fn supported() -> bool {
-    let r = gpgv(~[~"--version"]);
-    r.status == 0
-}
-
-pub fn init(root: &Path) {
-    let p = root.push("gpg");
-    if !os::path_is_dir(&p) {
-        os::make_dir(&p, 0x1c0i32);
-        let mut p = run::start_program(~"gpg", ~[~"--homedir",
-                                                 p.to_str(),
-                                                 ~"--import"]);
-        p.input().write_str(signing_key());
-        let s = p.finish();
-        if s != 0 {
-            fail!(~"pgp init failed");
-        }
-    }
-}
-
-pub fn add(root: &Path, key: &Path) {
-    let path = root.push("gpg");
-    let p =
-        run::program_output(~"gpg", ~[~"--homedir", path.to_str(),
-                                      ~"--import", key.to_str()]);
-    if p.status != 0 {
-        fail!(~"pgp add failed: " + p.out);
-    }
-}
-
-pub fn verify(root: &Path, data: &Path, sig: &Path) -> bool {
-    let path = root.push("gpg");
-    let res = gpgv(~[~"--homedir", path.to_str(),
-                  ~"--keyring", ~"pubring.gpg",
-                  ~"--verbose",
-                 sig.to_str(), data.to_str()]);
-    if res.status != 0 {
-        return false;
-    }
-    return true;
-}
diff --git a/src/libcargo/sources.json b/src/libcargo/sources.json
deleted file mode 100644
index 66e14f9eff7..00000000000
--- a/src/libcargo/sources.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-	"central": {
-		"url": "https://raw.github.com/mozilla/cargo-central/master/packages.json"
-	},
-	"elly": {
-		"url": "https://raw.github.com/elly/rust-packages/master/packages.json",
-		"sig": "https://raw.github.com/elly/rust-packages/master/packages.json.sig",
-		"key": "https://raw.github.com/elly/rust-packages/master/signing-key.gpg",
-		"keyfp": "4107 21C0 FF32 858F 61FF  33F6 E595 8E36 FDC8 EA00"
-	},
-	"erickt": {
-		"url": "https://raw.github.com/erickt/rust-packages/master/packages.json"
-	}
-}
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index 5b6c40e09ef..da13145b9f6 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -170,7 +170,6 @@ pub mod condition;
 pub mod logging;
 pub mod util;
 
-
 /* Reexported core operators */
 
 pub use kinds::{Const, Copy, Owned, Durable};
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index a90364c7d8c..13d4ec6e10d 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -41,7 +41,7 @@ let unwrapped_msg = match msg {
 
 */
 
-use cmp::Eq;
+use cmp::{Eq,Ord};
 use kinds::Copy;
 use option;
 use ptr;
@@ -56,6 +56,34 @@ pub enum Option<T> {
     Some(T),
 }
 
+pub impl<T:Ord> Ord for Option<T> {
+    pure fn lt(&self, other: &Option<T>) -> bool {
+        match (self, other) {
+            (&None, &None) => false,
+            (&None, &Some(_)) => true,
+            (&Some(_), &None) => false,
+            (&Some(ref a), &Some(ref b)) => *a < *b
+        }
+    }
+
+    pure fn le(&self, other: &Option<T>) -> bool {
+        match (self, other) {
+            (&None, &None) => true,
+            (&None, &Some(_)) => true,
+            (&Some(_), &None) => false,
+            (&Some(ref a), &Some(ref b)) => *a <= *b
+        }
+    }
+
+    pure fn ge(&self, other: &Option<T>) -> bool {
+        ! (self < other)
+    }
+
+    pure fn gt(&self, other: &Option<T>) -> bool {
+        ! (self <= other)
+    }
+}
+
 #[inline(always)]
 pub pure fn get<T: Copy>(opt: Option<T>) -> T {
     /*!
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index f1712d05562..5fc284bc9fc 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -184,14 +184,14 @@ pub enum compile_upto {
     cu_everything,
 }
 
-pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
-                    input: input, upto: compile_upto,
-                    outputs: Option<output_filenames>)
-                 -> {crate: @ast::crate, tcx: Option<ty::ctxt>} {
+// For continuing compilation after a parsed crate has been
+// modified
+pub fn compile_rest(sess: Session, cfg: ast::crate_cfg,
+                    upto: compile_upto, outputs: Option<output_filenames>,
+                    curr: Option<@ast::crate>)
+    -> {crate: @ast::crate, tcx: Option<ty::ctxt>} {
     let time_passes = sess.time_passes();
-    let mut crate = time(time_passes, ~"parsing",
-                         || parse_input(sess, copy cfg, input) );
-    if upto == cu_parse { return {crate: crate, tcx: None}; }
+    let mut crate = curr.get();
 
     *sess.building_library = session::building_library(
         sess.opts.crate_type, crate, sess.opts.test);
@@ -322,7 +322,6 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
 
     };
 
-
     time(time_passes, ~"LLVM passes", ||
         link::write::run_passes(sess, llmod,
                                 &outputs.obj_filename));
@@ -342,9 +341,20 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
     return {crate: crate, tcx: None};
 }
 
+pub fn compile_upto(sess: Session, +cfg: ast::crate_cfg,
+                input: input, upto: compile_upto,
+                outputs: Option<output_filenames>)
+    -> {crate: @ast::crate, tcx: Option<ty::ctxt>} {
+    let time_passes = sess.time_passes();
+    let mut crate = time(time_passes, ~"parsing",
+                         || parse_input(sess, copy cfg, input) );
+    if upto == cu_parse { return {crate: crate, tcx: None}; }
+
+    compile_rest(sess, cfg, upto, outputs, Some(crate))
+}
+
 pub fn compile_input(sess: Session, +cfg: ast::crate_cfg, input: input,
                      outdir: &Option<Path>, output: &Option<Path>) {
-
     let upto = if sess.opts.parse_only { cu_parse }
                else if sess.opts.no_trans { cu_no_trans }
                else { cu_everything };
diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs
index ed4ea665aaf..f5cc44867a5 100644
--- a/src/librustc/metadata/filesearch.rs
+++ b/src/librustc/metadata/filesearch.rs
@@ -49,11 +49,11 @@ pub fn mk_filesearch(maybe_sysroot: Option<Path>,
             paths.push(
                 make_target_lib_path(&self.sysroot,
                                      self.target_triple));
-            match get_cargo_lib_path_nearest() {
+            match get_rustpkg_lib_path_nearest() {
               result::Ok(ref p) => paths.push((/*bad*/copy *p)),
               result::Err(_) => ()
             }
-            match get_cargo_lib_path() {
+            match get_rustpkg_lib_path() {
               result::Ok(ref p) => paths.push((/*bad*/copy *p)),
               result::Err(_) => ()
             }
@@ -119,54 +119,54 @@ fn get_sysroot(maybe_sysroot: Option<Path>) -> Path {
     }
 }
 
-pub fn get_cargo_sysroot() -> Result<Path, ~str> {
-    result::Ok(get_or_default_sysroot().push_many([libdir(), ~"cargo"]))
+pub fn get_rustpkg_sysroot() -> Result<Path, ~str> {
+    result::Ok(get_or_default_sysroot().push_many([libdir(), ~"rustpkg"]))
 }
 
-pub fn get_cargo_root() -> Result<Path, ~str> {
-    match os::getenv(~"CARGO_ROOT") {
+pub fn get_rustpkg_root() -> Result<Path, ~str> {
+    match os::getenv(~"RUSTPKG_ROOT") {
         Some(ref _p) => result::Ok(Path((*_p))),
         None => match os::homedir() {
-          Some(ref _q) => result::Ok((*_q).push(".cargo")),
-          None => result::Err(~"no CARGO_ROOT or home directory")
+          Some(ref _q) => result::Ok((*_q).push(".rustpkg")),
+          None => result::Err(~"no RUSTPKG_ROOT or home directory")
         }
     }
 }
 
-pub fn get_cargo_root_nearest() -> Result<Path, ~str> {
-    do result::chain(get_cargo_root()) |p| {
+pub fn get_rustpkg_root_nearest() -> Result<Path, ~str> {
+    do result::chain(get_rustpkg_root()) |p| {
         let cwd = os::getcwd();
-        let cwd_cargo = cwd.push(".cargo");
-        let cargo_is_non_root_file =
-            !os::path_is_dir(&cwd_cargo) && cwd_cargo != p;
-        let mut par_cargo = cwd.pop().push(".cargo");
-        let mut rslt = result::Ok(cwd_cargo);
-
-        if cargo_is_non_root_file {
-            while par_cargo != p {
-                if os::path_is_dir(&par_cargo) {
-                    rslt = result::Ok(par_cargo);
+        let cwd_rustpkg = cwd.push(".rustpkg");
+        let rustpkg_is_non_root_file =
+            !os::path_is_dir(&cwd_rustpkg) && cwd_rustpkg != p;
+        let mut par_rustpkg = cwd.pop().push(".rustpkg");
+        let mut rslt = result::Ok(cwd_rustpkg);
+
+        if rustpkg_is_non_root_file {
+            while par_rustpkg != p {
+                if os::path_is_dir(&par_rustpkg) {
+                    rslt = result::Ok(par_rustpkg);
                     break;
                 }
-                if par_cargo.components.len() == 1 {
-                    // We just checked /.cargo, stop now.
+                if par_rustpkg.components.len() == 1 {
+                    // We just checked /.rustpkg, stop now.
                     break;
                 }
-                par_cargo = par_cargo.pop().pop().push(".cargo");
+                par_rustpkg = par_rustpkg.pop().pop().push(".rustpkg");
             }
         }
         rslt
     }
 }
 
-fn get_cargo_lib_path() -> Result<Path, ~str> {
-    do result::chain(get_cargo_root()) |p| {
+fn get_rustpkg_lib_path() -> Result<Path, ~str> {
+    do result::chain(get_rustpkg_root()) |p| {
         result::Ok(p.push(libdir()))
     }
 }
 
-fn get_cargo_lib_path_nearest() -> Result<Path, ~str> {
-    do result::chain(get_cargo_root_nearest()) |p| {
+fn get_rustpkg_lib_path_nearest() -> Result<Path, ~str> {
+    do result::chain(get_rustpkg_root_nearest()) |p| {
         result::Ok(p.push(libdir()))
     }
 }
diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc
new file mode 100644
index 00000000000..5b610bbb1f8
--- /dev/null
+++ b/src/librustpkg/rustpkg.rc
@@ -0,0 +1,1038 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// rustpkg - a purely function package manager and build system
+
+#[link(name = "rustpkg",
+       vers = "0.6",
+       uuid = "25de5e6e-279e-4a20-845c-4cabae92daaf",
+       url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")];
+
+#[crate_type = "lib"];
+#[no_core];
+#[allow(vecs_implicitly_copyable,
+        non_implicitly_copyable_typarams)];
+
+#[legacy_records];
+
+extern mod core(vers = "0.6");
+extern mod std(vers = "0.6");
+extern mod rustc(vers = "0.6");
+extern mod syntax(vers = "0.6");
+
+use core::*;
+use io::{ReaderUtil, WriterUtil};
+use std::{json, semver, getopts};
+use std::net::url;
+use hashmap::linear::LinearMap;
+use rustc::metadata::filesearch;
+use rustc::driver::{driver, session};
+use syntax::{ast, attr, codemap, diagnostic, parse, visit};
+use syntax::codemap::spanned;
+
+mod usage;
+mod util;
+
+use util::Package;
+
+struct PackageScript {
+    id: ~str,
+    name: ~str,
+    vers: semver::Version,
+    crates: ~[~str],
+    deps: ~[(~str, Option<~str>)],
+    input: driver::input,
+    sess: session::Session,
+    cfg: ast::crate_cfg,
+    crate: @ast::crate,
+    custom: bool
+}
+
+impl PackageScript {
+    static fn parse(parent: &Path) -> Result<PackageScript, ~str> {
+        let script = parent.push(~"pkg.rs");
+
+        if !os::path_exists(&script) {
+            return result::Err(~"no pkg.rs file");
+        }
+
+        let binary = os::args()[0];
+        let options: @session::options = @{
+            binary: binary,
+            crate_type: session::bin_crate,
+            .. *session::basic_options()
+        };
+        let input = driver::file_input(script);
+        let sess = driver::build_session(options, diagnostic::emit);
+        let cfg = driver::build_configuration(sess, binary, input);
+        let {crate, _} = driver::compile_upto(sess, cfg, input,
+                                              driver::cu_parse, None);
+        let mut id = None;
+        let mut vers = None;
+        let mut crates = ~[];
+        let mut deps = ~[];
+
+        fn load_pkg_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
+                                                      Option<~str>) {
+            let mut id = None;
+            let mut vers = None;
+
+            for mis.each |a| {
+                match a.node {
+                    ast::meta_name_value(v, spanned {
+                                                node: ast::lit_str(s),
+                                                span: _}) => {
+                        match v {
+                            ~"id" => id = Some(*s),
+                            ~"vers" => vers = Some(*s),
+                            _ => ()
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            (id, vers)
+        }
+
+        fn load_pkg_dep_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
+                                                          Option<~str>) {
+            let mut url = None;
+            let mut target = None;
+
+            for mis.each |a| {
+                match a.node {
+                    ast::meta_name_value(v, spanned {
+                                                node: ast::lit_str(s),
+                                                span: _}) => {
+                        match v {
+                            ~"url" => url = Some(*s),
+                            ~"target" => target = Some(*s),
+                            _ => ()
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            (url, target)
+        }
+
+        fn load_pkg_crate_attr(mis: ~[@ast::meta_item]) -> Option<~str> {
+            let mut file = None;
+
+            for mis.each |a| {
+                match a.node {
+                    ast::meta_name_value(v, spanned {
+                                                node: ast::lit_str(s),
+                                                span: _}) => {
+                        match v {
+                            ~"file" => file = Some(*s),
+                            _ => ()
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            file
+        }
+
+        for crate.node.attrs.each |a| {
+            match a.node.value.node {
+                ast::meta_list(v, mis) => {
+                    match v {
+                        ~"pkg" => {
+                            let (i, v) = load_pkg_attr(mis);
+
+                            id = i;
+                            vers = v;
+                        }
+                        ~"pkg_dep" => {
+                            let (u, t) = load_pkg_dep_attr(mis);
+
+                            if u.is_none() {
+                                fail!(~"pkg_dep attr without a url value");
+                            }
+
+                            deps.push((u.get(), t));
+                        }
+                        ~"pkg_crate" => {
+                            let f = load_pkg_crate_attr(mis);
+
+                            if f.is_none() {
+                                fail!(~"pkg_file attr without a file value");
+                            }
+
+                            crates.push(f.get());
+                        }
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        let mut custom = false;
+
+        // If we hit a function, we assume they want to use
+        // the build API.
+        for crate.node.module.items.each |i| {
+            match i.node {
+                ast::item_fn(_, _, _, _) => {
+                    custom = true;
+
+                    break;
+                }
+                _ => {}
+            }
+        }
+
+        if id.is_none() || vers.is_none() {
+            return result::Err(~"pkg attr without (id, vers) values");
+        }
+
+        let id = id.get();
+        let name = match util::parse_name(id) {
+            result::Ok(name) => name,
+            result::Err(err) => return result::Err(err)
+        };
+        let vers = match util::parse_vers(vers.get()) {
+            result::Ok(vers) => vers,
+            result::Err(err) => return result::Err(err)
+        };
+
+        result::Ok(PackageScript {
+            id: id,
+            name: name,
+            vers: vers,
+            crates: crates,
+            deps: deps,
+            input: input,
+            sess: sess,
+            cfg: cfg,
+            crate: crate,
+            custom: custom
+        })
+    }
+
+    // Build the bootstrap and run a command
+    // FIXME (#4432): Use workcache to only compile the script when changed
+    fn run(&self, cmd: ~str, test: bool) -> int {
+        let work_dir = self.work_dir();
+        let input = self.input;
+        let sess = self.sess;
+        let cfg = self.cfg;
+        let crate = util::ready_crate(sess, self.crate);
+        let outputs = driver::build_output_filenames(input, &Some(work_dir),
+                                                     &None, sess);
+        let exe = work_dir.push(~"pkg" + util::exe_suffix());
+        let root = filesearch::get_rustpkg_sysroot().get().pop().pop();
+
+        driver::compile_rest(sess, cfg, driver::cu_parse,
+                             Some(outputs), Some(crate));
+        run::run_program(exe.to_str(), ~[root.to_str(), cmd, test.to_str()])
+    }
+
+    fn hash(&self) -> ~str {
+        fmt!("%s-%s-%s", self.name, util::hash(self.id + self.vers.to_str()),
+                         self.vers.to_str())
+    }
+
+    fn work_dir(&self) -> Path {
+        util::root().push(~"work").push(self.hash())
+    }
+}
+
+struct Ctx {
+    cfgs: ~[~str],
+    json: bool,
+    mut dep_cache: LinearMap<~str, bool>
+}
+
+impl Ctx {
+    fn run(&self, cmd: ~str, args: ~[~str]) {
+        let root = util::root();
+
+        util::need_dir(&root);
+        util::need_dir(&root.push(~"work"));
+        util::need_dir(&root.push(~"lib"));
+        util::need_dir(&root.push(~"bin"));
+        util::need_dir(&root.push(~"tmp"));
+
+        fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) {
+            let mut name = None;
+            let mut vers = None;
+            let parts = str::split_char(in, '@');
+
+            if parts.len() >= 1 {
+                name = Some(parts[0]);
+
+                if parts.len() >= 2 {
+                    vers = Some(parts[1]);
+                }
+            }
+
+            (name, vers)
+        }
+
+        match cmd {
+            ~"build" => {
+                self.build(&os::getcwd(), true, false, false);
+            }
+            ~"clean" => {
+                self.clean();
+            }
+            ~"do" => {
+                if args.len() < 1 {
+                    return usage::do_cmd();
+                }
+
+                self.do_cmd(args[0]);
+            }
+            ~"info" => {
+                self.info();
+            }
+            ~"install" => {
+                self.install(if args.len() >= 1 { Some(args[0]) }
+                             else { None },
+                             if args.len() >= 2 { Some(args[1]) }
+                             else { None }, false);
+            }
+            ~"prefer" => {
+                if args.len() < 1 {
+                    return usage::uninstall();
+                }
+
+                let (name, vers) = sep_name_vers(args[0]);
+
+                self.prefer(name.get(), vers);
+            }
+            ~"test" => {
+                self.test();
+            }
+            ~"uninstall" => {
+                if args.len() < 1 {
+                    return usage::uninstall();
+                }
+
+                let (name, vers) = sep_name_vers(args[0]);
+
+                self.uninstall(name.get(), vers);
+            }
+            ~"unprefer" => {
+                if args.len() < 1 {
+                    return usage::uninstall();
+                }
+
+                let (name, vers) = sep_name_vers(args[0]);
+
+                self.unprefer(name.get(), vers);
+            }
+            _ => fail!(~"reached an unhandled command")
+        }
+    }
+
+    fn do_cmd(&self, cmd: ~str) -> bool {
+        match cmd {
+            ~"build" | ~"test" => {
+                util::error(~"that command cannot be manually called");
+
+                return false;
+            }
+            _ => {}
+        }
+
+        let cwd = &os::getcwd();
+        let script = match PackageScript::parse(cwd) {
+            result::Ok(script) => script,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+        let status = script.run(cmd, false);
+
+        if status == 42 {
+            util::error(~"no fns are listening for that cmd");
+
+            return false;
+        }
+
+        status == 0
+    }
+
+    fn build(&self, dir: &Path, verbose: bool, opt: bool,
+             test: bool) -> Option<PackageScript> {
+        let cwd = &os::getcwd();
+        let script = match PackageScript::parse(dir) {
+            result::Ok(script) => script,
+            result::Err(err) => {
+                util::error(err);
+
+                return None;
+            }
+        };
+        let work_dir = script.work_dir();
+        let mut success = true;
+
+        util::need_dir(&work_dir);
+
+        if script.deps.len() >= 1 {
+            util::note(~"installing dependencies");
+
+            for script.deps.each |&dep| {
+                let (url, target) = dep;
+
+                success = self.install(Some(url), target, true);
+
+                if !success { break; }
+            }
+
+
+            if !success {
+                util::error(
+                    fmt!("building %s v%s failed: a dep wasn't installed",
+                         script.name, script.vers.to_str()));
+
+                return None;
+            }
+
+            util::note(~"installed dependencies");
+        }
+
+        // Build imperative crates
+        os::change_dir(dir);
+
+        if script.custom {
+            let status = script.run(~"build", test);
+
+            if status != 0 && status != 42 {
+                util::error(
+                    fmt!("building %s v%s failed: custom logic failed (%d)",
+                         script.name, script.vers.to_str(), status));
+
+                return None;
+            }
+        }
+
+        os::change_dir(cwd);
+
+        for script.crates.each |&crate| {
+            let crate = &dir.push_rel(&Path(crate)).normalize();
+
+            util::note(fmt!("compiling %s", crate.to_str()));
+
+            success = self.compile(crate, &work_dir, ~[],
+                                   ~[], opt, test);
+
+            if !success { break; }
+        }
+
+        if !success {
+            util::error(
+                fmt!("building %s v%s failed: a crate failed to compile",
+                     script.name, script.vers.to_str()));
+
+            return None;
+        }
+
+        if verbose {
+            util::note(fmt!("built %s v%s", script.name,
+                            script.vers.to_str()));
+        }
+
+        Some(script)
+    }
+
+    fn compile(&self, crate: &Path, dir: &Path, flags: ~[~str],
+               cfgs: ~[~str], opt: bool, test: bool) -> bool {
+        util::compile_crate(None, crate, dir, flags, cfgs, opt, test)
+    }
+
+    fn clean(&self) -> bool {
+        let script = match PackageScript::parse(&os::getcwd()) {
+            result::Ok(script) => script,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+        let dir = script.work_dir();
+
+        util::note(fmt!("cleaning %s v%s (%s)", script.name,
+                        script.vers.to_str(), script.id));
+
+        if os::path_exists(&dir) {
+            util::remove_dir_r(&dir);
+            util::note(fmt!("removed %s", dir.to_str()));
+        }
+
+        util::note(fmt!("cleaned %s v%s", script.name,
+                                          script.vers.to_str()));
+
+        true
+    }
+
+    fn info(&self) {
+        if self.json {
+            match PackageScript::parse(&os::getcwd()) {
+                result::Ok(script) => {
+                    let mut map = ~LinearMap::new();
+
+                    map.insert(~"id", json::String(script.id));
+                    map.insert(~"name", json::String(script.name));
+                    map.insert(~"vers", json::String(script.vers.to_str()));
+                    map.insert(~"deps", json::List(do script.deps.map |&dep| {
+                        let (url, target) = dep;
+                        let mut inner = ~LinearMap::new();
+
+                        inner.insert(~"url", json::String(url));
+
+                        if !target.is_none() {
+                            inner.insert(~"target",
+                                         json::String(target.get()));
+                        }
+
+                        json::Object(inner)
+                    }));
+
+                    io::println(json::to_pretty_str(&json::Object(map)));
+                }
+                result::Err(_) => io::println(~"{}")
+            }
+        } else {
+            let script = match PackageScript::parse(&os::getcwd()) {
+                result::Ok(script) => script,
+                result::Err(err) => {
+                    util::error(err);
+
+                    return;
+                }
+            };
+
+            util::note(fmt!("id: %s", script.id));
+            util::note(fmt!("name: %s", script.name));
+            util::note(fmt!("vers: %s", script.vers.to_str()));
+            util::note(fmt!("deps: %s",
+                            if script.deps.len() > 0 {
+                                ~""
+                            } else {
+                                ~"none"
+                            }));
+
+            for script.deps.each |&dep| {
+                let (url, target) = dep;
+
+                util::note(fmt!("  <%s> (%s)", url, match target {
+                    Some(target) => target,
+                    None => ~""
+                }));
+            }
+        }
+    }
+
+    fn install(&self, url: Option<~str>,
+               target: Option<~str>, cache: bool) -> bool {
+        let mut success;
+        let mut dir;
+
+        if url.is_none() {
+            util::note(~"installing from the cwd");
+
+            dir = os::getcwd();
+        } else {
+            let url = url.get();
+            let hash = util::hash(if !target.is_none() { url + target.get() }
+                                  else { url });
+
+            if self.dep_cache.contains_key(&hash) {
+                util::warn(~"already installed dep this run");
+
+                return true;
+            }
+
+            self.dep_cache.insert(hash, true);
+
+            dir = util::root().push(~"tmp").push(hash);
+
+            if cache && os::path_exists(&dir) {
+                return true;
+            }
+
+            success = self.fetch(&dir, url, target);
+
+            if !success {
+                return false;
+            }
+        }
+
+        let script = match self.build(&dir, false, true, false) {
+            Some(script) => script,
+            None => {
+                return false;
+            }
+        };
+        let work_dir = script.work_dir();
+        let from_bin_dir = work_dir.push(~"bin");
+        let from_lib_dir = work_dir.push(~"lib");
+        let to_bin_dir = util::root().push(~"bin");
+        let to_lib_dir = util::root().push(~"lib");
+        let mut bins = ~[];
+        let mut libs = ~[];
+
+        for os::walk_dir(&from_bin_dir) |bin| {
+            let to = to_bin_dir.push_rel(&bin.file_path());
+
+            os::copy_file(bin, &to);
+            bins.push(to.to_str());
+        }
+
+        for os::walk_dir(&from_lib_dir) |lib| {
+            let to = to_lib_dir.push_rel(&lib.file_path());
+
+            os::copy_file(lib, &to);
+            libs.push(to.to_str());
+        }
+
+        let package = Package {
+            id: script.id,
+            vers: script.vers,
+            bins: bins,
+            libs: libs
+        };
+
+        util::note(fmt!("installed %s v%s", script.name,
+                                            script.vers.to_str()));
+        util::add_pkg(&package);
+
+        true
+    }
+
+    fn fetch(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
+        let url = if str::find_str(url, "://").is_none() {
+            ~"http://" + url }
+        else { url };
+        let url = match url::from_str(url) {
+            result::Ok(url) => url,
+            result::Err(err) => {
+                util::error(fmt!("failed parsing %s", err.to_lower()));
+
+                return false;
+            }
+        };
+        let str = url.to_str();
+
+        match Path(url.path).filetype() {
+            Some(ext) => {
+                if ext == ~".git" {
+                    return self.fetch_git(dir, str, target);
+                }
+            }
+            None => {}
+        }
+
+        match url.scheme {
+            ~"git" => self.fetch_git(dir, str, target),
+            ~"http" | ~"ftp" | ~"file" => self.fetch_curl(dir, str),
+            _ => {
+                util::warn(~"unknown url scheme to fetch, using curl");
+                self.fetch_curl(dir, str)
+            }
+        }
+    }
+
+    fn fetch_curl(&self, dir: &Path, url: ~str) -> bool {
+        util::note(fmt!("fetching from %s using curl", url));
+
+        let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar");
+
+        if run::program_output(~"curl", ~[~"-f", ~"-s",
+                                          ~"-o", tar.to_str(),
+                                          url]).status != 0 {
+            util::error(~"fetching failed: downloading using curl failed");
+
+            return false;
+        }
+
+        if run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
+                                         ~"-C", dir.to_str(), ~"-f",
+                                         tar.to_str()]).status != 0 {
+            util::error(~"fetching failed: extracting using tar failed" +
+                        ~"(is it a valid tar archive?)");
+
+            return false;
+        }
+
+        true
+    }
+
+    fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
+        util::note(fmt!("fetching from %s using git", url));
+
+        // Git can't clone into a non-empty directory
+        util::remove_dir_r(dir);
+
+        if run::program_output(~"git", ~[~"clone", url,
+                                         dir.to_str()]).status != 0 {
+            util::error(~"fetching failed: can't clone repository");
+
+            return false;
+        }
+
+        if !target.is_none() {
+            let mut success = true;
+
+            do util::temp_change_dir(dir) {
+                success = run::program_output(~"git",
+                                              ~[~"checkout",
+                                                target.get()]).status != 0
+            }
+
+            if !success {
+                util::error(~"fetching failed: can't checkout target");
+
+                return false;
+            }
+        }
+
+        true
+    }
+
+    fn prefer(&self, id: ~str, vers: Option<~str>) -> bool {
+        let package = match util::get_pkg(id, vers) {
+            result::Ok(package) => package,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+        let name = match util::parse_name(package.id) {
+            result::Ok(name) => name,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+
+        util::note(fmt!("preferring %s v%s (%s)", name, package.vers.to_str(),
+                                                  package.id));
+
+        let bin_dir = util::root().push(~"bin");
+
+        for package.bins.each |&bin| {
+            let path = Path(bin);
+            let name = str::split_char(path.file_path().to_str(), '-')[0];
+            let out = bin_dir.push(name);
+
+            util::link_exe(&path, &out);
+            util::note(fmt!("linked %s", out.to_str()));
+        }
+
+        util::note(fmt!("preferred %s v%s", name, package.vers.to_str()));
+
+        true
+    }
+
+    fn test(&self) -> bool {
+        let script = match self.build(&os::getcwd(), false, false, true) {
+            Some(script) => script,
+            None => {
+                return false;
+            }
+        };
+        let work_dir = script.work_dir();
+        let test_dir = work_dir.push(~"test");
+
+        for os::walk_dir(&test_dir) |test| {
+            util::note(fmt!("running %s", test.to_str()));
+
+            let status = run::run_program(test.to_str(), ~[]);
+
+            if status != 0 {
+                os::set_exit_status(status);
+            }
+        }
+
+        // Run custom test listener
+        if script.custom {
+            let status = script.run(~"test", false);
+
+            if status != 0 && status != 42 {
+                util::error(
+                    fmt!("testing %s v%s failed: custom logic failed (%d)",
+                         script.name, script.vers.to_str(), status));
+
+                os::set_exit_status(status);
+            }
+        }
+
+        util::note(fmt!("tested %s v%s", script.name, script.vers.to_str()));
+
+        true
+    }
+
+    fn uninstall(&self, id: ~str, vers: Option<~str>) -> bool {
+        let package = match util::get_pkg(id, vers) {
+            result::Ok(package) => package,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+        let name = match util::parse_name(package.id) {
+            result::Ok(name) => name,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+
+        util::note(fmt!("uninstalling %s v%s (%s)", name,
+                        package.vers.to_str(), package.id));
+
+        for vec::append(package.bins, package.libs).each |&file| {
+            let path = Path(file);
+
+            if os::path_exists(&path) {
+                if os::remove_file(&path) {
+                    util::note(fmt!("removed %s", path.to_str()));
+                } else {
+                    util::error(fmt!("could not remove %s", path.to_str()));
+                }
+            }
+        }
+
+        util::note(fmt!("uninstalled %s v%s", name, package.vers.to_str()));
+        util::remove_pkg(&package);
+
+        true
+    }
+
+    fn unprefer(&self, id: ~str, vers: Option<~str>) -> bool {
+        let package = match util::get_pkg(id, vers) {
+            result::Ok(package) => package,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+        let name = match util::parse_name(package.id) {
+            result::Ok(name) => name,
+            result::Err(err) => {
+                util::error(err);
+
+                return false;
+            }
+        };
+
+        util::note(fmt!("unpreferring %s v%s (%s)", name,
+                        package.vers.to_str(), package.id));
+
+        let bin_dir = util::root().push(~"bin");
+
+        for package.bins.each |&bin| {
+            let path = Path(bin);
+            let name = str::split_char(path.file_path().to_str(), '-')[0];
+            let out = bin_dir.push(name);
+
+            if os::path_exists(&out) {
+                if os::remove_file(&out) {
+                    util::note(fmt!("unlinked %s", out.to_str()));
+                } else {
+                    util::error(fmt!("could not unlink %s", out.to_str()));
+                }
+            }
+        }
+
+        util::note(fmt!("unpreferred %s v%s", name, package.vers.to_str()));
+
+        true
+    }
+}
+
+pub fn main() {
+    let args = os::args();
+    let opts = ~[getopts::optflag(~"h"), getopts::optflag(~"help"),
+                 getopts::optflag(~"j"), getopts::optflag(~"json"),
+                 getopts::optmulti(~"c"), getopts::optmulti(~"cfg")];
+    let matches = &match getopts::getopts(args, opts) {
+        result::Ok(m) => m,
+        result::Err(f) => {
+            util::error(fmt!("%s", getopts::fail_str(f)));
+
+            return;
+        }
+    };
+    let help = getopts::opt_present(matches, ~"h") ||
+               getopts::opt_present(matches, ~"help");
+    let json = getopts::opt_present(matches, ~"j") ||
+               getopts::opt_present(matches, ~"json");
+    let cfgs = vec::append(getopts::opt_strs(matches, ~"cfg"),
+                           getopts::opt_strs(matches, ~"c"));
+    let mut args = copy matches.free;
+
+    args.shift();
+
+    if (args.len() < 1) {
+        return usage::general();
+    }
+
+    let cmd = args.shift();
+
+    if !util::is_cmd(cmd) {
+        return usage::general();
+    } else if help {
+        return match cmd {
+            ~"build" => usage::build(),
+            ~"clean" => usage::clean(),
+            ~"do" => usage::do_cmd(),
+            ~"info" => usage::info(),
+            ~"install" => usage::install(),
+            ~"prefer" => usage::prefer(),
+            ~"test" => usage::test(),
+            ~"uninstall" => usage::uninstall(),
+            ~"unprefer" => usage::unprefer(),
+            _ => usage::general()
+        };
+    }
+
+    Ctx {
+        cfgs: cfgs,
+        json: json,
+        mut dep_cache: LinearMap::new()
+    }.run(cmd, args);
+}
+
+/// A crate is a unit of Rust code to be compiled into a binary or library
+pub struct Crate {
+    file: ~str,
+    flags: ~[~str],
+    cfgs: ~[~str]
+}
+
+pub struct Listener {
+    cmds: ~[~str],
+    cb: fn~()
+}
+
+pub fn run(listeners: ~[Listener]) {
+    let rcmd = os::args()[2];
+    let mut found = false;
+
+    for listeners.each |listener| {
+        for listener.cmds.each |&cmd| {
+            if cmd == rcmd {
+                (listener.cb)();
+
+                found = true;
+
+                break;
+            }
+        }
+    }
+
+    if !found {
+        os::set_exit_status(42);
+    }
+}
+
+pub impl Crate {
+    pub fn flag(&self, flag: ~str) -> Crate {
+        Crate {
+            flags: vec::append(copy self.flags, ~[flag]),
+            .. copy *self
+        }
+    }
+
+    pub fn flags(&self, flags: ~[~str]) -> Crate {
+        Crate {
+            flags: vec::append(copy self.flags, flags),
+            .. copy *self
+        }
+    }
+
+    pub fn cfg(&self, cfg: ~str) -> Crate {
+        Crate {
+            cfgs: vec::append(copy self.cfgs, ~[cfg]),
+            .. copy *self
+        }
+    }
+
+    pub fn cfgs(&self, cfgs: ~[~str]) -> Crate {
+        Crate {
+            cfgs: vec::append(copy self.cfgs, cfgs),
+            .. copy *self
+        }
+    }
+}
+
+/// Create a crate target from a source file
+pub fn Crate(file: ~str) -> Crate {
+    Crate {
+        file: file,
+        flags: ~[],
+        cfgs: ~[]
+    }
+}
+
+/**
+ * Get the working directory of the package script.
+ * Assumes that the package script has been compiled
+ * in is the working directory.
+ */
+pub fn work_dir() -> Path {
+    os::self_exe_path().get()
+}
+
+/**
+ * Get the source directory of the package (i.e.
+ * where the crates are located). Assumes
+ * that the cwd is changed to it before
+ * running this executable.
+ */
+pub fn src_dir() -> Path {
+    os::getcwd()
+}
+
+/// Build a set of crates, should be called once
+pub fn build(crates: ~[Crate]) -> bool {
+    let args = os::args();
+    let dir = src_dir();
+    let work_dir = work_dir();
+    let mut success = true;
+    let sysroot = Path(args[1]);
+    let test = args[3] == ~"true";
+
+    for crates.each |&crate| {
+        let path = &dir.push_rel(&Path(crate.file)).normalize();
+
+        util::note(fmt!("compiling %s", path.to_str()));
+
+        success = util::compile_crate(Some(sysroot), path, &work_dir,
+                                      crate.flags, crate.cfgs,
+                                      false, test);
+
+        if !success { break; }
+    }
+
+    if !success {
+        os::set_exit_status(101);
+    }
+
+    success
+}
diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs
new file mode 100644
index 00000000000..cfda56f777a
--- /dev/null
+++ b/src/librustpkg/usage.rs
@@ -0,0 +1,121 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::io;
+
+pub fn general() {
+    io::println(~"Usage: rustpkg [options] <cmd> [args..]
+
+Where <cmd> is one of:
+    build, clean, do, info, install, prefer, test, uninstall, unprefer
+
+Options:
+
+    -h, --help                  Display this message
+    <cmd> -h, <cmd> --help      Display help for <cmd>");
+}
+
+pub fn build() {
+    io::println(~"rustpkg [options..] build
+
+Build all targets described in the package script in the current
+directory.
+
+Options:
+    -c, --cfg      Pass a cfg flag to the package script");
+}
+
+pub fn clean() {
+    io::println(~"rustpkg clean
+
+Remove all build files in the work cache for the package in the current
+directory.");
+}
+
+pub fn do_cmd() {
+    io::println(~"rustpkg do <cmd>
+
+Runs a command in the package script. You can listen to a command
+by tagging a function with the attribute `#[pkg_do(cmd)]`.");
+}
+
+pub fn info() {
+    io::println(~"rustpkg [options..] info
+
+Probe the package script in the current directory for information.
+
+Options:
+    -j, --json      Output the result as JSON");
+}
+
+pub fn install() {
+    io::println(~"rustpkg [options..] install [url] [target]
+
+Install a package from a URL by Git or cURL (FTP, HTTP, etc.).
+If target is provided, Git will checkout the branch or tag before
+continuing. If the URL is a TAR file (with or without compression),
+extract it before installing. If a URL isn't provided, the package will
+be built and installed from the current directory (which is
+functionally the same as `rustpkg build` and installing the result).
+
+Examples:
+    rustpkg install
+    rustpkg install git://github.com/mozilla/servo.git
+    rustpkg install git://github.com/mozilla/servo.git v0.1.2
+    rustpkg install http://rust-lang.org/servo-0.1.2.tar.gz
+
+Options:
+    -c, --cfg      Pass a cfg flag to the package script");
+}
+
+pub fn uninstall() {
+    io::println(~"rustpkg uninstall <id|name>[@version]
+
+Remove a package by id or name and optionally version. If the package(s)
+is/are depended on by another package then they cannot be removed.");
+}
+
+pub fn prefer() {
+    io::println(~"rustpkg [options..] prefer <id|name>[@version]
+
+By default all binaries are given a unique name so that multiple versions can
+coexist. The prefer command will symlink the uniquely named binary to
+the binary directory under its bare name. If version is not supplied, the
+latest version of the package will be preferred.
+
+Example:
+    export PATH=$PATH:/home/user/.rustpkg/bin
+    rustpkg prefer machine@1.2.4
+    machine -v
+    ==> v1.2.4
+    rustpkg prefer machine@0.4.6
+    machine -v
+    ==> v0.4.6");
+}
+
+pub fn unprefer() {
+    io::println(~"rustpkg [options..] unprefer <id|name>[@version]
+
+Remove all symlinks from the store to the binary directory for a package
+name and optionally version. If version is not supplied, the latest version
+of the package will be unpreferred. See `rustpkg prefer -h` for more
+information.");
+}
+
+pub fn test() {
+    io::println(~"rustpkg [options..] test
+
+Build all targets described in the package script in the current directory
+with the test flag. The test bootstraps will be run afterwards and the output
+and exit code will be redirected.
+
+Options:
+    -c, --cfg      Pass a cfg flag to the package script");
+}
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
new file mode 100644
index 00000000000..1ad706742a8
--- /dev/null
+++ b/src/librustpkg/util.rs
@@ -0,0 +1,803 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::*;
+use hashmap::linear::LinearMap;
+use rustc::metadata::filesearch;
+use rustc::driver::{driver, session};
+use syntax::ast_util::*;
+use syntax::{ast, attr, codemap, diagnostic, fold, parse, visit};
+use codemap::{span, dummy_sp, spanned};
+use std::semver;
+use std::{json, term, sort, getopts};
+use getopts::groups::getopts;
+use Listener;
+
+use syntax::ext::base::{mk_ctxt, ext_ctxt};
+use syntax::ext::build;
+
+pub struct Package {
+    id: ~str,
+    vers: semver::Version,
+    bins: ~[~str],
+    libs: ~[~str],
+}
+
+pub fn root() -> Path {
+    match filesearch::get_rustpkg_root() {
+        result::Ok(path) => path,
+        result::Err(err) => fail!(err)
+    }
+}
+
+pub fn is_cmd(cmd: ~str) -> bool {
+    let cmds = &[~"build", ~"clean", ~"do", ~"info", ~"install", ~"prefer",
+                 ~"test", ~"uninstall", ~"unprefer"];
+
+    vec::contains(cmds, &cmd)
+}
+
+pub fn parse_name(id: ~str) -> result::Result<~str, ~str> {
+    let parts = str::split_char(id, '.');
+
+    for parts.each |&part| {
+        for str::chars(part).each |&char| {
+            if char::is_whitespace(char) {
+                return result::Err(
+                    ~"could not parse id: contains whitespace");
+            } else if char::is_uppercase(char) {
+                return result::Err(
+                    ~"could not parse id: should be all lowercase");
+            }
+        }
+    }
+
+    result::Ok(parts.last())
+}
+
+struct ListenerFn {
+    cmds: ~[~str],
+    span: codemap::span,
+    path: ~[ast::ident]
+}
+
+struct ReadyCtx {
+    sess: session::Session,
+    crate: @ast::crate,
+    ext_cx: ext_ctxt,
+    mut path: ~[ast::ident],
+    mut fns: ~[ListenerFn]
+}
+
+fn fold_mod(_ctx: @ReadyCtx, m: ast::_mod,
+            fold: fold::ast_fold) -> ast::_mod {
+    fn strip_main(item: @ast::item) -> @ast::item {
+        @ast::item {
+            attrs: do item.attrs.filtered |attr| {
+                attr::get_attr_name(*attr) != ~"main"
+            },
+            .. copy *item
+        }
+    }
+
+    fold::noop_fold_mod(ast::_mod {
+        items: do vec::map(m.items) |item| {
+            strip_main(*item)
+        },
+        .. m
+    }, fold)
+}
+
+fn fold_item(ctx: @ReadyCtx, item: @ast::item,
+             fold: fold::ast_fold) -> Option<@ast::item> {
+
+    ctx.path.push(item.ident);
+
+    let attrs = attr::find_attrs_by_name(item.attrs, ~"pkg_do");
+
+    if attrs.len() > 0 {
+        let mut cmds = ~[];
+
+        for attrs.each |attr| {
+            match attr.node.value.node {
+                ast::meta_list(_, mis) => {
+                    for mis.each |mi| {
+                        match mi.node {
+                            ast::meta_word(cmd) => cmds.push(cmd),
+                            _ => {}
+                        };
+                    }
+                }
+                _ => cmds.push(~"build")
+            };
+        }
+
+        ctx.fns.push(ListenerFn {
+            cmds: cmds,
+            span: item.span,
+            path: /*bad*/copy ctx.path
+        });
+    }
+
+    let res = fold::noop_fold_item(item, fold);
+
+    ctx.path.pop();
+
+    res
+}
+
+fn add_pkg_module(ctx: @ReadyCtx, m: ast::_mod) -> ast::_mod {
+    let listeners = mk_listener_vec(ctx);
+    let ext_cx = ctx.ext_cx;
+    let item = quote_item! (
+        mod __pkg {
+            extern mod rustpkg (vers="0.6");
+            const listeners : &[rustpkg::Listener] = $listeners;
+            #[main]
+            fn main() {
+                rustpkg::run(listeners);
+            }
+        }
+    );
+    ast::_mod {
+        items: vec::append_one(/*bad*/copy m.items, item.get()),
+        .. m
+    }
+}
+
+fn mk_listener_vec(ctx: @ReadyCtx) -> @ast::expr {
+    let fns = ctx.fns;
+    let descs = do fns.map |listener| {
+        mk_listener_rec(ctx, *listener)
+    };
+    build::mk_slice_vec_e(ctx.ext_cx, dummy_sp(), descs)
+}
+
+fn mk_listener_rec(ctx: @ReadyCtx, listener: ListenerFn) -> @ast::expr {
+
+    let span = listener.span;
+    let cmds = do listener.cmds.map |&cmd| {
+        build::mk_base_str(ctx.ext_cx, span, cmd)
+    };
+
+    let cmds_expr = build::mk_slice_vec_e(ctx.ext_cx, span, cmds);
+    let cb_expr = build::mk_path(ctx.ext_cx, span, copy listener.path);
+    let ext_cx = ctx.ext_cx;
+
+    quote_expr!(
+        Listener {
+            cmds: $cmds_expr,
+            cb: $cb_expr
+        }
+    )
+}
+
+/// Generate/filter main function, add the list of commands, etc.
+pub fn ready_crate(sess: session::Session,
+                   crate: @ast::crate) -> @ast::crate {
+    let ctx = @ReadyCtx {
+        sess: sess,
+        crate: crate,
+        ext_cx: mk_ctxt(sess.parse_sess, copy sess.opts.cfg),
+        mut path: ~[],
+        mut fns: ~[]
+    };
+    let precursor = @fold::AstFoldFns {
+        // fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
+        fold_item: |a, b| fold_item(ctx, a, b),
+        fold_mod: |a, b| fold_mod(ctx, a, b),
+        .. *fold::default_ast_fold()
+    };
+
+    let fold = fold::make_fold(precursor);
+
+    @fold.fold_crate(*crate)
+}
+
+pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
+    match semver::parse(vers) {
+        Some(vers) => result::Ok(vers),
+        None => result::Err(~"could not parse version: invalid")
+    }
+}
+
+pub fn need_dir(s: &Path) {
+    if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) {
+        fail!(fmt!("can't create dir: %s", s.to_str()));
+    }
+}
+
+pub fn note(msg: ~str) {
+    let out = io::stdout();
+
+    if term::color_supported() {
+        term::fg(out, term::color_green);
+        out.write_str(~"note: ");
+        term::reset(out);
+        out.write_line(msg);
+    } else {
+        out.write_line(~"note: " + msg);
+    }
+}
+
+pub fn warn(msg: ~str) {
+    let out = io::stdout();
+
+    if term::color_supported() {
+        term::fg(out, term::color_yellow);
+        out.write_str(~"warning: ");
+        term::reset(out);
+        out.write_line(msg);
+    } else {
+        out.write_line(~"warning: " + msg);
+    }
+}
+
+pub fn error(msg: ~str) {
+    let out = io::stdout();
+
+    if term::color_supported() {
+        term::fg(out, term::color_red);
+        out.write_str(~"error: ");
+        term::reset(out);
+        out.write_line(msg);
+    } else {
+        out.write_line(~"error: " + msg);
+    }
+}
+
+pub fn hash(data: ~str) -> ~str {
+    let hasher = hash::default_state();
+
+    hasher.write_str(data);
+    hasher.result_str()
+}
+
+pub fn temp_change_dir<T>(dir: &Path, cb: fn() -> T) {
+    let cwd = os::getcwd();
+
+    os::change_dir(dir);
+    cb();
+    os::change_dir(&cwd);
+}
+
+pub fn touch(path: &Path) {
+    match io::mk_file_writer(path, ~[io::Create]) {
+        result::Ok(writer) => writer.write_line(~""),
+        _ => {}
+    }
+}
+
+pub fn remove_dir_r(path: &Path) {
+    for os::walk_dir(path) |&file| {
+        let mut cdir = file;
+
+        loop {
+            if os::path_is_dir(&cdir) {
+                os::remove_dir(&cdir);
+            } else {
+                os::remove_file(&cdir);
+            }
+
+            cdir = cdir.dir_path();
+
+            if cdir == *path { break; }
+        }
+    }
+
+    os::remove_dir(path);
+}
+
+pub fn wait_for_lock(path: &Path) {
+    if os::path_exists(path) {
+        warn(fmt!("the database appears locked, please wait (or rm %s)",
+                        path.to_str()));
+
+        loop {
+            if !os::path_exists(path) { break; }
+        }
+    }
+}
+
+fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] {
+    for packages.each |&package| {
+        match &package {
+            &json::Object(ref map) => {
+                let mut has_id = false;
+
+                match map.get(&~"id") {
+                    &json::String(ref str) => {
+                        if pkg.id == *str {
+                            has_id = true;
+                        }
+                    }
+                    _ => {}
+                }
+
+                match map.get(&~"vers") {
+                    &json::String(ref str) => {
+                        if has_id && pkg.vers.to_str() == *str {
+                            return copy packages;
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+    }
+
+    let mut map = ~LinearMap::new();
+
+    map.insert(~"id", json::String(pkg.id));
+    map.insert(~"vers", json::String(pkg.vers.to_str()));
+    map.insert(~"bins", json::List(do pkg.bins.map |&bin| {
+        json::String(bin)
+    }));
+    map.insert(~"libs", json::List(do pkg.libs.map |&lib| {
+        json::String(lib)
+    }));
+
+    vec::append(packages, ~[json::Object(map)])
+}
+
+fn _rm_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] {
+    do packages.filter_mapped |&package| {
+        match &package {
+            &json::Object(ref map) => {
+                let mut has_id = false;
+
+                match map.get(&~"id") {
+                    &json::String(str) => {
+                        if pkg.id == str {
+                            has_id = true;
+                        }
+                    }
+                    _ => {}
+                }
+
+                match map.get(&~"vers") {
+                    &json::String(ref str) => {
+                        if has_id && pkg.vers.to_str() == *str {
+                            None
+                        } else {
+                            Some(copy package)
+                        }
+                    }
+                    _ => { Some(copy package) }
+                }
+            }
+            _ => { Some(copy package) }
+        }
+    }
+}
+
+pub fn load_pkgs() -> result::Result<~[json::Json], ~str> {
+    let root = root();
+    let db = root.push(~"db.json");
+    let db_lock = root.push(~"db.json.lck");
+
+    wait_for_lock(&db_lock);
+    touch(&db_lock);
+
+    let packages = if os::path_exists(&db) {
+        match io::read_whole_file_str(&db) {
+            result::Ok(str) => {
+                match json::from_str(str) {
+                    result::Ok(json) => {
+                        match json {
+                            json::List(list) => list,
+                            _ => {
+                                os::remove_file(&db_lock);
+
+                                return result::Err(
+                                    ~"package db's json is not a list");
+                            }
+                        }
+                    }
+                    result::Err(err) => {
+                        os::remove_file(&db_lock);
+
+                        return result::Err(
+                            fmt!("failed to parse package db: %s",
+                            err.to_str()));
+                    }
+                }
+            }
+            result::Err(err) => {
+                os::remove_file(&db_lock);
+
+                return result::Err(fmt!("failed to read package db: %s",
+                                        err));
+            }
+        }
+    } else { ~[] };
+
+    os::remove_file(&db_lock);
+
+    result::Ok(packages)
+}
+
+pub fn get_pkg(id: ~str,
+               vers: Option<~str>) -> result::Result<Package, ~str> {
+    let name = match parse_name(id) {
+        result::Ok(name) => name,
+        result::Err(err) => return result::Err(err)
+    };
+    let packages = match load_pkgs() {
+        result::Ok(packages) => packages,
+        result::Err(err) => return result::Err(err)
+    };
+    let mut sel = None;
+    let mut possibs = ~[];
+    let mut err = None;
+
+    for packages.each |&package| {
+        match package {
+            json::Object(map) => {
+                let pid = match map.get(&~"id") {
+                    &json::String(str) => str,
+                    _ => loop
+                };
+                let pname = match parse_name(pid) {
+                    result::Ok(pname) => pname,
+                    result::Err(perr) => {
+                        err = Some(perr);
+
+                        break;
+                    }
+                };
+                let pvers = match map.get(&~"vers") {
+                    &json::String(str) => str,
+                    _ => loop
+                };
+                if pid == id || pname == name {
+                    let bins = match map.get(&~"bins") {
+                        &json::List(ref list) => {
+                            do list.map |&bin| {
+                                match bin {
+                                    json::String(str) => str,
+                                    _ => ~""
+                                }
+                            }
+                        }
+                        _ => ~[]
+                    };
+                    let libs = match map.get(&~"libs") {
+                        &json::List(ref list) => {
+                            do list.map |&lib| {
+                                match lib {
+                                    json::String(str) => str,
+                                    _ => ~""
+                                }
+                            }
+                        }
+                        _ => ~[]
+                    };
+                    let package = Package {
+                        id: pid,
+                        vers: match parse_vers(pvers) {
+                            result::Ok(vers) => vers,
+                            result::Err(verr) => {
+                                err = Some(verr);
+
+                                break;
+                            }
+                        },
+                        bins: bins,
+                        libs: libs
+                    };
+
+                    if !vers.is_none() && vers.get() == pvers {
+                        sel = Some(package);
+                    }
+                    else {
+                        possibs.push(package);
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
+    if !err.is_none() {
+        return result::Err(err.get());
+    }
+    if !sel.is_none() {
+        return result::Ok(sel.get());
+    }
+    if !vers.is_none() || possibs.len() < 1 {
+        return result::Err(~"package not found");
+    }
+
+    result::Ok(sort::merge_sort(possibs, |v1, v2| {
+        v1.vers <= v2.vers
+    }).last())
+}
+
+pub fn add_pkg(pkg: &Package) -> bool {
+    let root = root();
+    let db = root.push(~"db.json");
+    let db_lock = root.push(~"db.json.lck");
+    let packages = match load_pkgs() {
+        result::Ok(packages) => packages,
+        result::Err(err) => {
+            error(err);
+
+            return false;
+        }
+    };
+
+    wait_for_lock(&db_lock);
+    touch(&db_lock);
+    os::remove_file(&db);
+
+    match io::mk_file_writer(&db, ~[io::Create]) {
+        result::Ok(writer) => {
+            writer.write_line(json::to_pretty_str(&json::List(
+                _add_pkg(packages, pkg))));
+        }
+        result::Err(err) => {
+            error(fmt!("failed to dump package db: %s", err));
+            os::remove_file(&db_lock);
+
+            return false;
+        }
+    }
+
+    os::remove_file(&db_lock);
+
+    true
+}
+
+pub fn remove_pkg(pkg: &Package) -> bool {
+    let root = root();
+    let db = root.push(~"db.json");
+    let db_lock = root.push(~"db.json.lck");
+    let packages = match load_pkgs() {
+        result::Ok(packages) => packages,
+        result::Err(err) => {
+            error(err);
+
+            return false;
+        }
+    };
+
+    wait_for_lock(&db_lock);
+    touch(&db_lock);
+    os::remove_file(&db);
+
+    match io::mk_file_writer(&db, ~[io::Create]) {
+        result::Ok(writer) => {
+            writer.write_line(json::to_pretty_str(&json::List(
+                _rm_pkg(packages, pkg))));
+        }
+        result::Err(err) => {
+            error(fmt!("failed to dump package db: %s", err));
+            os::remove_file(&db_lock);
+
+            return false;
+        }
+    }
+
+    os::remove_file(&db_lock);
+
+    true
+}
+
+pub fn compile_input(sysroot: Option<Path>, input: driver::input, dir: &Path,
+               flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool {
+    let lib_dir = dir.push(~"lib");
+    let bin_dir = dir.push(~"bin");
+    let test_dir = dir.push(~"test");
+    let binary = os::args()[0];
+    let matches = getopts(flags, driver::optgroups()).get();
+    let options = @{
+        crate_type: session::unknown_crate,
+        optimize: if opt { session::Aggressive } else { session::No },
+        test: test,
+        maybe_sysroot: sysroot,
+        .. *driver::build_session_options(binary, &matches, diagnostic::emit)
+    };
+    let mut crate_cfg = options.cfg;
+
+    for cfgs.each |&cfg| {
+        crate_cfg.push(attr::mk_word_item(cfg));
+    }
+
+    let options = @{
+        cfg: vec::append(options.cfg, crate_cfg),
+        .. *options
+    };
+    let sess = driver::build_session(options, diagnostic::emit);
+    let cfg = driver::build_configuration(sess, binary, input);
+    let mut outputs = driver::build_output_filenames(input, &None, &None,
+                                                     sess);
+    let {crate, _} = driver::compile_upto(sess, cfg, input, driver::cu_parse,
+                                          Some(outputs));
+
+    let mut name = None;
+    let mut vers = None;
+    let mut uuid = None;
+    let mut crate_type = None;
+
+    fn load_link_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
+                                                   Option<~str>,
+                                                   Option<~str>) {
+        let mut name = None;
+        let mut vers = None;
+        let mut uuid = None;
+
+        for mis.each |a| {
+            match a.node {
+                ast::meta_name_value(v, spanned {node: ast::lit_str(s),
+                                         span: _}) => {
+                    match v {
+                        ~"name" => name = Some(*s),
+                        ~"vers" => vers = Some(*s),
+                        ~"uuid" => uuid = Some(*s),
+                        _ => { }
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        (name, vers, uuid)
+    }
+
+    for crate.node.attrs.each |a| {
+        match a.node.value.node {
+            ast::meta_name_value(v, spanned {node: ast::lit_str(s),
+                                     span: _}) => {
+                match v {
+                    ~"crate_type" => crate_type = Some(*s),
+                    _ => {}
+                }
+            }
+            ast::meta_list(v, mis) => {
+                match v {
+                    ~"link" => {
+                        let (n, v, u) = load_link_attr(mis);
+
+                        name = n;
+                        vers = v;
+                        uuid = u;
+                    }
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+    }
+
+    if name.is_none() || vers.is_none() || uuid.is_none() {
+        error(~"link attr without (name, vers, uuid) values");
+
+        return false;
+    }
+
+    let name = name.get();
+    let vers = vers.get();
+    let uuid = uuid.get();
+
+    let is_bin = match crate_type {
+        Some(crate_type) => {
+            match crate_type {
+                ~"bin" => true,
+                ~"lib" => false,
+                _ => {
+                    warn(~"unknown crate_type, falling back to lib");
+
+                    false
+                }
+            }
+        }
+        None => {
+            warn(~"missing crate_type attr, assuming lib");
+
+            false
+        }
+    };
+
+    if test {
+        need_dir(&test_dir);
+
+        outputs = driver::build_output_filenames(input, &Some(test_dir),
+                                                 &None, sess)
+    }
+    else if is_bin {
+        need_dir(&bin_dir);
+
+        let path = bin_dir.push(fmt!("%s-%s-%s%s", name,
+                                                   hash(name + uuid + vers),
+                                                   vers, exe_suffix()));
+        outputs = driver::build_output_filenames(input, &None, &Some(path),
+                                                 sess);
+    } else {
+        need_dir(&lib_dir);
+
+        outputs = driver::build_output_filenames(input, &Some(lib_dir),
+                                                 &None, sess)
+    }
+
+    driver::compile_rest(sess, cfg, driver::cu_everything,
+                         Some(outputs), Some(crate));
+
+    true
+}
+
+#[cfg(windows)]
+pub fn exe_suffix() -> ~str { ~".exe" }
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "android")]
+#[cfg(target_os = "freebsd")]
+#[cfg(target_os = "macos")]
+pub fn exe_suffix() -> ~str { ~"" }
+
+
+// FIXME (#4432): Use workcache to only compile when needed
+pub fn compile_crate(sysroot: Option<Path>, crate: &Path, dir: &Path,
+                     flags: ~[~str], cfgs: ~[~str], opt: bool,
+                     test: bool) -> bool {
+    compile_input(sysroot, driver::file_input(*crate), dir, flags, cfgs,
+                  opt, test)
+}
+
+pub fn compile_str(sysroot: Option<Path>, code: ~str, dir: &Path,
+                   flags: ~[~str], cfgs: ~[~str], opt: bool,
+                   test: bool) -> bool {
+    compile_input(sysroot, driver::str_input(code), dir, flags, cfgs,
+                  opt, test)
+}
+
+#[cfg(windows)]
+pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
+    /* FIXME (#1768): Investigate how to do this on win32
+       Node wraps symlinks by having a .bat,
+       but that won't work with minGW. */
+
+    false
+}
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "android")]
+#[cfg(target_os = "freebsd")]
+#[cfg(target_os = "macos")]
+pub fn link_exe(src: &Path, dest: &Path) -> bool {
+    unsafe {
+        do str::as_c_str(src.to_str()) |src_buf| {
+            do str::as_c_str(dest.to_str()) |dest_buf| {
+                libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
+                    libc::chmod(dest_buf, 755) == 0 as libc::c_int
+            }
+        }
+    }
+}
+
+#[test]
+fn test_is_cmd() {
+    assert is_cmd(~"build");
+    assert is_cmd(~"clean");
+    assert is_cmd(~"do");
+    assert is_cmd(~"info");
+    assert is_cmd(~"install");
+    assert is_cmd(~"prefer");
+    assert is_cmd(~"test");
+    assert is_cmd(~"uninstall");
+    assert is_cmd(~"unprefer");
+}
+
+#[test]
+fn test_parse_name() {
+    assert parse_name(~"org.mozilla.servo").get() == ~"servo";
+    assert parse_name(~"org. mozilla.servo 2131").is_err();
+}
diff --git a/src/libstd/semver.rs b/src/libstd/semver.rs
new file mode 100644
index 00000000000..97c60330a7e
--- /dev/null
+++ b/src/libstd/semver.rs
@@ -0,0 +1,395 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Semver parsing and logic
+
+use io;
+use io::{ReaderUtil};
+use option::{Option, Some, None};
+use uint;
+use str;
+use to_str::ToStr;
+use char;
+use core::cmp;
+
+#[deriving_eq]
+pub enum Identifier {
+    Numeric(uint),
+    AlphaNumeric(~str)
+}
+
+impl cmp::Ord for Identifier {
+    #[inline(always)]
+    pure fn lt(&self, other: &Identifier) -> bool {
+        match (self, other) {
+            (&Numeric(a), &Numeric(b)) => a < b,
+            (&Numeric(_), _) => true,
+            (&AlphaNumeric(ref a), &AlphaNumeric(ref b)) => *a < *b,
+            (&AlphaNumeric(_), _) => false
+        }
+    }
+    #[inline(always)]
+    pure fn le(&self, other: &Identifier) -> bool {
+        ! (other < self)
+    }
+    #[inline(always)]
+    pure fn gt(&self, other: &Identifier) -> bool {
+        other < self
+    }
+    #[inline(always)]
+    pure fn ge(&self, other: &Identifier) -> bool {
+        ! (self < other)
+    }
+}
+
+impl ToStr for Identifier {
+    #[inline(always)]
+    pure fn to_str(&self) -> ~str {
+        match self {
+            &Numeric(n) => n.to_str(),
+            &AlphaNumeric(ref s) => s.to_str()
+        }
+    }
+}
+
+
+#[deriving_eq]
+pub struct Version {
+    major: uint,
+    minor: uint,
+    patch: uint,
+    pre: ~[Identifier],
+    build: ~[Identifier],
+}
+
+impl ToStr for Version {
+    #[inline(always)]
+    pure fn to_str(&self) -> ~str {
+        let s = fmt!("%u.%u.%u", self.major, self.minor, self.patch);
+        let s = if self.pre.is_empty() {
+            s
+        } else {
+            s + "-" + str::connect(self.pre.map(|i| i.to_str()), ".")
+        };
+        if self.build.is_empty() {
+            s
+        } else {
+            s + "+" + str::connect(self.build.map(|i| i.to_str()), ".")
+        }
+    }
+}
+
+impl cmp::Ord for Version {
+    #[inline(always)]
+    pure fn lt(&self, other: &Version) -> bool {
+
+        self.major < other.major ||
+
+            (self.major == other.major &&
+             self.minor < other.minor) ||
+
+            (self.major == other.major &&
+             self.minor == other.minor &&
+             self.patch < other.patch) ||
+
+            (self.major == other.major &&
+             self.minor == other.minor &&
+             self.patch == other.patch &&
+             // NB: semver spec says 0.0.0-pre < 0.0.0
+             // but the version of ord defined for vec
+             // says that [] < [pre], so we alter it
+             // here.
+             (match (self.pre.len(), other.pre.len()) {
+                 (0, 0) => false,
+                 (0, _) => false,
+                 (_, 0) => true,
+                 (_, _) => self.pre < other.pre
+             })) ||
+
+            (self.major == other.major &&
+             self.minor == other.minor &&
+             self.patch == other.patch &&
+             self.pre == other.pre &&
+             self.build < other.build)
+    }
+
+    #[inline(always)]
+    pure fn le(&self, other: &Version) -> bool {
+        ! (other < self)
+    }
+    #[inline(always)]
+    pure fn gt(&self, other: &Version) -> bool {
+        other < self
+    }
+    #[inline(always)]
+    pure fn ge(&self, other: &Version) -> bool {
+        ! (self < other)
+    }
+}
+
+condition! {
+    bad_parse: () -> ();
+}
+
+fn take_nonempty_prefix(rdr: io::Reader,
+                        ch: char,
+                        pred: fn(char) -> bool) -> (~str, char) {
+    let mut buf = ~"";
+    let mut ch = ch;
+    while pred(ch) {
+        str::push_char(&mut buf, ch);
+        ch = rdr.read_char();
+    }
+    if buf.is_empty() {
+        bad_parse::cond.raise(())
+    }
+    debug!("extracted nonempty prefix: %s", buf);
+    (buf, ch)
+}
+
+fn take_num(rdr: io::Reader, ch: char) -> (uint, char) {
+    let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit);
+    match uint::from_str(s) {
+        None => { bad_parse::cond.raise(()); (0, ch) },
+        Some(i) => (i, ch)
+    }
+}
+
+fn take_ident(rdr: io::Reader, ch: char) -> (Identifier, char) {
+    let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric);
+    if s.all(char::is_digit) {
+        match uint::from_str(s) {
+            None => { bad_parse::cond.raise(()); (Numeric(0), ch) },
+            Some(i) => (Numeric(i), ch)
+        }
+    } else {
+        (AlphaNumeric(s), ch)
+    }
+}
+
+fn expect(ch: char, c: char) {
+    if ch != c {
+        bad_parse::cond.raise(())
+    }
+}
+
+fn parse_reader(rdr: io::Reader) -> Version {
+
+    let (major, ch) = take_num(rdr, rdr.read_char());
+    expect(ch, '.');
+    let (minor, ch) = take_num(rdr, rdr.read_char());
+    expect(ch, '.');
+    let (patch, ch) = take_num(rdr, rdr.read_char());
+
+    let mut pre = ~[];
+    let mut build = ~[];
+
+    let mut ch = ch;
+    if ch == '-' {
+        loop {
+            let (id, c) = take_ident(rdr, rdr.read_char());
+            pre.push(id);
+            ch = c;
+            if ch != '.' { break; }
+        }
+    }
+
+    if ch == '+' {
+        loop {
+            let (id, c) = take_ident(rdr, rdr.read_char());
+            build.push(id);
+            ch = c;
+            if ch != '.' { break; }
+        }
+    }
+
+    Version {
+        major: major,
+        minor: minor,
+        patch: patch,
+        pre: pre,
+        build: build,
+    }
+}
+
+
+pub fn parse(s: &str) -> Option<Version> {
+    if ! str::is_ascii(s) {
+        return None;
+    }
+    let s = s.trim();
+    let mut bad = false;
+    do bad_parse::cond.trap(|_| { debug!("bad"); bad = true }).in {
+        do io::with_str_reader(s) |rdr| {
+            let v = parse_reader(rdr);
+            if bad || v.to_str() != s {
+                None
+            } else {
+                Some(v)
+            }
+        }
+    }
+}
+
+#[test]
+fn test_parse() {
+    assert parse("") == None;
+    assert parse("  ") == None;
+    assert parse("1") == None;
+    assert parse("1.2") == None;
+    assert parse("1.2") == None;
+    assert parse("1") == None;
+    assert parse("1.2") == None;
+    assert parse("1.2.3-") == None;
+    assert parse("a.b.c") == None;
+    assert parse("1.2.3 abc") == None;
+
+    assert parse("1.2.3") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[],
+        build: ~[],
+    });
+    assert parse("  1.2.3  ") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[],
+        build: ~[],
+    });
+    assert parse("1.2.3-alpha1") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[AlphaNumeric(~"alpha1")],
+        build: ~[]
+    });
+    assert parse("  1.2.3-alpha1  ") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[AlphaNumeric(~"alpha1")],
+        build: ~[]
+    });
+    assert parse("1.2.3+build5") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[],
+        build: ~[AlphaNumeric(~"build5")]
+    });
+    assert parse("  1.2.3+build5  ") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[],
+        build: ~[AlphaNumeric(~"build5")]
+    });
+    assert parse("1.2.3-alpha1+build5") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[AlphaNumeric(~"alpha1")],
+        build: ~[AlphaNumeric(~"build5")]
+    });
+    assert parse("  1.2.3-alpha1+build5  ") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[AlphaNumeric(~"alpha1")],
+        build: ~[AlphaNumeric(~"build5")]
+    });
+    assert parse("1.2.3-1.alpha1.9+build5.7.3aedf  ") == Some(Version {
+        major: 1u,
+        minor: 2u,
+        patch: 3u,
+        pre: ~[Numeric(1),AlphaNumeric(~"alpha1"),Numeric(9)],
+        build: ~[AlphaNumeric(~"build5"),
+                 Numeric(7),
+                 AlphaNumeric(~"3aedf")]
+    });
+
+}
+
+#[test]
+fn test_eq() {
+    assert parse("1.2.3")        == parse("1.2.3");
+    assert parse("1.2.3-alpha1") == parse("1.2.3-alpha1");
+}
+
+#[test]
+fn test_ne() {
+    assert parse("0.0.0")       != parse("0.0.1");
+    assert parse("0.0.0")       != parse("0.1.0");
+    assert parse("0.0.0")       != parse("1.0.0");
+    assert parse("1.2.3-alpha") != parse("1.2.3-beta");
+}
+
+#[test]
+fn test_lt() {
+    assert parse("0.0.0")        < parse("1.2.3-alpha2");
+    assert parse("1.0.0")        < parse("1.2.3-alpha2");
+    assert parse("1.2.0")        < parse("1.2.3-alpha2");
+    assert parse("1.2.3-alpha1") < parse("1.2.3");
+    assert parse("1.2.3-alpha1") < parse("1.2.3-alpha2");
+    assert !(parse("1.2.3-alpha2") < parse("1.2.3-alpha2"));
+}
+
+#[test]
+fn test_le() {
+    assert parse("0.0.0")        <= parse("1.2.3-alpha2");
+    assert parse("1.0.0")        <= parse("1.2.3-alpha2");
+    assert parse("1.2.0")        <= parse("1.2.3-alpha2");
+    assert parse("1.2.3-alpha1") <= parse("1.2.3-alpha2");
+    assert parse("1.2.3-alpha2") <= parse("1.2.3-alpha2");
+}
+
+#[test]
+fn test_gt() {
+    assert parse("1.2.3-alpha2") > parse("0.0.0");
+    assert parse("1.2.3-alpha2") > parse("1.0.0");
+    assert parse("1.2.3-alpha2") > parse("1.2.0");
+    assert parse("1.2.3-alpha2") > parse("1.2.3-alpha1");
+    assert parse("1.2.3")        > parse("1.2.3-alpha2");
+    assert !(parse("1.2.3-alpha2") > parse("1.2.3-alpha2"));
+}
+
+#[test]
+fn test_ge() {
+    assert parse("1.2.3-alpha2") >= parse("0.0.0");
+    assert parse("1.2.3-alpha2") >= parse("1.0.0");
+    assert parse("1.2.3-alpha2") >= parse("1.2.0");
+    assert parse("1.2.3-alpha2") >= parse("1.2.3-alpha1");
+    assert parse("1.2.3-alpha2") >= parse("1.2.3-alpha2");
+}
+
+#[test]
+fn test_spec_order() {
+
+    let vs = ["1.0.0-alpha",
+              "1.0.0-alpha.1",
+              "1.0.0-beta.2",
+              "1.0.0-beta.11",
+              "1.0.0-rc.1",
+              "1.0.0-rc.1+build.1",
+              "1.0.0",
+              "1.0.0+0.3.7",
+              "1.3.7+build",
+              "1.3.7+build.2.b8f12d7",
+              "1.3.7+build.11.e0f985a"];
+    let mut i = 1;
+    while i < vs.len() {
+        let a = parse(vs[i-1]).get();
+        let b = parse(vs[i]).get();
+        assert a < b;
+        i += 1;
+    }
+}
\ No newline at end of file
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
index 3c2baae6d57..b0756104fe5 100644
--- a/src/libstd/std.rc
+++ b/src/libstd/std.rc
@@ -99,6 +99,7 @@ pub mod rl;
 pub mod workcache;
 pub mod bigint;
 pub mod stats;
+pub mod semver;
 
 #[cfg(unicode)]
 mod unicode;