about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustpkg/api.rs35
-rw-r--r--src/librustpkg/conditions.rs2
-rw-r--r--src/librustpkg/crate_id.rs144
-rw-r--r--src/librustpkg/installed_packages.rs8
-rw-r--r--src/librustpkg/lib.rs34
-rw-r--r--src/librustpkg/package_source.rs74
-rw-r--r--src/librustpkg/path_util.rs56
-rw-r--r--src/librustpkg/tests.rs509
-rw-r--r--src/librustpkg/util.rs32
-rw-r--r--src/librustpkg/workspace.rs8
-rw-r--r--src/libsyntax/crateid.rs10
11 files changed, 413 insertions, 499 deletions
diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs
index 27dfc3cae41..13d5a117704 100644
--- a/src/librustpkg/api.rs
+++ b/src/librustpkg/api.rs
@@ -11,7 +11,6 @@
 use CtxMethods;
 use context::*;
 use crate::*;
-use crate_id::*;
 use package_source::*;
 use path_util::{platform_library_name, target_build_dir};
 use target::*;
@@ -26,6 +25,7 @@ use extra::arc::{Arc,RWArc};
 use extra::workcache;
 use extra::workcache::{Database, FreshnessMap};
 use extra::treemap::TreeMap;
+use syntax::crateid::CrateId;
 
 // A little sad -- duplicated from rustc::back::*
 #[cfg(target_arch = "arm")]
@@ -78,20 +78,19 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
     workcache::Context::new_with_freshness(db, cfg, Arc::new(freshness))
 }
 
-pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Option<~str>,
-                 lib: Path) {
-    build_lib_with_cfgs(sysroot, root, name, version, lib, ~[])
+pub fn build_lib(sysroot: Path, root: Path, name: ~str, lib: Path) {
+    build_lib_with_cfgs(sysroot, root, name, lib, ~[])
 }
 
-pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str,
-                           version: Option<~str>, lib: Path, cfgs: ~[~str]) {
+pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, lib: Path, cfgs: ~[~str]) {
     let cx = default_context(sysroot, root.clone());
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
     let pkg_src = PkgSrc {
         source_workspace: root.clone(),
         build_in_destination: false,
         destination_workspace: root.clone(),
         start_dir: root.join_many(["src", name.as_slice()]),
-        id: CrateId{ version: version, ..CrateId::new(name)},
+        id: crate_id,
         // n.b. This assumes the package only has one crate
         libs: ~[mk_crate(lib)],
         mains: ~[],
@@ -101,20 +100,19 @@ pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str,
     pkg_src.build(&cx, cfgs, []);
 }
 
-pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Option<~str>,
-                 main: Path) {
-    build_exe_with_cfgs(sysroot, root, name, version, main, ~[])
+pub fn build_exe(sysroot: Path, root: Path, name: ~str, main: Path) {
+    build_exe_with_cfgs(sysroot, root, name, main, ~[])
 }
 
-pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str,
-                           version: Option<~str>, main: Path, cfgs: ~[~str]) {
+pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, main: Path, cfgs: ~[~str]) {
     let cx = default_context(sysroot, root.clone());
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
     let pkg_src = PkgSrc {
         source_workspace: root.clone(),
         build_in_destination: false,
         destination_workspace: root.clone(),
         start_dir: root.join_many(["src", name.as_slice()]),
-        id: CrateId{ version: version, ..CrateId::new(name)},
+        id: crate_id,
         libs: ~[],
         // n.b. This assumes the package only has one crate
         mains: ~[mk_crate(main)],
@@ -128,11 +126,10 @@ pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str,
 pub fn install_pkg(cx: &BuildContext,
                    workspace: Path,
                    name: ~str,
-                   version: Option<~str>,
                    // For now, these inputs are assumed to be inputs to each of the crates
                    more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
-    let crateid = CrateId{ version: version, ..CrateId::new(name)};
-    cx.install(PkgSrc::new(workspace.clone(), workspace, false, crateid),
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
+    cx.install(PkgSrc::new(workspace.clone(), workspace, false, crate_id),
                &WhatToBuild{ build_type: Inferred,
                              inputs_to_discover: more_inputs,
                              sources: Everything });
@@ -156,10 +153,10 @@ pub fn build_library_in_workspace(exec: &mut workcache::Exec,
     let out_name = workspace_build_dir.join_many([package_name.to_str(),
                                                   platform_library_name(output)]);
     // make paths absolute
-    let crateid = CrateId::new(package_name);
+    let crateid: CrateId = from_str(package_name).expect("valid crate id");
     let absolute_paths = paths.map(|s| {
             let whatever = workspace.join_many([~"src",
-                                crateid.to_str(),
+                                crateid.short_name_with_version(),
                                 s.to_owned()]);
             whatever.as_str().unwrap().to_owned()
         });
@@ -189,7 +186,7 @@ pub fn my_workspace(context: &Context, package_name: &str) -> Path {
     use bad_pkg_id     = conditions::bad_pkg_id::cond;
 
     // (this assumes no particular version is requested)
-    let crateid = CrateId::new(package_name);
+    let crateid = from_str(package_name).expect("valid crate id");
     let workspaces = pkg_parent_workspaces(context, &crateid);
     if workspaces.is_empty() {
         bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs
index 6c38d63a518..d18161d7c4a 100644
--- a/src/librustpkg/conditions.rs
+++ b/src/librustpkg/conditions.rs
@@ -10,7 +10,7 @@
 
 // Useful conditions
 
-pub use crate_id::CrateId;
+pub use syntax::crateid::CrateId;
 pub use std::io::FileStat;
 pub use std::io::process::ProcessExit;
 pub use std::path::Path;
diff --git a/src/librustpkg/crate_id.rs b/src/librustpkg/crate_id.rs
deleted file mode 100644
index 4a87bcb70f5..00000000000
--- a/src/librustpkg/crate_id.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2013 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 std::hash::Streaming;
-use syntax::crateid;
-use extra::hex::ToHex;
-use rustc::util::sha2::{Digest, Sha256};
-
-/// Path-fragment identifier of a package such as
-/// 'github.com/graydon/test'; path must be a relative
-/// path with >=1 component.
-#[deriving(Clone)]
-pub struct CrateId {
-    /// This is a path, on the local filesystem, referring to where the
-    /// files for this package live. For example:
-    /// github.com/mozilla/quux-whatever (it's assumed that if we're
-    /// working with a package ID of this form, rustpkg has already cloned
-    /// the sources into a local directory in the RUST_PATH).
-    path: Path,
-    /// Short name. This is the path's filestem, but we store it
-    /// redundantly so as to not call get() everywhere (filestem() returns an
-    /// option)
-    /// The short name does not need to be a valid Rust identifier.
-    /// Users can write: `extern mod foo = "...";` to get around the issue
-    /// of package IDs whose short names aren't valid Rust identifiers.
-    short_name: ~str,
-    /// The requested package version.
-    version: Option<~str>
-}
-
-impl Eq for CrateId {
-    fn eq(&self, other: &CrateId) -> bool {
-        self.path == other.path && self.version == other.version
-    }
-}
-
-impl CrateId {
-    pub fn version_or_default<'a>(&'a self) -> &'a str {
-        match self.version {
-            Some(ref ver) => ver.as_slice(),
-            None => "0.0"
-        }
-    }
-
-    pub fn new(s: &str) -> CrateId {
-        use conditions::bad_pkg_id::cond;
-
-        let raw_crateid: Option<crateid::CrateId> = from_str(s);
-        if raw_crateid.is_none() {
-            return cond.raise((Path::new(s), ~"bad crateid"))
-        }
-        let raw_crateid = raw_crateid.unwrap();
-        let crateid::CrateId { path, name, version } = raw_crateid;
-        let path = Path::new(path);
-
-        CrateId {
-            path: path,
-            short_name: name,
-            version: version
-        }
-    }
-
-    pub fn to_crate_id_str(&self) -> ~str {
-        format!("{}\\#{}", self.path.as_str().unwrap(), self.version_or_default())
-    }
-
-    pub fn to_lib_name(&self) -> ~str {
-        format!("{}-{}-{}", self.short_name, self.hash(), self.version_or_default())
-    }
-
-    pub fn hash(&self) -> ~str {
-        let mut hasher = Sha256::new();
-        hasher.reset();
-        hasher.input_str(self.to_crate_id_str());
-        let hash = hasher.result_bytes().to_hex();
-        hash.slice_chars(0, 8).to_owned()
-    }
-
-    pub fn short_name_with_version(&self) -> ~str {
-        format!("{}-{}", self.short_name, self.version_or_default())
-    }
-
-    /// True if the ID has multiple components
-    pub fn is_complex(&self) -> bool {
-        self.short_name.as_bytes() != self.path.as_vec()
-    }
-
-    pub fn prefixes(&self) -> Prefixes {
-        prefixes(&self.path)
-    }
-
-    // This is the workcache function name for the *installed*
-    // binaries for this package (as opposed to the built ones,
-    // which are per-crate).
-    pub fn install_tag(&self) -> ~str {
-        format!("install({})", self.to_str())
-    }
-}
-
-pub fn prefixes(p: &Path) -> Prefixes {
-    Prefixes {
-        components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
-        remaining: ~[]
-    }
-}
-
-struct Prefixes {
-    priv components: ~[~str],
-    priv remaining: ~[~str]
-}
-
-impl Iterator<(Path, Path)> for Prefixes {
-    #[inline]
-    fn next(&mut self) -> Option<(Path, Path)> {
-        if self.components.len() <= 1 {
-            None
-        }
-        else {
-            let last = self.components.pop().unwrap();
-            self.remaining.unshift(last);
-            // converting to str and then back is a little unfortunate
-            Some((Path::new(self.components.connect("/")),
-                  Path::new(self.remaining.connect("/"))))
-        }
-    }
-}
-
-impl ToStr for CrateId {
-    fn to_str(&self) -> ~str {
-        // should probably use the filestem and not the whole path
-        format!("{}-{}", self.path.as_str().unwrap(), self.version_or_default())
-    }
-}
-
-pub fn write<W: Writer>(writer: &mut W, string: &str) {
-    writer.write(string.as_bytes());
-}
diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs
index 67ba5d2b8e8..c7900181a77 100644
--- a/src/librustpkg/installed_packages.rs
+++ b/src/librustpkg/installed_packages.rs
@@ -11,10 +11,10 @@
 // Listing installed packages
 
 use rustc::metadata::filesearch::rust_path;
-use path_util::*;
 use std::os;
 use std::io;
 use std::io::fs;
+use syntax::crateid::CrateId;
 
 pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
     let workspaces = rust_path();
@@ -28,7 +28,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
             match exec.filestem_str() {
                 None => (),
                 Some(exec_path) => {
-                    if !f(&CrateId::new(exec_path)) {
+                    let crate_id = from_str(exec_path).expect("valid crate id");
+                    if !f(&crate_id) {
                         return false;
                     }
                 }
@@ -50,7 +51,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
                     let rel_path = rel_p.join(basename);
                     rel_path.display().with_str(|s| {
                         debug!("Rel name: {}", s);
-                        f(&CrateId::new(s));
+                        let crate_id = from_str(s).expect("valid crate id");
+                        f(&crate_id);
                     });
                 }
                 None => ()
diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs
index 22871179a6e..e5e494e9b5f 100644
--- a/src/librustpkg/lib.rs
+++ b/src/librustpkg/lib.rs
@@ -33,6 +33,7 @@ use rustc::metadata::filesearch;
 use rustc::metadata::filesearch::rust_path;
 use rustc::util::sha2;
 use syntax::{ast, diagnostic};
+use syntax::crateid::CrateId;
 use messages::{error, warn, note};
 use parse_args::{ParseResult, parse_args};
 use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
@@ -46,7 +47,6 @@ use context::{BuildContext, Trans, Nothing, Pretty, Analysis,
               LLVMAssemble, LLVMCompileBitcode};
 use context::{Command, BuildCmd, CleanCmd, DoCmd, HelpCmd, InfoCmd, InstallCmd, ListCmd,
     PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd};
-use crate_id::CrateId;
 use package_source::PkgSrc;
 use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
 use target::{Main, Tests, MaybeCustom, Inferred, JustOne};
@@ -60,7 +60,6 @@ mod crate;
 pub mod exit_codes;
 mod installed_packages;
 mod messages;
-pub mod crate_id;
 pub mod package_source;
 mod parse_args;
 mod path_util;
@@ -103,7 +102,7 @@ impl<'a> PkgScript<'a> {
                  workspace: &Path,
                  id: &'a CrateId) -> PkgScript<'a> {
         // Get the executable name that was invoked
-        let binary = os::args()[0].to_owned();
+        let binary = os::args()[0];
         // Build the rustc session data structures to pass
         // to the compiler
         debug!("pkgscript parse: {}", sysroot.display());
@@ -244,7 +243,7 @@ impl CtxMethods for BuildContext {
             match cwd_to_workspace() {
                 None if dir_has_crate_file(&cwd) => {
                     // FIXME (#9639): This needs to handle non-utf8 paths
-                    let crateid = CrateId::new(cwd.filename_str().unwrap());
+                    let crateid = from_str(cwd.filename_str().unwrap()).expect("valid crate id");
                     let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, crateid);
                     self.build(&mut pkg_src, what);
                     match pkg_src {
@@ -269,7 +268,7 @@ impl CtxMethods for BuildContext {
         } else {
             // The package id is presumed to be the first command-line
             // argument
-            let crateid = CrateId::new(args[0].clone());
+            let crateid = from_str(args[0]).expect("valid crate id");
             let mut dest_ws = default_workspace();
             each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
                 debug!("found pkg {} in workspace {}, trying to build",
@@ -308,7 +307,7 @@ impl CtxMethods for BuildContext {
                 else {
                     // The package id is presumed to be the first command-line
                     // argument
-                    let crateid = CrateId::new(args[0].clone());
+                    let crateid = from_str(args[0]).expect("valid crate id");
                     self.clean(&cwd, &crateid); // tjc: should use workspace, not cwd
                 }
             }
@@ -341,7 +340,7 @@ impl CtxMethods for BuildContext {
                             // FIXME (#9639): This needs to handle non-utf8 paths
 
                             let inferred_crateid =
-                                CrateId::new(cwd.filename_str().unwrap());
+                                from_str(cwd.filename_str().unwrap()).expect("valid crate id");
                             self.install(PkgSrc::new(cwd, default_workspace(),
                                                      true, inferred_crateid),
                                          &WhatToBuild::new(MaybeCustom, Everything));
@@ -357,7 +356,7 @@ impl CtxMethods for BuildContext {
                 else {
                     // The package id is presumed to be the first command-line
                     // argument
-                    let crateid = CrateId::new(args[0]);
+                    let crateid = from_str(args[0]).expect("valid crate id");
                     let workspaces = pkg_parent_workspaces(&self.context, &crateid);
                     debug!("package ID = {}, found it in {:?} workspaces",
                            crateid.to_str(), workspaces.len());
@@ -383,7 +382,7 @@ impl CtxMethods for BuildContext {
             ListCmd => {
                 println!("Installed packages:");
                 installed_packages::list_installed_packages(|pkg_id| {
-                    pkg_id.path.display().with_str(|s| println!("{}", s));
+                    println!("{}", pkg_id.path);
                     true
                 });
             }
@@ -420,7 +419,7 @@ impl CtxMethods for BuildContext {
                     return usage::uninstall();
                 }
 
-                let crateid = CrateId::new(args[0]);
+                let crateid = from_str(args[0]).expect("valid crate id");
                 if !installed_packages::package_is_installed(&crateid) {
                     warn(format!("Package {} doesn't seem to be installed! \
                                   Doing nothing.", args[0]));
@@ -458,24 +457,24 @@ impl CtxMethods for BuildContext {
         let workspace = pkg_src.source_workspace.clone();
         let crateid = pkg_src.id.clone();
 
+        let path = crateid.path.as_slice();
         debug!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
                 crateid = {} pkgsrc start_dir = {}", workspace.display(),
-               in_rust_path(&workspace), is_git_dir(&workspace.join(&crateid.path)),
+               in_rust_path(&workspace), is_git_dir(&workspace.join(path)),
                crateid.to_str(), pkg_src.start_dir.display());
         debug!("build: what to build = {:?}", what_to_build);
 
         // If workspace isn't in the RUST_PATH, and it's a git repo,
         // then clone it into the first entry in RUST_PATH, and repeat
-        if !in_rust_path(&workspace) && is_git_dir(&workspace.join(&crateid.path)) {
+        if !in_rust_path(&workspace) && is_git_dir(&workspace.join(path)) {
             let mut out_dir = default_workspace().join("src");
-            out_dir.push(&crateid.path);
-            let git_result = source_control::safe_git_clone(&workspace.join(&crateid.path),
+            out_dir.push(path);
+            let git_result = source_control::safe_git_clone(&workspace.join(path),
                                                             &crateid.version,
                                                             &out_dir);
             match git_result {
                 CheckedOutSources => make_read_only(&out_dir),
-                // FIXME (#9639): This needs to handle non-utf8 paths
-                _ => cond.raise((crateid.path.as_str().unwrap().to_owned(), out_dir.clone()))
+                _ => cond.raise((path.to_owned(), out_dir.clone()))
             };
             let default_ws = default_workspace();
             debug!("Calling build recursively with {:?} and {:?}", default_ws.display(),
@@ -652,7 +651,8 @@ impl CtxMethods for BuildContext {
                target_exec.display(), target_lib,
                maybe_executable, maybe_library);
 
-        self.workcache_context.with_prep(id.install_tag(), |prep| {
+        let install_tag = format!("install({}-{})", id.path, id.version_or_default());
+        self.workcache_context.with_prep(install_tag, |prep| {
             for ee in maybe_executable.iter() {
                 // FIXME (#9639): This needs to handle non-utf8 paths
                 prep.declare_input("binary",
diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs
index 2bc1966bff0..5ac62c5284e 100644
--- a/src/librustpkg/package_source.rs
+++ b/src/librustpkg/package_source.rs
@@ -11,7 +11,6 @@
 extern mod extra;
 
 use target::*;
-use crate_id::CrateId;
 use std::io;
 use std::io::fs;
 use std::os;
@@ -27,7 +26,7 @@ use workcache_support;
 use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
 use extra::workcache;
 use extra::treemap::TreeMap;
-
+use syntax::crateid::CrateId;
 use rustc::driver::session;
 
 // An enumeration of the unpacked source of a package workspace.
@@ -68,12 +67,38 @@ impl ToStr for PkgSrc {
     }
 }
 condition! {
-    // #6009: should this be pub or not, when #8215 is fixed?
     build_err: (~str) -> ~str;
 }
 
-impl PkgSrc {
+fn prefixes(p: &Path) -> Prefixes {
+    Prefixes {
+        components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
+        remaining: ~[]
+    }
+}
+
+struct Prefixes {
+    priv components: ~[~str],
+    priv remaining: ~[~str]
+}
+
+impl Iterator<(Path, Path)> for Prefixes {
+    #[inline]
+    fn next(&mut self) -> Option<(Path, Path)> {
+        if self.components.len() <= 1 {
+            None
+        }
+        else {
+            let last = self.components.pop().unwrap();
+            self.remaining.unshift(last);
+            // converting to str and then back is a little unfortunate
+            Some((Path::new(self.components.connect("/")),
+                  Path::new(self.remaining.connect("/"))))
+        }
+    }
+}
 
+impl PkgSrc {
     pub fn new(mut source_workspace: Path,
                destination_workspace: Path,
                use_rust_path_hack: bool,
@@ -98,21 +123,22 @@ impl PkgSrc {
         } else {
             // We search for sources under both src/ and build/ , because build/ is where
             // automatically-checked-out sources go.
+            let path = Path::new(id.path.as_slice());
             let mut result = source_workspace.join("src");
-            result.push(&id.path.dir_path());
+            result.push(&path.dir_path());
             result.push(id.short_name_with_version());
             to_try.push(result);
             let mut result = source_workspace.join("src");
-            result.push(&id.path);
+            result.push(&path);
             to_try.push(result);
 
             let mut result = build_dir.join("src");
-            result.push(&id.path.dir_path());
+            result.push(&path.dir_path());
             result.push(id.short_name_with_version());
             to_try.push(result.clone());
             output_names.push(result);
             let mut other_result = build_dir.join("src");
-            other_result.push(&id.path);
+            other_result.push(&path);
             to_try.push(other_result.clone());
             output_names.push(other_result);
 
@@ -132,9 +158,10 @@ impl PkgSrc {
             None => {
                 // See if any of the prefixes of this package ID form a valid package ID
                 // That is, is this a package ID that points into the middle of a workspace?
-                for (prefix, suffix) in id.prefixes() {
-                    let crate_id = CrateId::new(prefix.as_str().unwrap());
-                    let path = build_dir.join(&crate_id.path);
+                for (prefix, suffix) in prefixes(&Path::new(id.path.as_slice())) {
+                    let crate_id: Option<CrateId> = from_str(prefix.as_str().unwrap());
+                    let crate_id = crate_id.expect("valid crate id");
+                    let path = build_dir.join(crate_id.path.as_slice());
                     debug!("in loop: checking if {} is a directory", path.display());
                     if path.is_dir() {
                         let ps = PkgSrc::new(source_workspace,
@@ -163,7 +190,7 @@ impl PkgSrc {
                             }
                         }
 
-                    };
+                    }
                 }
 
                 // Ok, no prefixes work, so try fetching from git
@@ -179,11 +206,12 @@ impl PkgSrc {
                     }
                     match ok_d {
                         Some(ref d) => {
-                            if d.is_ancestor_of(&id.path)
-                                || d.is_ancestor_of(&versionize(&id.path, &id.version)) {
+                            let path = Path::new(id.path.as_slice());
+                            if d.is_ancestor_of(&path)
+                                || d.is_ancestor_of(&versionize(id.path, &id.version)) {
                                 // Strip off the package ID
                                 source_workspace = d.clone();
-                                for _ in id.path.components() {
+                                for _ in path.components() {
                                     source_workspace.pop();
                                 }
                                 // Strip off the src/ part
@@ -226,8 +254,7 @@ impl PkgSrc {
                                         exist, and couldn't interpret it as a URL fragment"))
                                 }
                             }
-                        }
-                        else {
+                        } else {
                             cond.raise((id.clone(),
                                 ~"supplied path for package dir does not \
                                 exist, and couldn't interpret it as a URL fragment"))
@@ -268,24 +295,25 @@ impl PkgSrc {
         use conditions::git_checkout_failed::cond;
 
         let cwd = os::getcwd();
+        let path = Path::new(crateid.path.as_slice());
         debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}",
-                crateid.to_str(), crateid.path.display(),
+                crateid.to_str(), crateid.path,
                 cwd.display(),
-                crateid.path.exists());
+                path.exists());
 
-        match safe_git_clone(&crateid.path, &crateid.version, local) {
+        match safe_git_clone(&path, &crateid.version, local) {
             CheckedOutSources => {
                 make_read_only(local);
                 Some(local.clone())
             }
             DirToUse(clone_target) => {
-                if crateid.path.components().nth(1).is_none() {
+                if path.components().nth(1).is_none() {
                     // If a non-URL, don't bother trying to fetch
                     return None;
                 }
 
                 // FIXME (#9639): This needs to handle non-utf8 paths
-                let url = format!("https://{}", crateid.path.as_str().unwrap());
+                let url = format!("https://{}", path.as_str().unwrap());
                 debug!("Fetching package: git clone {} {} [version={}]",
                         url, clone_target.display(), crateid.version_or_default());
 
@@ -345,7 +373,7 @@ impl PkgSrc {
         use conditions::missing_pkg_files::cond;
 
         let prefix = self.start_dir.components().len();
-        debug!("Matching against {}", self.id.short_name);
+        debug!("Matching against {}", self.id.name);
         for pth in fs::walk_dir(&self.start_dir) {
             let maybe_known_crate_set = match pth.filename_str() {
                 Some(filename) if filter(filename) => match filename {
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs
index 1412b99d285..a0d49e7565f 100644
--- a/src/librustpkg/path_util.rs
+++ b/src/librustpkg/path_util.rs
@@ -12,9 +12,8 @@
 
 #[allow(dead_code)];
 
-pub use crate_id::CrateId;
 pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
-pub use version::{Version, split_version, split_version_general, try_parsing_version};
+pub use version::{Version, split_version_general};
 pub use rustc::metadata::filesearch::rust_path;
 
 use std::libc;
@@ -22,6 +21,9 @@ use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
 use std::os;
 use std::io;
 use std::io::fs;
+use extra::hex::ToHex;
+use syntax::crateid::CrateId;
+use rustc::util::sha2::{Digest, Sha256};
 use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
 use rustc::driver::driver::host_triple;
 use messages::*;
@@ -77,13 +79,13 @@ pub fn workspace_contains_crate_id_(crateid: &CrateId, workspace: &Path,
     let mut found = None;
     for p in fs::walk_dir(&src_dir) {
         if p.is_dir() {
-            if p == src_dir.join(&crateid.path) || {
+            if p == src_dir.join(crateid.path.as_slice()) || {
                 let pf = p.filename_str();
                 pf.iter().any(|&g| {
                     match split_version_general(g, '-') {
                         None => false,
                         Some((ref might_match, ref vers)) => {
-                            *might_match == crateid.short_name
+                            *might_match == crateid.name
                                 && (crateid.version == *vers || crateid.version == None)
                         }
                     }
@@ -178,33 +180,39 @@ pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option
 /// Does the actual searching stuff
 pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> {
     // This could break once we're handling multiple versions better -- I should add a test for it
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    match crate_id.path.filename_str() {
+    let path = Path::new(crate_id.path.as_slice());
+    match path.filename_str() {
         None => None,
         Some(_short_name) => library_in_workspace(crate_id, Install, workspace)
     }
 }
 
 /// `workspace` is used to figure out the directory to search.
-/// `short_name` is taken as the link name of the library.
+/// `name` is taken as the link name of the library.
 pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> {
     debug!("library_in_workspace: checking whether a library named {} exists",
-           crate_id.short_name);
+           crate_id.name);
 
     let dir_to_search = match where {
-        Build => target_build_dir(workspace).join(&crate_id.path),
+        Build => target_build_dir(workspace).join(crate_id.path.as_slice()),
         Install => target_lib_dir(workspace)
     };
 
     library_in(crate_id, &dir_to_search)
 }
 
-pub fn system_library(sysroot: &Path, crate_id: &str) -> Option<Path> {
-    library_in(&CrateId::new(crate_id), &sysroot.join(relative_target_lib_path(host_triple())))
+pub fn system_library(sysroot: &Path, crate_id: &CrateId) -> Option<Path> {
+    library_in(crate_id, &sysroot.join(relative_target_lib_path(host_triple())))
 }
 
 fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
-    let lib_name = crate_id.to_lib_name();
+    let mut hasher = Sha256::new();
+    hasher.reset();
+    hasher.input_str(crate_id.to_str());
+    let hash = hasher.result_bytes().to_hex();
+    let hash = hash.slice_chars(0, 8);
+
+    let lib_name = format!("{}-{}-{}", crate_id.name, hash, crate_id.version_or_default());
     let filenames = [
         format!("{}{}.{}", "lib", lib_name, "rlib"),
         format!("{}{}{}", os::consts::DLL_PREFIX, lib_name, os::consts::DLL_SUFFIX),
@@ -219,7 +227,7 @@ fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
         }
     }
     debug!("warning: library_in_workspace didn't find a library in {} for {}",
-           dir_to_search.display(), crate_id.short_name);
+           dir_to_search.display(), crate_id.to_str());
     return None;
 }
 
@@ -271,7 +279,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
     // Artifacts in the build directory live in a package-ID-specific subdirectory,
     // but installed ones don't.
     let result = match (where, what) {
-                (Build, _)      => target_build_dir(workspace).join(&crateid.path),
+                (Build, _)      => target_build_dir(workspace).join(crateid.path.as_slice()),
                 (Install, Lib)  => target_lib_dir(workspace),
                 (Install, _)    => target_bin_dir(workspace)
     };
@@ -287,7 +295,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
 /// Creates it if it doesn't exist.
 pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
     let mut result = target_build_dir(workspace);
-    result.push(&crateid.path);
+    result.push(crateid.path.as_slice());
     debug!("Creating build dir {} for package id {}", result.display(),
            crateid.to_str());
     fs::mkdir_recursive(&result, io::UserRWX);
@@ -297,24 +305,24 @@ pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
 /// Return the output file for a given directory name,
 /// given whether we're building a library and whether we're building tests
 pub fn mk_output_path(what: OutputType, where: Target,
-                      pkg_id: &CrateId, workspace: Path) -> Path {
-    let short_name_with_version = pkg_id.short_name_with_version();
+                      crate_id: &CrateId, workspace: Path) -> Path {
+    let short_name_with_version = crate_id.short_name_with_version();
     // Not local_path.dir_path()! For package foo/bar/blat/, we want
     // the executable blat-0.5 to live under blat/
     let dir = match where {
         // If we're installing, it just goes under <workspace>...
         Install => workspace,
         // and if we're just building, it goes in a package-specific subdir
-        Build => workspace.join(&pkg_id.path)
+        Build => workspace.join(crate_id.path.as_slice())
     };
-    debug!("[{:?}:{:?}] mk_output_path: short_name = {}, path = {}", what, where,
-           if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() },
+    debug!("[{:?}:{:?}] mk_output_path: name = {}, path = {}", what, where,
+           if what == Lib { short_name_with_version.clone() } else { crate_id.name.clone() },
            dir.display());
     let mut output_path = match what {
         // this code is duplicated from elsewhere; fix this
         Lib => dir.join(os::dll_filename(short_name_with_version)),
         // executable names *aren't* versioned
-        _ => dir.join(format!("{}{}{}", pkg_id.short_name,
+        _ => dir.join(format!("{}{}{}", crate_id.name,
                            match what {
                                Test => "test",
                                Bench => "bench",
@@ -361,11 +369,12 @@ fn dir_has_file(dir: &Path, file: &str) -> bool {
 
 pub fn find_dir_using_rust_path_hack(p: &CrateId) -> Option<Path> {
     let rp = rust_path();
+    let path = Path::new(p.path.as_slice());
     for dir in rp.iter() {
         // Require that the parent directory match the package ID
         // Note that this only matches if the package ID being searched for
         // has a name that's a single component
-        if dir.ends_with_path(&p.path) || dir.ends_with_path(&versionize(&p.path, &p.version)) {
+        if dir.ends_with_path(&path) || dir.ends_with_path(&versionize(p.path, &p.version)) {
             debug!("In find_dir_using_rust_path_hack: checking dir {}", dir.display());
             if dir_has_crate_file(dir) {
                 debug!("Did find id {} in dir {}", p.to_str(), dir.display());
@@ -387,7 +396,8 @@ pub fn user_set_rust_path() -> bool {
 }
 
 /// Append the version string onto the end of the path's filename
-pub fn versionize(p: &Path, v: &Version) -> Path {
+pub fn versionize(p: &str, v: &Version) -> Path {
+    let p = Path::new(p);
     let q = p.filename().expect("path is a directory");
     let mut q = q.to_owned();
     q.push('-' as u8);
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index 4bc9714fa2a..bf8ec1e738c 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -20,12 +20,12 @@ use extra::arc::Arc;
 use extra::arc::RWArc;
 use extra::tempfile::TempDir;
 use extra::workcache;
-use extra::workcache::{Database};
+use extra::workcache::Database;
 use extra::treemap::TreeMap;
 use extra::getopts::groups::getopts;
 use std::run::ProcessOutput;
 use installed_packages::list_installed_packages;
-use crate_id::CrateId;
+use syntax::crateid::CrateId;
 use path_util::{target_executable_in_workspace, target_test_in_workspace,
                target_bench_in_workspace, make_dir_rwx,
                library_in_workspace, installed_library_in_workspace,
@@ -58,18 +58,17 @@ fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
 }
 
 fn fake_pkg() -> CrateId {
-    let sn = ~"bogus";
     CrateId {
-        path: Path::new(sn.as_slice()),
-        short_name: sn,
+        path: ~"bogus",
+        name: ~"bogus",
         version: None
     }
 }
 
 fn git_repo_pkg() -> CrateId {
     CrateId {
-        path: Path::new("mockgithub.com/catamorphism/test-pkg"),
-        short_name: ~"test-pkg",
+        path: ~"mockgithub.com/catamorphism/test-pkg",
+        name: ~"test-pkg",
         version: None
     }
 }
@@ -273,14 +272,11 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         err_fd: None
     }).expect(format!("failed to exec `{}`", cmd));
     let output = prog.finish_with_output();
-    debug!("Output from command {} with args {:?} was {} \\{{}\\}[{:?}]",
+    debug!("Output from command {} with args {:?} was --- {} \\{{}\\} --- [{:?}]",
            cmd, args, str::from_utf8(output.output).unwrap(),
            str::from_utf8(output.error).unwrap(),
            output.status);
     if !output.status.success() {
-        debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} {} ---",
-              cmd, args, output.status,
-              str::from_utf8(output.output).unwrap(), str::from_utf8(output.error).unwrap());
         Fail(output)
     }
     else {
@@ -297,7 +293,7 @@ fn create_local_package(crateid: &CrateId) -> TempDir {
 
 fn create_local_package_in(crateid: &CrateId, pkgdir: &Path) -> Path {
 
-    let package_dir = pkgdir.join_many([~"src", crateid.to_str()]);
+    let package_dir = pkgdir.join_many([~"src", crateid.short_name_with_version()]);
 
     // Create main, lib, test, and bench files
     fs::mkdir_recursive(&package_dir, io::UserRWX);
@@ -325,11 +321,15 @@ fn create_local_package_with_dep(crateid: &CrateId, subord_crateid: &CrateId) ->
     let package_dir = create_local_package(crateid);
     create_local_package_in(subord_crateid, package_dir.path());
     // Write a main.rs file into crateid that references subord_crateid
-    writeFile(&package_dir.path().join_many([~"src", crateid.to_str(), ~"main.rs"]),
+    writeFile(&package_dir.path().join_many([~"src",
+                                             crateid.short_name_with_version(),
+                                             ~"main.rs"]),
               format!("extern mod {};\nfn main() \\{\\}",
-                   subord_crateid.short_name));
+                   subord_crateid.name));
     // Write a lib.rs file into subord_crateid that has something in it
-    writeFile(&package_dir.path().join_many([~"src", subord_crateid.to_str(), ~"lib.rs"]),
+    writeFile(&package_dir.path().join_many([~"src",
+                                             subord_crateid.short_name_with_version(),
+                                             ~"lib.rs"]),
               "pub fn f() {}");
     package_dir
 }
@@ -362,19 +362,21 @@ fn assert_executable_exists(repo: &Path, short_name: &str) {
 }
 
 fn executable_exists(repo: &Path, short_name: &str) -> bool {
+    let crate_id = from_str(short_name).expect("valid crate id");
     debug!("executable_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let exec = target_executable_in_workspace(&CrateId::new(short_name), repo);
+    let exec = target_executable_in_workspace(&crate_id, repo);
     exec.exists() && is_rwx(&exec)
 }
 
 fn test_executable_exists(repo: &Path, short_name: &str) -> bool {
+    let crate_id = from_str(short_name).expect("valid crate id");
     debug!("test_executable_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let exec = built_test_in_workspace(&CrateId::new(short_name), repo);
+    let exec = built_test_in_workspace(&crate_id, repo);
     exec.map_or(false, |exec| exec.exists() && is_rwx(&exec))
 }
 
 fn remove_executable_file(p: &CrateId, workspace: &Path) {
-    let exec = target_executable_in_workspace(&CrateId::new(p.short_name), workspace);
+    let exec = target_executable_in_workspace(p, workspace);
     if exec.exists() {
         fs::unlink(&exec);
     }
@@ -387,7 +389,8 @@ fn assert_built_executable_exists(repo: &Path, short_name: &str) {
 fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
     debug!("assert_built_executable_exists: repo = {}, short_name = {}",
             repo.display(), short_name);
-    let exec = built_executable_in_workspace(&CrateId::new(short_name), repo);
+    let crate_id = from_str(short_name).expect("valid crate id");
+    let exec = built_executable_in_workspace(&crate_id, repo);
     exec.is_some() && {
        let execname = exec.get_ref();
        execname.exists() && is_rwx(execname)
@@ -395,7 +398,7 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
 }
 
 fn remove_built_executable_file(p: &CrateId, workspace: &Path) {
-    let exec = built_executable_in_workspace(&CrateId::new(p.short_name), workspace);
+    let exec = built_executable_in_workspace(p, workspace);
     match exec {
         Some(r) => fs::unlink(&r),
         None    => ()
@@ -430,7 +433,8 @@ fn assert_built_library_exists(repo: &Path, short_name: &str) {
 
 fn built_library_exists(repo: &Path, short_name: &str) -> bool {
     debug!("assert_built_library_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let lib = built_library_in_workspace(&CrateId::new(short_name), repo);
+    let crate_id = from_str(short_name).expect("valid crate id");
+    let lib = built_library_in_workspace(&crate_id, repo);
     lib.is_some() && {
         let libname = lib.get_ref();
         libname.exists() && is_rwx(libname)
@@ -465,7 +469,8 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~
 fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
     debug!("lib_output_file_name: given {} and short name {}",
            workspace.display(), short_name);
-    library_in_workspace(&CrateId::new(short_name),
+    let crate_id = from_str(short_name).expect("valid crate id");
+    library_in_workspace(&crate_id,
                          Build,
                          workspace).expect("lib_output_file_name")
 }
@@ -473,7 +478,7 @@ fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
 #[cfg(target_os = "linux")]
 fn touch_source_file(workspace: &Path, crateid: &CrateId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let contents = fs::readdir(&pkg_src_dir);
     for p in contents.iter() {
         if p.extension_str() == Some("rs") {
@@ -493,7 +498,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) {
 #[cfg(not(target_os = "linux"))]
 fn touch_source_file(workspace: &Path, crateid: &CrateId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let contents = fs::readdir(&pkg_src_dir);
     for p in contents.iter() {
         if p.extension_str() == Some("rs") {
@@ -512,7 +517,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) {
 /// Add a comment at the end
 fn frob_source_file(workspace: &Path, crateid: &CrateId, filename: &str) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let mut maybe_p = None;
     let maybe_file = pkg_src_dir.join(filename);
     debug!("Trying to frob {} -- {}", pkg_src_dir.display(), filename);
@@ -615,7 +620,7 @@ fn test_install_invalid() {
 
 #[test]
 fn test_install_valid_external() {
-    let temp_pkg_id = CrateId::new("foo");
+    let temp_pkg_id: CrateId = from_str("foo").unwrap();
     let (tempdir, _) = mk_temp_workspace(&temp_pkg_id);
     let temp_workspace = tempdir.path();
     command_line_test([~"install", ~"foo"], temp_workspace);
@@ -653,7 +658,8 @@ fn test_install_invalid_external() {
 #[test]
 fn test_install_git() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let path = Path::new(temp_pkg_id.path.as_slice());
+    let repo = init_git_repo(&path);
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -670,10 +676,9 @@ fn test_install_git() {
     add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
 
     debug!("test_install_git: calling rustpkg install {} in {}",
-           temp_pkg_id.path.display(), repo.display());
+           temp_pkg_id.path, repo.display());
     // should have test, bench, lib, and main
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
+    command_line_test([~"install", temp_pkg_id.path.to_owned()], repo);
     let ws = repo.join(".rust");
     // Check that all files exist
     debug!("Checking for files in {}", ws.display());
@@ -702,8 +707,6 @@ fn test_install_git() {
 
 #[test]
 fn test_crate_ids_must_be_relative_path_like() {
-    use conditions::bad_pkg_id::cond;
-
     /*
     Okay:
     - One identifier, with no slashes
@@ -715,32 +718,16 @@ fn test_crate_ids_must_be_relative_path_like() {
 
     */
 
-    let whatever = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
+    assert_eq!(~"foo#0.0", foo.to_str());
+    let test_pkg: CrateId = from_str("github.com/catamorphism/test-pkg").unwrap();
+    assert_eq!(~"github.com/catamorphism/test-pkg#0.0", test_pkg.to_str());
 
-    assert_eq!(~"foo-0.0", whatever.to_str());
-    assert!("github.com/catamorphism/test-pkg-0.0" ==
-            CrateId::new("github.com/catamorphism/test-pkg").to_str());
-
-    cond.trap(|(p, e)| {
-        assert!(p.filename().is_none());
-        assert!("bad crateid" == e);
-        whatever.clone()
-    }).inside(|| {
-        let x = CrateId::new("");
-        assert_eq!(~"foo-0.0", x.to_str());
-    });
+    let x: Option<CrateId> = from_str("");
+    assert_eq!(x, None);
 
-    cond.trap(|(p, e)| {
-        let abs = os::make_absolute(&Path::new("foo/bar/quux"));
-        assert_eq!(p, abs);
-        assert!("bad crateid" == e);
-        whatever.clone()
-    }).inside(|| {
-        let zp = os::make_absolute(&Path::new("foo/bar/quux"));
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        let z = CrateId::new(zp.as_str().unwrap());
-        assert_eq!(~"foo-0.0", z.to_str());
-    })
+    let z: Option<CrateId> = from_str("/foo/bar/quux");
+    assert_eq!(z, None);
 }
 
 #[test]
@@ -765,7 +752,8 @@ fn test_package_request_version() {
 
     command_line_test([~"install", format!("{}\\#0.3", local_path)], repo);
 
-    assert!(match installed_library_in_workspace(&CrateId::new(format!("{}\\#0.3", local_path)),
+    let crate_id = from_str(format!("{}\\#0.3", local_path)).unwrap();
+    assert!(match installed_library_in_workspace(&crate_id,
                                                  &repo.join(".rust")) {
         Some(p) => {
             debug!("installed: {}", p.display());
@@ -774,7 +762,7 @@ fn test_package_request_version() {
         }
         None    => false
     });
-    let temp_pkg_id = CrateId::new("mockgithub.com/catamorphism/test_pkg_version#0.3");
+    let temp_pkg_id = from_str("mockgithub.com/catamorphism/test_pkg_version#0.3").unwrap();
     assert!(target_executable_in_workspace(&temp_pkg_id, &repo.join(".rust"))
             == repo.join_many([".rust", "bin", "test_pkg_version"]));
 
@@ -812,12 +800,14 @@ fn rustpkg_library_target() {
     add_git_tag(&package_dir, ~"0.0");
 
     command_line_test([~"install", ~"foo"], foo_repo);
-    assert_lib_exists(&foo_repo.join(".rust"), &CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    assert_lib_exists(&foo_repo.join(".rust"), &crate_id);
 }
 
 #[test]
 fn rustpkg_local_pkg() {
-    let dir = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let dir = create_local_package(&crate_id);
     command_line_test([~"install", ~"foo"], dir.path());
     assert_executable_exists(dir.path(), "foo");
 }
@@ -825,7 +815,8 @@ fn rustpkg_local_pkg() {
 #[test]
 #[ignore(reason="busted")]
 fn package_script_with_default_build() {
-    let dir = create_local_package(&CrateId::new("fancy-lib"));
+    let crate_id: CrateId = from_str("fancy-lib").unwrap();
+    let dir = create_local_package(&crate_id);
     let dir = dir.path();
     debug!("dir = {}", dir.display());
     let mut source = test_sysroot().dir_path();
@@ -835,7 +826,7 @@ fn package_script_with_default_build() {
     debug!("package_script_with_default_build: {}", source.display());
     fs::copy(&source, &dir.join_many(["src", "fancy-lib-0.0", "pkg.rs"]));
     command_line_test([~"install", ~"fancy-lib"], dir);
-    assert_lib_exists(dir, &CrateId::new("fancy-lib"));
+    assert_lib_exists(dir, &crate_id);
     assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists());
     let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]);
     debug!("generated path = {}", generated_path.display());
@@ -866,7 +857,8 @@ fn rustpkg_install_no_arg() {
               "fn main() { let _x = (); }");
     debug!("install_no_arg: dir = {}", package_dir.display());
     command_line_test([~"install"], &package_dir);
-    assert_lib_exists(&tmp, &CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    assert_lib_exists(&tmp, &crate_id);
 }
 
 #[test]
@@ -882,14 +874,16 @@ fn rustpkg_clean_no_arg() {
     command_line_test([~"build"], &package_dir);
     assert_built_executable_exists(&tmp, "foo");
     command_line_test([~"clean"], &package_dir);
-    let res = built_executable_in_workspace(&CrateId::new("foo"), &tmp);
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let res = built_executable_in_workspace(&crate_id, &tmp);
     assert!(!res.as_ref().map_or(false, |m| m.exists()));
 }
 
 #[test]
 fn rust_path_test() {
     let dir_for_path = TempDir::new("more_rust").expect("rust_path_test failed");
-    let dir = mk_workspace(dir_for_path.path(), &CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let dir = mk_workspace(dir_for_path.path(), &crate_id);
     debug!("dir = {}", dir.display());
     writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }");
 
@@ -940,11 +934,11 @@ fn rust_path_parse() {
 fn test_list() {
     let dir = TempDir::new("test_list").expect("test_list failed");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
     create_local_package_in(&foo, dir);
-    let bar = CrateId::new("bar");
+    let bar: CrateId = from_str("bar").unwrap();
     create_local_package_in(&bar, dir);
-    let quux = CrateId::new("quux");
+    let quux: CrateId = from_str("quux").unwrap();
     create_local_package_in(&quux, dir);
 
 // list doesn't output very much right now...
@@ -970,9 +964,9 @@ fn test_list() {
 fn install_remove() {
     let dir = TempDir::new("install_remove").expect("install_remove");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
-    let bar = CrateId::new("bar");
-    let quux = CrateId::new("quux");
+    let foo: CrateId = from_str("foo").unwrap();
+    let bar: CrateId = from_str("bar").unwrap();
+    let quux: CrateId = from_str("quux").unwrap();
     create_local_package_in(&foo, dir);
     create_local_package_in(&bar, dir);
     create_local_package_in(&quux, dir);
@@ -999,7 +993,7 @@ fn install_check_duplicates() {
     // check invariant that there are no dups in the pkg database
     let dir = TempDir::new("install_remove").expect("install_remove");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
     create_local_package_in(&foo, dir);
 
     command_line_test([~"install", ~"foo"], dir);
@@ -1007,7 +1001,7 @@ fn install_check_duplicates() {
     let mut contents = ~[];
     let check_dups = |p: &CrateId| {
         if contents.contains(p) {
-            fail!("package {} appears in `list` output more than once", p.path.display());
+            fail!("package {} appears in `list` output more than once", p.path);
         }
         else {
             contents.push((*p).clone());
@@ -1019,7 +1013,7 @@ fn install_check_duplicates() {
 
 #[test]
 fn no_rebuilding() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1040,7 +1034,7 @@ fn no_rebuilding() {
 #[test]
 #[ignore]
 fn no_recopying() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     command_line_test([~"install", ~"foo"], workspace);
@@ -1059,8 +1053,8 @@ fn no_recopying() {
 
 #[test]
 fn no_rebuilding_dep() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1078,8 +1072,8 @@ fn no_rebuilding_dep() {
 
 #[test]
 fn do_rebuild_dep_dates_change() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1098,8 +1092,8 @@ fn do_rebuild_dep_dates_change() {
 
 #[test]
 fn do_rebuild_dep_only_contents_change() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1119,8 +1113,10 @@ fn do_rebuild_dep_only_contents_change() {
 
 #[test]
 fn test_versions() {
-    let workspace = create_local_package(&CrateId::new("foo#0.1"));
-    let _other_workspace = create_local_package(&CrateId::new("foo#0.2"));
+    let foo_01: CrateId = from_str("foo#0.1").unwrap();
+    let foo_02: CrateId = from_str("foo#0.2").unwrap();
+    let workspace = create_local_package(&foo_01);
+    let _other_workspace = create_local_package(&foo_02);
     command_line_test([~"install", ~"foo#0.1"], workspace.path());
     let output = command_line_test_output([~"list"]);
     // make sure output includes versions
@@ -1130,7 +1126,8 @@ fn test_versions() {
 #[test]
 #[ignore(reason = "do not yet implemented")]
 fn test_build_hooks() {
-    let workspace = create_local_package_with_custom_build_hook(&CrateId::new("foo"),
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package_with_custom_build_hook(&crate_id,
                                                                 "frob");
     command_line_test([~"do", ~"foo", ~"frob"], workspace.path());
 }
@@ -1140,14 +1137,16 @@ fn test_build_hooks() {
 #[ignore(reason = "info not yet implemented")]
 fn test_info() {
     let expected_info = ~"package foo"; // fill in
-    let workspace = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package(&crate_id);
     let output = command_line_test([~"info", ~"foo"], workspace.path());
     assert_eq!(str::from_utf8_owned(output.output).unwrap(), expected_info);
 }
 
 #[test]
 fn test_uninstall() {
-    let workspace = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package(&crate_id);
     command_line_test([~"uninstall", ~"foo"], workspace.path());
     let output = command_line_test([~"list"], workspace.path());
     assert!(!str::from_utf8(output.output).unwrap().contains("foo"));
@@ -1156,7 +1155,7 @@ fn test_uninstall() {
 #[test]
 fn test_non_numeric_tag() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice()));
     let repo = repo.path();
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
     writeFile(&repo_subdir.join("foo"), "foo");
@@ -1168,9 +1167,7 @@ fn test_non_numeric_tag() {
     writeFile(&repo_subdir.join("not_on_testbranch_only"), "bye bye");
     add_all_and_commit(&repo_subdir);
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", format!("{}\\#testbranch",
-                                           temp_pkg_id.path.as_str().unwrap())], repo);
+    command_line_test([~"install", format!("{}\\#testbranch", temp_pkg_id.path)], repo);
     let file1 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "testbranch_only"]);
     let file2 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]);
     assert!(file1.exists());
@@ -1283,7 +1280,7 @@ fn test_extern_mod_simpler() {
 
 #[test]
 fn test_import_rustpkg() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]),
@@ -1296,7 +1293,7 @@ fn test_import_rustpkg() {
 
 #[test]
 fn test_macro_pkg_script() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]),
@@ -1313,7 +1310,8 @@ fn multiple_workspaces() {
 // Copy the exact same package into directory B and install it
 // Set the RUST_PATH to A:B
 // Make a third package that uses foo, make sure we can build/install it
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let bar_p_id: CrateId = from_str("bar").unwrap();
     let (a_loc, _pkg_dir) = mk_temp_workspace(&p_id);
     let (b_loc, _pkg_dir) = mk_temp_workspace(&p_id);
     let (a_loc, b_loc) = (a_loc.path(), b_loc.path());
@@ -1324,7 +1322,7 @@ fn multiple_workspaces() {
     // FIXME (#9639): This needs to handle non-utf8 paths
     let env = Some(~[(~"RUST_PATH", format!("{}:{}", a_loc.as_str().unwrap(),
                                             b_loc.as_str().unwrap()))]);
-    let c_loc = create_local_package_with_dep(&CrateId::new("bar"), &CrateId::new("foo"));
+    let c_loc = create_local_package_with_dep(&bar_p_id, &p_id);
     command_line_test_with_env([~"install", ~"bar"], c_loc.path(), env);
 }
 
@@ -1337,26 +1335,28 @@ fn rust_path_hack_test(hack_flag: bool) {
       make sure built files for foo are in B
       make sure nothing gets built into A or A/../build[lib,bin]
 */
-   let p_id = CrateId::new("foo");
-   let workspace = create_local_package(&p_id);
-   let workspace = workspace.path();
-   let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   let foo_path = workspace.join_many(["src", "foo-0.0"]);
-   let rust_path = Some(~[(~"RUST_PATH",
-       format!("{}:{}",
-               dest_workspace.as_str().unwrap(),
-               foo_path.as_str().unwrap()))]);
-   command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
-                               ~[~"foo"], dest_workspace, rust_path);
-   assert_lib_exists(dest_workspace, &CrateId::new("foo"));
-   assert_executable_exists(dest_workspace, "foo");
-   assert_built_library_exists(dest_workspace, "foo");
-   assert_built_executable_exists(dest_workspace, "foo");
-   assert!(!lib_exists(workspace, &CrateId::new("foo")));
-   assert!(!executable_exists(workspace, "foo"));
-   assert!(!built_library_exists(workspace, "foo"));
-   assert!(!built_executable_exists(workspace, "foo"));
+    let p_id: CrateId = from_str("foo").unwrap();
+    let bar_p_id: CrateId = from_str("bar").unwrap();
+    let workspace = create_local_package(&p_id);
+    let workspace = workspace.path();
+    let dest_workspace = mk_empty_workspace(&bar_p_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    let foo_path = workspace.join_many(["src", "foo-0.0"]);
+    let rust_path = Some(~[(~"RUST_PATH",
+        format!("{}:{}",
+                dest_workspace.as_str().unwrap(),
+                foo_path.as_str().unwrap()))]);
+    command_line_test_with_env(~[~"install"] +
+                               if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } + ~[~"foo"],
+                               dest_workspace, rust_path);
+    assert_lib_exists(dest_workspace, &p_id);
+    assert_executable_exists(dest_workspace, "foo");
+    assert_built_library_exists(dest_workspace, "foo");
+    assert_built_executable_exists(dest_workspace, "foo");
+    assert!(!lib_exists(workspace, &p_id));
+    assert!(!executable_exists(workspace, "foo"));
+    assert!(!built_library_exists(workspace, "foo"));
+    assert!(!built_executable_exists(workspace, "foo"));
 }
 
 // Notice that this is the only test case where the --rust-path-hack
@@ -1382,88 +1382,95 @@ fn test_rust_path_can_contain_package_dirs_without_flag() {
 
 #[test]
 fn rust_path_hack_cwd() {
-   // Same as rust_path_hack_test, but the CWD is the dir to build out of
-   let cwd = TempDir::new("foo").expect("rust_path_hack_cwd");
-   let cwd = cwd.path().join("foo");
-   fs::mkdir_recursive(&cwd, io::UserRWX);
-   writeFile(&cwd.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_lib_exists(dest_workspace, &CrateId::new("foo"));
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!lib_exists(&cwd, &CrateId::new("foo")));
-   assert!(!built_library_exists(&cwd, "foo"));
+    // Same as rust_path_hack_test, but the CWD is the dir to build out of
+    let cwd = TempDir::new("foo").expect("rust_path_hack_cwd");
+    let cwd = cwd.path().join("foo");
+    fs::mkdir_recursive(&cwd, io::UserRWX);
+    writeFile(&cwd.join("lib.rs"), "pub fn f() { }");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!lib_exists(&cwd, &foo_id));
+    assert!(!built_library_exists(&cwd, "foo"));
 }
 
 #[test]
 fn rust_path_hack_multi_path() {
-   // Same as rust_path_hack_test, but with a more complex package ID
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd");
-   let subdir = cwd.path().join_many(["foo", "bar", "quux"]);
-   fs::mkdir_recursive(&subdir, io::UserRWX);
-   writeFile(&subdir.join("lib.rs"), "pub fn f() { }");
-   let name = ~"foo/bar/quux";
-
-   let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
-   debug!("Checking that {} exists in {}", name, dest_workspace.display());
-   assert_lib_exists(dest_workspace, &CrateId::new("foo/bar/quux"));
-   assert_built_library_exists(dest_workspace, name);
-   assert!(!lib_exists(&subdir, &CrateId::new("foo/bar/quux")));
-   assert!(!built_library_exists(&subdir, name));
+    // Same as rust_path_hack_test, but with a more complex package ID
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd");
+    let subdir = cwd.path().join_many(["foo", "bar", "quux"]);
+    fs::mkdir_recursive(&subdir, io::UserRWX);
+    writeFile(&subdir.join("lib.rs"), "pub fn f() { }");
+    let name = ~"foo/bar/quux";
+    let foo_id: CrateId = from_str("foo/bar/quux").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
+    debug!("Checking that {} exists in {}", name, dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, name);
+    assert!(!lib_exists(&subdir, &foo_id));
+    assert!(!built_library_exists(&subdir, name));
 }
 
 #[test]
 fn rust_path_hack_install_no_arg() {
-   // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg");
-   let cwd = cwd.path();
-   let source_dir = cwd.join("foo");
-   assert!(make_dir_rwx(&source_dir));
-   writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_lib_exists(dest_workspace, &CrateId::new("foo"));
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!lib_exists(&source_dir, &CrateId::new("foo")));
-   assert!(!built_library_exists(cwd, "foo"));
+    // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg");
+    let cwd = cwd.path();
+    let source_dir = cwd.join("foo");
+    assert!(make_dir_rwx(&source_dir));
+    writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
+
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!lib_exists(&source_dir, &foo_id));
+    assert!(!built_library_exists(cwd, "foo"));
 }
 
 #[test]
 fn rust_path_hack_build_no_arg() {
-   // Same as rust_path_hack_install_no_arg, but building instead of installing
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg");
-   let source_dir = cwd.path().join("foo");
-   assert!(make_dir_rwx(&source_dir));
-   writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!built_library_exists(&source_dir, "foo"));
+    // Same as rust_path_hack_install_no_arg, but building instead of installing
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg");
+    let source_dir = cwd.path().join("foo");
+    assert!(make_dir_rwx(&source_dir));
+    writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
+
+    let bar_id: CrateId = from_str("bar").unwrap();
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!built_library_exists(&source_dir, "foo"));
 }
 
 #[test]
 fn rust_path_hack_build_with_dependency() {
-    let foo_id = CrateId::new("foo");
-    let dep_id = CrateId::new("dep");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("dep").unwrap();
     // Tests that when --rust-path-hack is in effect, dependencies get built
     // into the destination workspace and not the source directory
     let work_dir = create_local_package(&foo_id);
@@ -1488,7 +1495,8 @@ fn rust_path_hack_build_with_dependency() {
 fn rust_path_install_target() {
     let dir_for_path = TempDir::new(
         "source_workspace").expect("rust_path_install_target failed");
-    let mut dir = mk_workspace(dir_for_path.path(), &CrateId::new("foo"));
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let mut dir = mk_workspace(dir_for_path.path(), &foo_id);
     debug!("dir = {}", dir.display());
     writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }");
     let dir_to_install_to = TempDir::new(
@@ -1511,7 +1519,7 @@ fn rust_path_install_target() {
 
 #[test]
 fn sysroot_flag() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     // no-op sysroot setting; I'm not sure how else to test this
@@ -1527,7 +1535,7 @@ fn sysroot_flag() {
 
 #[test]
 fn compile_flag_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1544,7 +1552,7 @@ fn compile_flag_build() {
 #[test]
 fn compile_flag_fail() {
     // --no-link shouldn't be accepted for install
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1560,7 +1568,7 @@ fn compile_flag_fail() {
 
 #[test]
 fn notrans_flag_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let flags_to_test = [~"--no-trans", ~"--parse-only",
@@ -1585,7 +1593,7 @@ fn notrans_flag_build() {
 #[test]
 fn notrans_flag_fail() {
     // --no-trans shouldn't be accepted for install
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let flags_to_test = [~"--no-trans", ~"--parse-only",
@@ -1600,13 +1608,13 @@ fn notrans_flag_fail() {
                           workspace, None, BAD_FLAG_CODE);
         assert!(!built_executable_exists(workspace, "foo"));
         assert!(!object_file_exists(workspace, "foo"));
-        assert!(!lib_exists(workspace, &CrateId::new("foo")));
+        assert!(!lib_exists(workspace, &p_id));
     }
 }
 
 #[test]
 fn dash_S() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1623,7 +1631,7 @@ fn dash_S() {
 
 #[test]
 fn dash_S_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1640,7 +1648,7 @@ fn dash_S_fail() {
 
 #[test]
 fn test_cfg_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     // If the cfg flag gets messed up, this won't compile
@@ -1659,7 +1667,7 @@ fn test_cfg_build() {
 
 #[test]
 fn test_cfg_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "main.rs"]),
@@ -1678,7 +1686,7 @@ fn test_cfg_fail() {
 
 #[test]
 fn test_emit_llvm_S_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1696,7 +1704,7 @@ fn test_emit_llvm_S_build() {
 
 #[test]
 fn test_emit_llvm_S_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1716,7 +1724,7 @@ fn test_emit_llvm_S_fail() {
 
 #[test]
 fn test_emit_llvm_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1735,7 +1743,7 @@ fn test_emit_llvm_build() {
 
 #[test]
 fn test_emit_llvm_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1756,7 +1764,7 @@ fn test_emit_llvm_fail() {
 
 #[test]
 fn test_linker_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let matches = getopts([], optgroups());
@@ -1801,7 +1809,7 @@ fn test_build_install_flags_fail() {
 
 #[test]
 fn test_optimized_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1842,8 +1850,8 @@ fn crateid_pointing_to_subdir() {
     fs::mkdir_recursive(&testpkg_dir, io::UserRWX);
 
     writeFile(&testpkg_dir.join("main.rs"),
-              "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n
-               extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar\";\n
+              "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo#foo:0.0\";\n
+               extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar#bar:0.0\";\n
                use foo::f; use bar::g; \n
                fn main() { f(); g(); }");
 
@@ -1853,9 +1861,9 @@ fn crateid_pointing_to_subdir() {
 
 #[test]
 fn test_recursive_deps() {
-    let a_id = CrateId::new("a");
-    let b_id = CrateId::new("b");
-    let c_id = CrateId::new("c");
+    let a_id: CrateId = from_str("a").unwrap();
+    let b_id: CrateId = from_str("b").unwrap();
+    let c_id: CrateId = from_str("c").unwrap();
     let b_workspace = create_local_package_with_dep(&b_id, &c_id);
     let b_workspace = b_workspace.path();
     writeFile(&b_workspace.join_many(["src", "c-0.0", "lib.rs"]),
@@ -1872,17 +1880,18 @@ fn test_recursive_deps() {
     command_line_test_with_env([~"install", ~"a"],
                                a_workspace,
                                environment);
-    assert_lib_exists(a_workspace, &CrateId::new("a"));
-    assert_lib_exists(b_workspace, &CrateId::new("b"));
-    assert_lib_exists(b_workspace, &CrateId::new("c"));
+    assert_lib_exists(a_workspace, &a_id);
+    assert_lib_exists(b_workspace, &b_id);
+    assert_lib_exists(b_workspace, &c_id);
 }
 
 #[test]
 fn test_install_to_rust_path() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let second_workspace = create_local_package(&p_id);
     let second_workspace = second_workspace.path();
-    let first_workspace = mk_empty_workspace(&CrateId::new("p"), "dest");
+    let none_id: CrateId = from_str("p").unwrap();
+    let first_workspace = mk_empty_workspace(&none_id, "dest");
     let first_workspace = first_workspace.path();
     // FIXME (#9639): This needs to handle non-utf8 paths
     let rust_path = Some(~[(~"RUST_PATH",
@@ -1903,7 +1912,7 @@ fn test_install_to_rust_path() {
 
 #[test]
 fn test_target_specific_build_dir() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1919,7 +1928,7 @@ fn test_target_specific_build_dir() {
 
 #[test]
 fn test_target_specific_install_dir() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1929,7 +1938,7 @@ fn test_target_specific_install_dir() {
                        ~"foo"],
                       workspace);
     assert!(workspace.join_many([~"lib", host_triple()]).is_dir());
-    assert_lib_exists(workspace, &CrateId::new("foo"));
+    assert_lib_exists(workspace, &p_id);
     assert!(fs::readdir(&workspace.join("lib")).len() == 1);
     assert!(workspace.join("bin").is_dir());
     assert_executable_exists(workspace, "foo");
@@ -1938,7 +1947,7 @@ fn test_target_specific_install_dir() {
 #[test]
 #[ignore(reason = "See #7240")]
 fn test_dependencies_terminate() {
-    let b_id = CrateId::new("b");
+    let b_id: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b_id);
     let workspace = workspace.path();
     let b_dir = workspace.join_many(["src", "b-0.0"]);
@@ -1951,42 +1960,42 @@ fn test_dependencies_terminate() {
 
 #[test]
 fn install_after_build() {
-    let b_id = CrateId::new("b");
+    let b_id: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"b"], workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b_id.short_name);
+    assert_executable_exists(workspace, b_id.name);
     assert_lib_exists(workspace, &b_id);
 }
 
 #[test]
 fn reinstall() {
-    let b = CrateId::new("b");
+    let b: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b);
     let workspace = workspace.path();
     // 1. Install, then remove executable file, then install again,
     // and make sure executable was re-installed
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
+    assert_executable_exists(workspace, b.name);
     assert_lib_exists(workspace, &b);
     remove_executable_file(&b, workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
+    assert_executable_exists(workspace, b.name);
     // 2. Build, then remove build executable file, then build again,
     // and make sure executable was re-built.
     command_line_test([~"build", ~"b"], workspace);
     remove_built_executable_file(&b, workspace);
     command_line_test([~"build", ~"b"], workspace);
-    assert_built_executable_exists(workspace, b.short_name);
+    assert_built_executable_exists(workspace, b.name);
     // 3. Install, then remove both executable and built executable,
     // then install again, make sure both were recreated
     command_line_test([~"install", ~"b"], workspace);
     remove_executable_file(&b, workspace);
     remove_built_executable_file(&b, workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
-    assert_built_executable_exists(workspace, b.short_name);
+    assert_executable_exists(workspace, b.name);
+    assert_built_executable_exists(workspace, b.name);
 }
 
 #[test]
@@ -2001,11 +2010,11 @@ fn correct_package_name_with_rust_path_hack() {
     */
 
     // Set RUST_PATH to something containing only the sources for foo
-    let foo_id = CrateId::new("foo");
-    let bar_id = CrateId::new("bar");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
-    let dest_workspace = mk_empty_workspace(&CrateId::new("bar"), "dest_workspace");
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
     let dest_workspace = dest_workspace.path();
 
     writeFile(&dest_workspace.join_many(["src", "bar-0.0", "main.rs"]),
@@ -2031,7 +2040,7 @@ fn correct_package_name_with_rust_path_hack() {
 
 #[test]
 fn test_rustpkg_test_creates_exec() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2042,7 +2051,8 @@ fn test_rustpkg_test_creates_exec() {
 
 #[test]
 fn test_rustpkg_test_output() {
-    let workspace = create_local_package_with_test(&CrateId::new("foo"));
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package_with_test(&foo_id);
     let output = command_line_test([~"test", ~"foo"], workspace.path());
     let output_str = str::from_utf8(output.output).unwrap();
     // The first two assertions are separate because test output may
@@ -2054,7 +2064,7 @@ fn test_rustpkg_test_output() {
 
 #[test]
 fn test_rustpkg_test_failure_exit_status() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2068,7 +2078,7 @@ fn test_rustpkg_test_failure_exit_status() {
 
 #[test]
 fn test_rustpkg_test_cfg() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2081,7 +2091,7 @@ fn test_rustpkg_test_cfg() {
 
 #[test]
 fn test_rebuild_when_needed() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]);
@@ -2102,7 +2112,7 @@ fn test_rebuild_when_needed() {
 #[test]
 #[ignore] // FIXME (#10257): This doesn't work as is since a read only file can't execute
 fn test_no_rebuilding() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]);
@@ -2124,8 +2134,9 @@ fn test_no_rebuilding() {
 fn test_installed_read_only() {
     // Install sources from a "remote" (actually a local github repo)
     // Check that afterward, sources are read-only and installed under build/
-    let mut temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let temp_pkg_id = git_repo_pkg();
+    let path = Path::new(temp_pkg_id.path.as_slice());
+    let repo = init_git_repo(&path);
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -2137,10 +2148,9 @@ fn test_installed_read_only() {
               "pub fn f() { let _x = (); }");
     add_git_tag(&repo_subdir, ~"0.0"); // this has the effect of committing the files
     // update crateid to what will be auto-detected
-    temp_pkg_id.version = Some(~"0.0");
 
     // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
+    command_line_test([~"install", temp_pkg_id.to_str()], repo);
 
     let ws = repo.join(".rust");
     // Check that all files exist
@@ -2156,8 +2166,10 @@ fn test_installed_read_only() {
     assert!(is_rwx(&built_lib));
 
     // Make sure sources are (a) under "build" and (b) read-only
-    let src1 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"main.rs"]);
-    let src2 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"lib.rs"]);
+    let temp_dir = format!("{}-{}", temp_pkg_id.path, temp_pkg_id.version_or_default());
+    let src1 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"main.rs"]);
+    let src2 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"lib.rs"]);
+    debug!("src1: {}", src1.display());
     assert!(src1.exists());
     assert!(src2.exists());
     assert!(is_read_only(&src1));
@@ -2167,7 +2179,7 @@ fn test_installed_read_only() {
 #[test]
 fn test_installed_local_changes() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice()));
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -2180,9 +2192,7 @@ fn test_installed_local_changes() {
               "pub fn f() { let _x = (); }");
     add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
-
+    command_line_test([~"install", temp_pkg_id.path.to_owned()], repo);
 
     // We installed the dependency.
     // Now start a new workspace and clone it into it
@@ -2214,14 +2224,13 @@ fn test_installed_local_changes() {
               fn main() { g(); }");
     // And make sure we can build it
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"build", importer_pkg_id.path.as_str().unwrap().to_owned()],
-                      hacking_workspace);
+    command_line_test([~"build", importer_pkg_id.path.to_owned()], hacking_workspace);
 }
 
 #[test]
 fn test_7402() {
-    let dir = create_local_package(&CrateId::new("foo"));
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let dir = create_local_package(&foo_id);
     let dest_workspace = TempDir::new("more_rust").expect("test_7402");
     let dest_workspace = dest_workspace.path();
     // FIXME (#9639): This needs to handle non-utf8 paths
@@ -2235,7 +2244,7 @@ fn test_7402() {
 
 #[test]
 fn test_compile_error() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let main_crate = foo_workspace.join_many(["src", "foo-0.0", "main.rs"]);
@@ -2269,7 +2278,8 @@ fn test_c_dependency_ok() {
     // registers a hook to build it if it's not fresh
     // After running `build`, test that the C library built
 
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2292,7 +2302,8 @@ fn test_c_dependency_ok() {
 #[test]
 #[ignore(reason="busted")]
 fn test_c_dependency_no_rebuilding() {
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2326,7 +2337,8 @@ fn test_c_dependency_no_rebuilding() {
 #[test]
 #[ignore(reason="busted")]
 fn test_c_dependency_yes_rebuilding() {
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2347,7 +2359,7 @@ fn test_c_dependency_yes_rebuilding() {
     assert!(c_library_path.exists());
 
     // Now, make the Rust library read-only so rebuilding will fail
-    match built_library_in_workspace(&CrateId::new("cdep"), dir) {
+    match built_library_in_workspace(&cdep_id, dir) {
         Some(ref pth) => assert!(chmod_read_only(pth)),
         None => assert_built_library_exists(dir, "cdep")
     }
@@ -2365,7 +2377,8 @@ fn test_c_dependency_yes_rebuilding() {
 fn correct_error_dependency() {
     // Supposing a package we're trying to install via a dependency doesn't
     // exist, we should throw a condition, and not ICE
-    let workspace_dir = create_local_package(&CrateId::new("badpkg"));
+    let crate_id: CrateId = from_str("badpkg").unwrap();
+    let workspace_dir = create_local_package(&crate_id);
 
     let dir = workspace_dir.path();
     let main_rs = dir.join_many(["src", "badpkg-0.0", "main.rs"]);
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 4c2fc98a305..9042dfea256 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -10,6 +10,10 @@
 
 #[allow(dead_code)];
 
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
+pub use target::{Target, Build, Install};
+pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
+
 use std::cell::RefCell;
 use std::libc;
 use std::os;
@@ -17,7 +21,7 @@ use std::io;
 use std::io::fs;
 use extra::workcache;
 use rustc::metadata::creader::Loader;
-use rustc::driver::{driver, session};
+use extra::treemap::TreeMap;
 use extra::getopts::groups::getopts;
 use syntax;
 use syntax::codemap::{DUMMY_SP, Spanned};
@@ -28,19 +32,16 @@ use syntax::attr::AttrMetaMethods;
 use syntax::fold::Folder;
 use syntax::visit::Visitor;
 use syntax::util::small_vector::SmallVector;
+use syntax::crateid::CrateId;
 use rustc::back::link::OutputTypeExe;
 use rustc::back::link;
+use rustc::driver::{driver, session};
 use CtxMethods;
 use context::{in_target, StopBefore, Link, Assemble, BuildContext};
-use crate_id::CrateId;
 use package_source::PkgSrc;
 use workspace::pkg_parent_workspaces;
 use path_util::{system_library, target_build_dir};
 use path_util::{default_workspace, built_library_in_workspace};
-pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
-pub use target::{Target, Build, Install};
-use extra::treemap::TreeMap;
-pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
 use workcache_support::{digest_file_with_date, digest_only_date};
 use messages::error;
 
@@ -177,11 +178,11 @@ pub fn compile_input(context: &BuildContext,
     // not sure if we should support anything else
 
     let mut out_dir = target_build_dir(workspace);
-    out_dir.push(&crate_id.path);
+    out_dir.push(crate_id.path.as_slice());
     // Make the output directory if it doesn't exist already
     fs::mkdir_recursive(&out_dir, io::UserRWX);
 
-    let binary = os::args()[0].to_owned();
+    let binary = os::args()[0];
 
     debug!("flags: {}", flags.connect(" "));
     debug!("cfgs: {}", cfgs.connect(" "));
@@ -312,7 +313,7 @@ pub fn compile_input(context: &BuildContext,
     if !attr::contains_name(crate.attrs, "crate_id") {
         // FIXME (#9639): This needs to handle non-utf8 paths
         let crateid_attr =
-            attr::mk_name_value_item_str(@"crate_id", crate_id.to_crate_id_str().to_managed());
+            attr::mk_name_value_item_str(@"crate_id", crate_id.to_str().to_managed());
 
         debug!("crateid attr: {:?}", crateid_attr);
         crate.attrs.push(attr::mk_attr(crateid_attr));
@@ -441,7 +442,7 @@ pub fn compile_crate(ctxt: &BuildContext,
                      opt: session::OptLevel,
                      what: OutputType) -> Option<Path> {
     debug!("compile_crate: crate={}, workspace={}", crate.display(), workspace.display());
-    debug!("compile_crate: short_name = {}, flags =...", crate_id.to_str());
+    debug!("compile_crate: name = {}, flags =...", crate_id.to_str());
     for fl in flags.iter() {
         debug!("+++ {}", *fl);
     }
@@ -470,8 +471,9 @@ impl<'a> CrateInstaller<'a> {
                     None => self.sess.str_of(lib_ident)
                 };
                 debug!("Finding and installing... {}", lib_name);
+                let crate_id: CrateId = from_str(lib_name).expect("valid crate id");
                 // Check standard Rust library path first
-                let whatever = system_library(&self.context.sysroot_to_use(), lib_name);
+                let whatever = system_library(&self.context.sysroot_to_use(), &crate_id);
                 debug!("system library returned {:?}", whatever);
                 match whatever {
                     Some(ref installed_path) => {
@@ -491,10 +493,8 @@ impl<'a> CrateInstaller<'a> {
                     }
                     None => {
                         // FIXME #8711: need to parse version out of path_opt
-                        debug!("Trying to install library {}, rebuilding it",
-                               lib_name.to_str());
+                        debug!("Trying to install library {}, rebuilding it", crate_id.to_str());
                         // Try to install it
-                        let crate_id = CrateId::new(lib_name);
                         // Find all the workspaces in the RUST_PATH that contain this package.
                         let workspaces = pkg_parent_workspaces(&self.context.context,
                                                                &crate_id);
@@ -526,8 +526,8 @@ impl<'a> CrateInstaller<'a> {
                                  // Nonexistent package? Then print a better error
                                  error(format!("Package {} depends on {}, but I don't know \
                                                how to find it",
-                                               self.parent.path.display(),
-                                               crate_id.path.display()));
+                                               self.parent.path,
+                                               crate_id.path));
                                  fail!()
                         }).inside(|| {
                             PkgSrc::new(source_workspace.clone(),
diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs
index d6e617d2d50..e19a19dc8ab 100644
--- a/src/librustpkg/workspace.rs
+++ b/src/librustpkg/workspace.rs
@@ -11,12 +11,11 @@
 // rustpkg utilities having to do with workspaces
 
 use std::os;
-use std::path::Path;
 use context::Context;
 use path_util::{workspace_contains_crate_id, find_dir_using_rust_path_hack, default_workspace};
 use path_util::rust_path;
 use util::option_to_vec;
-use crate_id::CrateId;
+use syntax::crateid::CrateId;
 
 pub fn each_pkg_parent_workspace(cx: &Context,
                                  crateid: &CrateId,
@@ -29,7 +28,7 @@ pub fn each_pkg_parent_workspace(cx: &Context,
         // tjc: make this a condition
         fail!("Package {} not found in any of \
                     the following workspaces: {}",
-                   crateid.path.display(),
+                   crateid.path,
                    rust_path().map(|p| p.display().to_str()).to_str());
     }
     for ws in workspaces.iter() {
@@ -64,7 +63,8 @@ pub fn cwd_to_workspace() -> Option<(Path, CrateId)> {
             let rel = cwd.path_relative_from(&srcpath);
             let rel_s = rel.as_ref().and_then(|p|p.as_str());
             if rel_s.is_some() {
-                return Some((path, CrateId::new(rel_s.unwrap())));
+                let crate_id = from_str(rel_s.unwrap()).expect("valid crate id");
+                return Some((path, crate_id));
             }
         }
     }
diff --git a/src/libsyntax/crateid.rs b/src/libsyntax/crateid.rs
index 0bb1eec512b..0831f319ce7 100644
--- a/src/libsyntax/crateid.rs
+++ b/src/libsyntax/crateid.rs
@@ -70,7 +70,11 @@ impl FromStr for CrateId {
             };
 
             let version = if !hash_version.is_empty() {
-                Some(hash_version.to_owned())
+                if hash_version == "0.0" {
+                    None
+                } else {
+                    Some(hash_version.to_owned())
+                }
             } else {
                 None
             };
@@ -93,6 +97,10 @@ impl CrateId {
             Some(ref version) => version.as_slice(),
         }
     }
+
+    pub fn short_name_with_version(&self) -> ~str {
+        format!("{}-{}", self.name, self.version_or_default())
+    }
 }
 
 #[test]