diff options
| author | bors <bors@rust-lang.org> | 2013-08-09 16:17:10 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-09 16:17:10 -0700 |
| commit | 6f6dce7bbcfb104a8a1e23b0b93d83cbb770f338 (patch) | |
| tree | 1f5f151dfd5c72f41338c495a38b422ea4aa552c /src | |
| parent | 1de201c3c6ee1e563ca58d4d6b288929e841081e (diff) | |
| parent | 37fd8f03fdbc622457396877168d2a8d82cf3d2b (diff) | |
| download | rust-6f6dce7bbcfb104a8a1e23b0b93d83cbb770f338.tar.gz rust-6f6dce7bbcfb104a8a1e23b0b93d83cbb770f338.zip | |
auto merge of #8176 : catamorphism/rust/rustpkg-extern-mod, r=catamorphism
r? @graydon Also, notably, make rustpkgtest depend on the rustpkg executable (otherwise, tests that shell out to rustpgk might run when rustpkg doesn't exist).
Diffstat (limited to 'src')
28 files changed, 894 insertions, 785 deletions
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 637ea159d79..bd95f1b735b 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -16,7 +16,7 @@ use lib::llvm::llvm; use lib::llvm::ModuleRef; use lib; use metadata::common::LinkMeta; -use metadata::{encoder, csearch, cstore}; +use metadata::{encoder, csearch, cstore, filesearch}; use middle::trans::context::CrateContext; use middle::trans::common::gensym_name; use middle::ty; @@ -497,6 +497,7 @@ pub fn build_link_meta(sess: Session, struct ProvidedMetas { name: Option<@str>, vers: Option<@str>, + pkg_id: Option<@str>, cmh_items: ~[@ast::MetaItem] } @@ -504,6 +505,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { let mut name = None; let mut vers = None; + let mut pkg_id = None; let mut cmh_items = ~[]; let linkage_metas = attr::find_linkage_metas(c.attrs); attr::require_unique_names(sess.diagnostic(), linkage_metas); @@ -511,6 +513,7 @@ pub fn build_link_meta(sess: Session, match meta.name_str_pair() { Some((n, value)) if "name" == n => name = Some(value), Some((n, value)) if "vers" == n => vers = Some(value), + Some((n, value)) if "package_id" == n => pkg_id = Some(value), _ => cmh_items.push(*meta) } } @@ -518,6 +521,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { name: name, vers: vers, + pkg_id: pkg_id, cmh_items: cmh_items } } @@ -525,7 +529,8 @@ pub fn build_link_meta(sess: Session, // This calculates CMH as defined above fn crate_meta_extras_hash(symbol_hasher: &mut hash::State, cmh_items: ~[@ast::MetaItem], - dep_hashes: ~[@str]) -> @str { + dep_hashes: ~[@str], + pkg_id: Option<@str>) -> @str { fn len_and_str(s: &str) -> ~str { fmt!("%u_%s", s.len(), s) } @@ -563,7 +568,10 @@ pub fn build_link_meta(sess: Session, write_string(symbol_hasher, len_and_str(*dh)); } - // tjc: allocation is unfortunate; need to change std::hash + for p in pkg_id.iter() { + write_string(symbol_hasher, len_and_str(*p)); + } + return truncated_hash_result(symbol_hasher).to_managed(); } @@ -605,6 +613,7 @@ pub fn build_link_meta(sess: Session, let ProvidedMetas { name: opt_name, vers: opt_vers, + pkg_id: opt_pkg_id, cmh_items: cmh_items } = provided_link_metas(sess, c); let name = crate_meta_name(sess, output, opt_name); @@ -612,11 +621,12 @@ pub fn build_link_meta(sess: Session, let dep_hashes = cstore::get_dep_hashes(sess.cstore); let extras_hash = crate_meta_extras_hash(symbol_hasher, cmh_items, - dep_hashes); + dep_hashes, opt_pkg_id); LinkMeta { name: name, vers: vers, + package_id: opt_pkg_id, extras_hash: extras_hash } } @@ -939,6 +949,11 @@ pub fn link_args(sess: Session, args.push(~"-L" + path.to_str()); } + let rustpath = filesearch::rust_path(); + for path in rustpath.iter() { + args.push(~"-L" + path.to_str()); + } + // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); for l in used_libs.iter() { args.push(~"-l" + *l); } diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 6aac627729c..5dc92dbc5e6 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -14,10 +14,7 @@ use metadata::cstore; use metadata::filesearch; use std::hashmap::HashSet; -use std::num; -use std::os; -use std::util; -use std::vec; +use std::{num, os, path, uint, util, vec}; fn not_win32(os: session::os) -> bool { os != session::os_win32 @@ -122,42 +119,7 @@ pub fn get_rpath_relative_to_output(os: session::os, session::os_win32 => util::unreachable() }; - Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output), - &os::make_absolute(lib))) -} - -// Find the relative path from one file to another -pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path { - assert!(abs1.is_absolute); - assert!(abs2.is_absolute); - let abs1 = abs1.normalize(); - let abs2 = abs2.normalize(); - debug!("finding relative path from %s to %s", - abs1.to_str(), abs2.to_str()); - let split1: &[~str] = abs1.components; - let split2: &[~str] = abs2.components; - let len1 = split1.len(); - let len2 = split2.len(); - assert!(len1 > 0); - assert!(len2 > 0); - - let max_common_path = num::min(len1, len2) - 1; - let mut start_idx = 0; - while start_idx < max_common_path - && split1[start_idx] == split2[start_idx] { - start_idx += 1; - } - - let mut path = ~[]; - for _ in range(start_idx, len1 - 1) { path.push(~".."); }; - - path.push_all(split2.slice(start_idx, len2 - 1)); - - return if !path.is_empty() { - Path("").push_many(path) - } else { - Path(".") - } + Path(prefix).push_rel(&os::make_absolute(output).get_relative_to(&os::make_absolute(lib))) } fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] { @@ -208,8 +170,7 @@ mod test { #[cfg(test)] #[cfg(test)] use back::rpath::{get_absolute_rpath, get_install_prefix_rpath}; - use back::rpath::{get_relative_to, get_rpath_relative_to_output}; - use back::rpath::{minimize_rpaths, rpaths_to_flags}; + use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; use driver::session; #[test] @@ -254,77 +215,8 @@ mod test { } #[test] - fn test_relative_to1() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to2() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/bin/../lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to3() { - let p1 = Path("/usr/bin/whatever/rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../../lib/whatever")); - } - - #[test] - fn test_relative_to4() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib/whatever")); - } - - #[test] - fn test_relative_to5() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/../mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to6() { - let p1 = Path("/1"); - let p2 = Path("/2/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("2")); - } - - #[test] - fn test_relative_to7() { - let p1 = Path("/1/2"); - let p2 = Path("/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("..")); - } - - #[test] - fn test_relative_to8() { - let p1 = Path("/home/brian/Dev/rust/build/").push_rel( - &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); - let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( - &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); - let res = get_relative_to(&p1, &p2); - debug!("test_relative_tu8: %s vs. %s", - res.to_str(), - Path(".").to_str()); - assert_eq!(res, Path(".")); - } - - #[test] #[cfg(target_os = "linux")] - #[cfg(target_os = "andorid")] + #[cfg(target_os = "android")] fn test_rpath_relative() { let o = session::os_linux; let res = get_rpath_relative_to_output(o, @@ -344,7 +236,6 @@ mod test { #[test] #[cfg(target_os = "macos")] fn test_rpath_relative() { - // this is why refinements would be nice let o = session::os_macos; let res = get_rpath_relative_to_output(o, &Path("bin/rustc"), diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 3a1129b1dd9..2a61ea28e0c 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -47,7 +47,7 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate { let n1 = sess.next_node_id(); let vi1 = ast::view_item { node: ast::view_item_extern_mod( - sess.ident_of("std"), ~[], n1), + sess.ident_of("std"), None, ~[], n1), attrs: ~[ attr::mk_attr( attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed())) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index d2d2a8b4be9..c6b1bdbe51b 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -282,7 +282,7 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item { cx.sess.next_node_id()))]) } else { let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre"); - ast::view_item_extern_mod(id_extra, ~[mi], cx.sess.next_node_id()) + ast::view_item_extern_mod(id_extra, None, ~[mi], cx.sess.next_node_id()) }; ast::view_item { node: vi, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 1c5d202d4d9..f2d8b68faa6 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -185,5 +185,7 @@ pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, vers: @str, + // Optional package ID + package_id: Option<@str>, // non-None if this was a URL-like package ID extras_hash: @str } diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index d8f14228824..0a9e8490f22 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -18,6 +18,7 @@ use metadata::loader; use std::hashmap::HashMap; use syntax::ast; +use std::vec; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::{span, dummy_sp}; @@ -137,18 +138,33 @@ fn visit_crate(e: &Env, c: &ast::Crate) { fn visit_view_item(e: @mut Env, i: &ast::view_item) { match i.node { - ast::view_item_extern_mod(ident, ref meta_items, id) => { - debug!("resolving extern mod stmt. ident: %?, meta: %?", - ident, *meta_items); - let cnum = resolve_crate(e, - ident, - (*meta_items).clone(), - @"", - i.span); - cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); + ast::view_item_extern_mod(ident, path_opt, ref meta_items, id) => { + let ident = token::ident_to_str(&ident); + let meta_items = match path_opt { + None => meta_items.clone(), + Some(p) => { + let p_path = Path(p); + match p_path.filestem() { + Some(s) => + vec::append( + ~[attr::mk_name_value_item_str(@"package_id", p), + attr::mk_name_value_item_str(@"name", s.to_managed())], + *meta_items), + None => e.diag.span_bug(i.span, "Bad package path in `extern mod` item") + } + } + }; + debug!("resolving extern mod stmt. ident: %?, meta: %?", + ident, meta_items); + let cnum = resolve_crate(e, + ident, + meta_items, + @"", + i.span); + cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); } _ => () - } + } } fn visit_item(e: &Env, i: @ast::item) { @@ -233,12 +249,12 @@ fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str) } fn resolve_crate(e: @mut Env, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, span: span) -> ast::CrateNum { - let metas = metas_with_ident(token::ident_to_str(&ident), metas); + let metas = metas_with_ident(ident, metas); match existing_match(e, metas, hash) { None => { @@ -279,7 +295,7 @@ fn resolve_crate(e: @mut Env, match attr::last_meta_item_value_str_by_name(load_ctxt.metas, "name") { Some(v) => v, - None => token::ident_to_str(&ident), + None => ident }; let cmeta = @cstore::crate_metadata { name: cname, @@ -308,7 +324,6 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { let r = decoder::get_crate_deps(cdata); for dep in r.iter() { let extrn_cnum = dep.cnum; - let cname = dep.name; let cname_str = token::ident_to_str(&dep.name); let cmetas = metas_with(dep.vers, @"vers", ~[]); debug!("resolving dep crate %s ver: %s hash: %s", @@ -327,7 +342,7 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { // FIXME (#2404): Need better error reporting than just a bogus // span. let fake_span = dummy_sp(); - let local_cnum = resolve_crate(e, cname, cmetas, dep.hash, + let local_cnum = resolve_crate(e, cname_str, cmetas, dep.hash, fake_span); cnum_map.insert(extrn_cnum, local_cnum); } diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index e18879464e8..2b44d793a9d 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -11,12 +11,15 @@ use std::option; use std::os; -use std::result; +use std::{result, str}; +use std::hashmap::HashSet; // A module for searching for libraries // FIXME (#2658): I'm not happy how this module turned out. Should // probably just be folded into cstore. +/// Functions with type `pick` take a parent directory as well as +/// a file found in that directory. pub type pick<'self, T> = &'self fn(path: &Path) -> Option<T>; pub fn pick_file(file: Path, path: &Path) -> Option<Path> { @@ -46,28 +49,33 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, impl FileSearch for FileSearchImpl { fn sysroot(&self) -> @Path { self.sysroot } fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool { + let mut visited_dirs = HashSet::new(); + debug!("filesearch: searching additional lib search paths [%?]", self.addl_lib_search_paths.len()); - // a little weird - self.addl_lib_search_paths.iter().advance(|path| f(path)); + for path in self.addl_lib_search_paths.iter() { + f(path); + visited_dirs.insert(path.to_str()); + } debug!("filesearch: searching target lib path"); - if !f(&make_target_lib_path(self.sysroot, - self.target_triple)) { - return false; - } - debug!("filesearch: searching rustpkg lib path nearest"); - if match get_rustpkg_lib_path_nearest() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } { - return true; + let tlib_path = make_target_lib_path(self.sysroot, + self.target_triple); + if !visited_dirs.contains(&tlib_path.to_str()) { + if !f(&tlib_path) { + return false; } - debug!("filesearch: searching rustpkg lib path"); - match get_rustpkg_lib_path() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } + } + visited_dirs.insert(tlib_path.to_str()); + // Try RUST_PATH + let rustpath = rust_path(); + for path in rustpath.iter() { + if !visited_dirs.contains(&path.push("lib").to_str()) { + f(&path.push("lib")); + visited_dirs.insert(path.push("lib").to_str()); + } + } + true } fn get_target_lib_path(&self) -> Path { make_target_lib_path(self.sysroot, self.target_triple) @@ -94,12 +102,15 @@ pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> { for path in r.iter() { debug!("testing %s", path.to_str()); let maybe_picked = pick(path); - if maybe_picked.is_some() { - debug!("picked %s", path.to_str()); - rslt = maybe_picked; - break; - } else { - debug!("rejected %s", path.to_str()); + match maybe_picked { + Some(_) => { + debug!("picked %s", path.to_str()); + rslt = maybe_picked; + break; + } + None => { + debug!("rejected %s", path.to_str()); + } } } rslt.is_none() @@ -132,55 +143,59 @@ fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path { } } -pub fn get_rustpkg_sysroot() -> Result<Path, ~str> { - result::Ok(get_or_default_sysroot().push_many([libdir(), ~"rustpkg"])) +#[cfg(windows)] +static PATH_ENTRY_SEPARATOR: &'static str = ";"; +#[cfg(not(windows))] +static PATH_ENTRY_SEPARATOR: &'static str = ":"; + +/// Returns RUST_PATH as a string, without default paths added +pub fn get_rust_path() -> Option<~str> { + os::getenv("RUST_PATH") } -pub fn get_rustpkg_root() -> Result<Path, ~str> { - match os::getenv("RUSTPKG_ROOT") { - Some(ref _p) => result::Ok(Path((*_p))), - None => match os::homedir() { - Some(ref _q) => result::Ok((*_q).push(".rustpkg")), - None => result::Err(~"no RUSTPKG_ROOT or home directory") +/// Returns the value of RUST_PATH, as a list +/// of Paths. Includes default entries for, if they exist: +/// $HOME/.rust +/// DIR/.rust for any DIR that's the current working directory +/// or an ancestor of it +pub fn rust_path() -> ~[Path] { + let mut env_rust_path: ~[Path] = match get_rust_path() { + Some(env_path) => { + let env_path_components: ~[&str] = + env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); + env_path_components.map(|&s| Path(s)) } + None => ~[] + }; + let cwd = os::getcwd(); + // now add in default entries + let cwd_dot_rust = cwd.push(".rust"); + if !env_rust_path.contains(&cwd_dot_rust) { + env_rust_path.push(cwd_dot_rust); } -} - -pub fn get_rustpkg_root_nearest() -> Result<Path, ~str> { - do get_rustpkg_root().chain |p| { - let cwd = os::getcwd(); - let cwd_rustpkg = cwd.push(".rustpkg"); - let rustpkg_is_non_root_file = - !os::path_is_dir(&cwd_rustpkg) && cwd_rustpkg != p; - let mut par_rustpkg = cwd.pop().push(".rustpkg"); - let mut rslt = result::Ok(cwd_rustpkg); - - if rustpkg_is_non_root_file { - while par_rustpkg != p { - if os::path_is_dir(&par_rustpkg) { - rslt = result::Ok(par_rustpkg); - break; - } - if par_rustpkg.components.len() == 1 { - // We just checked /.rustpkg, stop now. - break; - } - par_rustpkg = par_rustpkg.pop().pop().push(".rustpkg"); - } + if !env_rust_path.contains(&cwd) { + env_rust_path.push(cwd.clone()); + } + do cwd.each_parent() |p| { + if !env_rust_path.contains(&p.push(".rust")) { + push_if_exists(&mut env_rust_path, p); } - rslt } -} - -fn get_rustpkg_lib_path() -> Result<Path, ~str> { - do get_rustpkg_root().chain |p| { - result::Ok(p.push(libdir())) + let h = os::homedir(); + for h in h.iter() { + if !env_rust_path.contains(&h.push(".rust")) { + push_if_exists(&mut env_rust_path, h); + } } + env_rust_path } -fn get_rustpkg_lib_path_nearest() -> Result<Path, ~str> { - do get_rustpkg_root_nearest().chain |p| { - result::Ok(p.push(libdir())) + +/// Adds p/.rust into vec, only if it exists +fn push_if_exists(vec: &mut ~[Path], p: &Path) { + let maybe_dir = p.push(".rust"); + if os::path_exists(&maybe_dir) { + vec.push(maybe_dir); } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 9330cfc5c88..5f145d87ca8 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -18,7 +18,6 @@ use metadata::filesearch::FileSearch; use metadata::filesearch; use syntax::codemap::span; use syntax::diagnostic::span_handler; -use syntax::parse::token; use syntax::parse::token::ident_interner; use syntax::print::pprust; use syntax::{ast, attr}; @@ -46,7 +45,7 @@ pub struct Context { diag: @span_handler, filesearch: @FileSearch, span: span, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, os: os, @@ -60,7 +59,7 @@ pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) { None => { cx.diag.span_fatal(cx.span, fmt!("can't find crate for `%s`", - token::ident_to_str(&cx.ident))); + cx.ident)); } } } @@ -89,37 +88,38 @@ fn find_library_crate_aux( filesearch: @filesearch::FileSearch ) -> Option<(~str, @~[u8])> { let crate_name = crate_name_from_metas(cx.metas); - let prefix = prefix + crate_name + "-"; - + // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" + let prefix = fmt!("%s%s-", prefix, crate_name); let mut matches = ~[]; filesearch::search(filesearch, |path| -> Option<()> { - debug!("inspecting file %s", path.to_str()); - match path.filename() { - Some(ref f) if f.starts_with(prefix) && f.ends_with(suffix) => { - debug!("%s is a candidate", path.to_str()); - match get_metadata_section(cx.os, path) { - Some(cvec) => - if !crate_matches(cvec, cx.metas, cx.hash) { - debug!("skipping %s, metadata doesn't match", - path.to_str()); - None - } else { - debug!("found %s with matching metadata", path.to_str()); - matches.push((path.to_str(), cvec)); - None - }, - _ => { - debug!("could not load metadata for %s", path.to_str()); - None - } - } - } - _ => { - debug!("skipping %s, doesn't look like %s*%s", path.to_str(), - prefix, suffix); - None - } - }}); + let path_str = path.filename(); + match path_str { + None => None, + Some(path_str) => + if path_str.starts_with(prefix) && path_str.ends_with(suffix) { + debug!("%s is a candidate", path.to_str()); + match get_metadata_section(cx.os, path) { + Some(cvec) => + if !crate_matches(cvec, cx.metas, cx.hash) { + debug!("skipping %s, metadata doesn't match", + path.to_str()); + None + } else { + debug!("found %s with matching metadata", path.to_str()); + matches.push((path.to_str(), cvec)); + None + }, + _ => { + debug!("could not load metadata for %s", path.to_str()); + None + } + } + } + else { + None + } + } + }); match matches.len() { 0 => None, @@ -137,8 +137,8 @@ fn find_library_crate_aux( } cx.diag.handler().abort_if_errors(); None - } } + } } pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { @@ -151,6 +151,16 @@ pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { fail!("expected to find the crate name") } +pub fn package_id_from_metas(metas: &[@ast::MetaItem]) -> Option<@str> { + for m in metas.iter() { + match m.name_str_pair() { + Some((name, s)) if "package_id" == name => { return Some(s); } + _ => {} + } + } + None +} + pub fn note_linkage_attrs(intr: @ident_interner, diag: @span_handler, attrs: ~[ast::Attribute]) { @@ -175,6 +185,8 @@ fn crate_matches(crate_data: @~[u8], pub fn metadata_matches(extern_metas: &[@ast::MetaItem], local_metas: &[@ast::MetaItem]) -> bool { +// extern_metas: metas we read from the crate +// local_metas: metas we're looking for debug!("matching %u metadata requirements against %u items", local_metas.len(), extern_metas.len()); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 43953a50e15..7d892d97676 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1487,9 +1487,10 @@ impl Resolver { } } - view_item_extern_mod(name, _, node_id) => { + view_item_extern_mod(name, _, _, node_id) => { + // n.b. we don't need to look at the path option here, because cstore already did match find_extern_mod_stmt_cnum(self.session.cstore, - node_id) { + node_id) { Some(crate_id) => { let def_id = def_id { crate: crate_id, node: 0 }; let parent_link = ModuleParentLink diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index bcda135cbb6..2da66baa412 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -23,33 +23,30 @@ fn default_ctxt(p: @Path) -> Ctx { Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() } } -pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, +pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version, lib: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[mk_crate(lib)], mains: ~[], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } -pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, - main: Path) { +pub fn build_exe(sysroot: @Path, root: Path, name: ~str, version: Version, main: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[], mains: ~[mk_crate(main)], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } @@ -62,12 +59,9 @@ pub fn install_lib(sysroot: @Path, debug!("sysroot = %s", sysroot.to_str()); debug!("workspace = %s", workspace.to_str()); // make a PkgSrc - let pkg_id = PkgId{ version: version, ..PkgId::new(name, &workspace)}; - let build_dir = workspace.push("build"); - let dst_dir = build_dir.push_rel(&*pkg_id.local_path); + let pkg_id = PkgId{ version: version, ..PkgId::new(name)}; let pkg_src = PkgSrc { root: workspace.clone(), - dst_dir: dst_dir.clone(), id: pkg_id.clone(), libs: ~[mk_crate(lib_path)], mains: ~[], @@ -75,13 +69,13 @@ pub fn install_lib(sysroot: @Path, benchs: ~[] }; let cx = default_ctxt(sysroot); - pkg_src.build(&cx, dst_dir, ~[]); + pkg_src.build(&cx, ~[]); cx.install_no_build(&workspace, &pkg_id); } pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) { default_ctxt(sysroot).install(&workspace, &PkgId{ version: version, - ..PkgId::new(name, &workspace)}); + ..PkgId::new(name)}); } diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 230a0f915ac..f051be25f26 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -12,6 +12,7 @@ use std::hashmap::HashMap; +use std::os; pub struct Ctx { // Sysroot -- if this is None, uses rustc filesearch's @@ -23,3 +24,26 @@ pub struct Ctx { // though I'm not sure why the value is a bool dep_cache: @mut HashMap<~str, bool>, } + +impl Ctx { + /// Debugging + pub fn sysroot_opt_str(&self) -> ~str { + match self.sysroot_opt { + None => ~"[none]", + Some(p) => p.to_str() + } + } +} + +/// We assume that if ../../rustc exists, then we're running +/// rustpkg from a Rust target directory. This is part of a +/// kludgy hack used to adjust the sysroot. +pub fn in_target(sysroot_opt: Option<@Path>) -> bool { + match sysroot_opt { + None => false, + Some(p) => { + debug!("Checking whether %s is in target", p.to_str()); + os::path_is_dir(&p.pop().pop().push("rustc")) + } + } +} diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index cec64f36947..7c3cde65517 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -10,6 +10,7 @@ // Listing installed packages +use rustc::metadata::filesearch::rust_path; use path_util::*; use std::os; @@ -20,21 +21,46 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { for exec in binfiles.iter() { let exec_path = Path(*exec).filestem(); do exec_path.iter().advance |s| { - f(&PkgId::new(*s, p)) + f(&PkgId::new(*s)) }; } let libfiles = os::list_dir(&p.push("lib")); for lib in libfiles.iter() { - debug!("Full name: %s", *lib); - let lib_path = Path(*lib).filestem(); - do lib_path.iter().advance |s| { - f(&PkgId::new(*s, p)) - }; - } + let lib = Path(*lib); + debug!("Full name: %s", lib.to_str()); + match has_library(&lib) { + Some(basename) => { + debug!("parent = %s, child = %s", + p.push("lib").to_str(), lib.to_str()); + let rel_p = p.push("lib/").get_relative_to(&lib); + debug!("Rel: %s", rel_p.to_str()); + let rel_path = rel_p.push(basename).to_str(); + debug!("Rel name: %s", rel_path); + f(&PkgId::new(rel_path)); + } + None => () + } + }; } true } +pub fn has_library(p: &Path) -> Option<~str> { + let files = os::list_dir(p); + for q in files.iter() { + let as_path = Path(*q); + if as_path.filetype() == Some(os::consts::DLL_SUFFIX.to_owned()) { + let stuff : ~str = as_path.filestem().expect("has_library: weird path"); + let mut stuff2 = stuff.split_str_iter(&"-"); + let stuff3: ~[&str] = stuff2.collect(); + // argh + let chars_to_drop = os::consts::DLL_PREFIX.len(); + return Some(stuff3[0].slice(chars_to_drop, stuff3[0].len()).to_owned()); + } + } + None +} + pub fn package_is_installed(p: &PkgId) -> bool { let mut is_installed = false; do list_installed_packages() |installed| { @@ -44,4 +70,4 @@ pub fn package_is_installed(p: &PkgId) -> bool { false }; is_installed -} \ No newline at end of file +} diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index e1cf5b1fd35..e3b3252587a 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -8,33 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use package_path::{RemotePath, LocalPath, normalize, hash}; use version::{try_getting_version, try_getting_local_version, Version, NoVersion, split_version}; +use std::rt::io::Writer; +use std::hash::Streaming; +use std::hash; /// 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 PkgId { - /// Remote path: for example, github.com/mozilla/quux-whatever - remote_path: RemotePath, - /// Local path: for example, /home/quux/github.com/mozilla/quux_whatever - /// Note that '-' normalizes to '_' when mapping a remote path - /// onto a local path - /// Also, this will change when we implement #6407, though we'll still - /// need to keep track of separate local and remote paths - local_path: LocalPath, - /// Short name. This is the local path's filestem, but we store it + /// 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: Version } impl Eq for PkgId { fn eq(&self, p: &PkgId) -> bool { - *p.local_path == *self.local_path && p.version == self.version + p.path == self.path && p.version == self.version } fn ne(&self, p: &PkgId) -> bool { !(self.eq(p)) @@ -42,10 +46,7 @@ impl Eq for PkgId { } impl PkgId { - // The PkgId constructor takes a Path argument so as - // to be able to infer the version if the path refers - // to a local git repository - pub fn new(s: &str, work_dir: &Path) -> PkgId { + pub fn new(s: &str) -> PkgId { use conditions::bad_pkg_id::cond; let mut given_version = None; @@ -63,51 +64,64 @@ impl PkgId { } }; - let p = Path(s); - if p.is_absolute { - return cond.raise((p, ~"absolute pkgid")); + let path = Path(s); + if path.is_absolute { + return cond.raise((path, ~"absolute pkgid")); } - if p.components.len() < 1 { - return cond.raise((p, ~"0-length pkgid")); + if path.components.len() < 1 { + return cond.raise((path, ~"0-length pkgid")); } - let remote_path = RemotePath(p); - let local_path = normalize(remote_path.clone()); - let short_name = local_path.clone().filestem().expect(fmt!("Strange path! %s", s)); + let short_name = path.clone().filestem().expect(fmt!("Strange path! %s", s)); let version = match given_version { Some(v) => v, - None => match try_getting_local_version(&work_dir.push_rel(&*local_path)) { + None => match try_getting_local_version(&path) { Some(v) => v, - None => match try_getting_version(&remote_path) { + None => match try_getting_version(&path) { Some(v) => v, None => NoVersion } } }; - debug!("local_path = %s, remote_path = %s", local_path.to_str(), remote_path.to_str()); + debug!("path = %s", path.to_str()); PkgId { - local_path: local_path, - remote_path: remote_path, + path: path, short_name: short_name, version: version } } pub fn hash(&self) -> ~str { - fmt!("%s-%s-%s", self.remote_path.to_str(), - hash(self.remote_path.to_str() + self.version.to_str()), + fmt!("%s-%s-%s", self.path.to_str(), + hash(self.path.to_str() + self.version.to_str()), self.version.to_str()) } pub fn short_name_with_version(&self) -> ~str { fmt!("%s%s", self.short_name, self.version.to_str()) } + + /// True if the ID has multiple components + pub fn is_complex(&self) -> bool { + self.short_name != self.path.to_str() + } } impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - fmt!("%s-%s", self.local_path.to_str(), self.version.to_str()) + fmt!("%s-%s", self.path.to_str(), self.version.to_str()) } } + + +pub fn write<W: Writer>(writer: &mut W, string: &str) { + writer.write(string.as_bytes()); +} + +pub fn hash(data: ~str) -> ~str { + let hasher = &mut hash::default_state(); + write(hasher, data); + hasher.result_str() +} diff --git a/src/librustpkg/package_path.rs b/src/librustpkg/package_path.rs deleted file mode 100644 index 4ba9c8066e4..00000000000 --- a/src/librustpkg/package_path.rs +++ /dev/null @@ -1,68 +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. - -// rustpkg utilities having to do with local and remote paths - -use std::clone::Clone; -use std::hash::Streaming; -use std::hash; -use std::option::Some; -use std::path::Path; -use std::rt::io::Writer; - -/// Wrappers to prevent local and remote paths from getting confused -/// (These will go away after #6407) -pub struct RemotePath (Path); - -impl Clone for RemotePath { - fn clone(&self) -> RemotePath { - RemotePath((**self).clone()) - } -} - -pub struct LocalPath (Path); - -impl Clone for LocalPath { - fn clone(&self) -> LocalPath { - LocalPath((**self).clone()) - } -} - - -// normalize should be the only way to construct a LocalPath -// (though this isn't enforced) -/// Replace all occurrences of '-' in the stem part of path with '_' -/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux -/// as the same name -pub fn normalize(p_: RemotePath) -> LocalPath { - let RemotePath(p) = p_; - match p.filestem() { - None => LocalPath(p), - Some(st) => { - let replaced = st.replace("-", "_"); - if replaced != st { - LocalPath(p.with_filestem(replaced)) - } - else { - LocalPath(p) - } - } - } -} - -pub fn write<W: Writer>(writer: &mut W, string: &str) { - writer.write(string.as_bytes()); -} - -pub fn hash(data: ~str) -> ~str { - let hasher = &mut hash::default_state(); - write(hasher, data); - hasher.result_str() -} diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index bbe35ee5004..9833e18e016 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -11,7 +11,7 @@ use target::*; use package_id::PkgId; use std::path::Path; -use std::{os, str}; +use std::os; use context::*; use crate::Crate; use messages::*; @@ -23,7 +23,6 @@ use util::compile_crate; // This contains a list of files found in the source workspace. pub struct PkgSrc { root: Path, // root of where the package source code lives - dst_dir: Path, // directory where we will put the compiled output id: PkgId, libs: ~[Crate], mains: ~[Crate], @@ -37,11 +36,9 @@ condition! { impl PkgSrc { - pub fn new(src_dir: &Path, dst_dir: &Path, - id: &PkgId) -> PkgSrc { + pub fn new(src_dir: &Path, id: &PkgId) -> PkgSrc { PkgSrc { root: (*src_dir).clone(), - dst_dir: (*dst_dir).clone(), id: (*id).clone(), libs: ~[], mains: ~[], @@ -54,8 +51,7 @@ impl PkgSrc { fn check_dir(&self) -> Path { use conditions::nonexistent_package::cond; - debug!("Pushing onto root: %s | %s", self.id.remote_path.to_str(), - self.root.to_str()); + debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str()); let dir; let dirs = pkgid_src_in_workspace(&self.id, &self.root); debug!("Checking dirs: %?", dirs); @@ -89,18 +85,18 @@ impl PkgSrc { os::remove_dir_recursive(&local); debug!("Checking whether %s exists locally. Cwd = %s, does it? %?", - self.id.local_path.to_str(), + self.id.path.to_str(), os::getcwd().to_str(), - os::path_exists(&*self.id.local_path)); + os::path_exists(&self.id.path)); - if os::path_exists(&*self.id.local_path) { + if os::path_exists(&self.id.path) { debug!("%s exists locally! Cloning it into %s", - self.id.local_path.to_str(), local.to_str()); - git_clone(&*self.id.local_path, &local, &self.id.version); + self.id.path.to_str(), local.to_str()); + git_clone(&self.id.path, &local, &self.id.version); return Some(local); } - let url = fmt!("https://%s", self.id.remote_path.to_str()); + let url = fmt!("https://%s", self.id.path.to_str()); note(fmt!("Fetching package: git clone %s %s [version=%s]", url, local.to_str(), self.id.version.to_str())); if git_clone_general(url, &local, &self.id.version) { @@ -125,25 +121,8 @@ impl PkgSrc { } /// True if the given path's stem is self's pkg ID's stem - /// or if the pkg ID's stem is <rust-foo> and the given path's - /// stem is foo - /// Requires that dashes in p have already been normalized to - /// underscores fn stem_matches(&self, p: &Path) -> bool { - let self_id = self.id.local_path.filestem(); - if self_id == p.filestem() { - return true; - } - else { - for pth in self_id.iter() { - if pth.starts_with("rust_") // because p is already normalized - && match p.filestem() { - Some(s) => str::eq_slice(s, pth.slice(5, pth.len())), - None => false - } { return true; } - } - } - false + p.filestem().map_default(false, |p| { p == &self.id.short_name }) } fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { @@ -164,7 +143,7 @@ impl PkgSrc { let dir = self.check_dir(); debug!("Called check_dir, I'm in %s", dir.to_str()); let prefix = dir.components.len(); - debug!("Matching against %?", self.id.local_path.filestem()); + debug!("Matching against %?", self.id.short_name); do os::walk_dir(&dir) |pth| { match pth.filename() { Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs, @@ -202,7 +181,6 @@ impl PkgSrc { fn build_crates(&self, ctx: &Ctx, - dst_dir: &Path, src_dir: &Path, crates: &[Crate], cfgs: &[~str], @@ -210,12 +188,13 @@ impl PkgSrc { for crate in crates.iter() { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); - note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); + note(fmt!("build_crates: using as workspace %s", self.root.to_str())); let result = compile_crate(ctx, &self.id, path, - dst_dir, + // compile_crate wants the workspace + &self.root, crate.flags, crate.cfgs + cfgs, false, @@ -229,15 +208,15 @@ impl PkgSrc { } } - pub fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) { + pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) { let dir = self.check_dir(); debug!("Building libs in %s", dir.to_str()); - self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib); + self.build_crates(ctx, &dir, self.libs, cfgs, Lib); debug!("Building mains"); - self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main); + self.build_crates(ctx, &dir, self.mains, cfgs, Main); debug!("Building tests"); - self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test); + self.build_crates(ctx, &dir, self.tests, cfgs, Test); debug!("Building benches"); - self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench); + self.build_crates(ctx, &dir, self.benchs, cfgs, Bench); } } diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index fdfa29b2f83..bbe84b2ecac 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -10,65 +10,17 @@ // rustpkg utilities having to do with paths and directories -pub use package_path::{RemotePath, LocalPath, normalize}; pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general}; +pub use rustc::metadata::filesearch::rust_path; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os::mkdir_recursive; use std::os; -use std::iterator::IteratorUtil; use messages::*; use package_id::*; -fn push_if_exists(vec: &mut ~[Path], p: &Path) { - let maybe_dir = p.push(".rust"); - if os::path_exists(&maybe_dir) { - vec.push(maybe_dir); - } -} - -#[cfg(windows)] -static PATH_ENTRY_SEPARATOR: &'static str = ";"; -#[cfg(not(windows))] -static PATH_ENTRY_SEPARATOR: &'static str = ":"; - -/// Returns RUST_PATH as a string, without default paths added -pub fn get_rust_path() -> Option<~str> { - os::getenv("RUST_PATH") -} - -/// Returns the value of RUST_PATH, as a list -/// of Paths. Includes default entries for, if they exist: -/// $HOME/.rust -/// DIR/.rust for any DIR that's the current working directory -/// or an ancestor of it -pub fn rust_path() -> ~[Path] { - let mut env_rust_path: ~[Path] = match get_rust_path() { - Some(env_path) => { - let env_path_components: ~[&str] = - env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); - env_path_components.map(|&s| Path(s)) - } - None => ~[] - }; - debug!("RUST_PATH entries from environment: %?", env_rust_path); - let cwd = os::getcwd(); - // now add in default entries - env_rust_path.push(cwd.clone()); - do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; - let h = os::homedir(); - // Avoid adding duplicates - // could still add dups if someone puts one of these in the RUST_PATH - // manually, though... - for hdir in h.iter() { - if !(cwd.is_ancestor_of(hdir) || hdir.is_ancestor_of(&cwd)) { - push_if_exists(&mut env_rust_path, hdir); - } - } - env_rust_path -} - pub fn default_workspace() -> Path { let p = rust_path(); if p.is_empty() { @@ -99,39 +51,39 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } /// pkgid's short name pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); - let dirs = os::list_dir(&src_dir); - for p in dirs.iter() { - let p = Path((*p).clone()); + let mut found = false; + do os::walk_dir(&src_dir) |p| { debug!("=> p = %s", p.to_str()); - if !os::path_is_dir(&src_dir.push_rel(&p)) { - loop; - } - debug!("p = %s, remote_path = %s", p.to_str(), pkgid.remote_path.to_str()); + if os::path_is_dir(p) { + debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(), + src_dir.push_rel(&pkgid.path).to_str()); - if p == *pkgid.remote_path { - return true; - } - else { - let pf = p.filename(); - for pf in pf.iter() { - let f_ = (*pf).clone(); - let g = f_.to_str(); - match split_version_general(g, '-') { - Some((ref might_match, ref vers)) => { - debug!("might_match = %s, vers = %s", *might_match, + if *p == src_dir.push_rel(&pkgid.path) { + found = true; + } + else { + let pf = p.filename(); + for pf in pf.iter() { + let f_ = (*pf).clone(); + let g = f_.to_str(); + match split_version_general(g, '-') { + Some((ref might_match, ref vers)) => { + debug!("might_match = %s, vers = %s", *might_match, vers.to_str()); - if *might_match == pkgid.short_name - && (*vers == pkgid.version || pkgid.version == NoVersion) - { - return true; + if *might_match == pkgid.short_name + && (*vers == pkgid.version || pkgid.version == NoVersion) + { + found = true; + } } - } - None => () + None => () + } } } } - } - false + true + }; + found } /// Returns a list of possible directories @@ -141,9 +93,9 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] { let mut results = ~[]; let result = workspace.push("src").push(fmt!("%s-%s", - pkgid.local_path.to_str(), pkgid.version.to_str())); + pkgid.path.to_str(), pkgid.version.to_str())); results.push(result); - results.push(workspace.push("src").push_rel(&*pkgid.remote_path)); + results.push(workspace.push("src").push_rel(&pkgid.path)); results } @@ -163,7 +115,7 @@ pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<P pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(Main, Build, pkgid, &result); + result = mk_output_path(Main, Build, pkgid, result); debug!("built_executable_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -191,7 +143,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(what, Build, pkgid, &result); + result = mk_output_path(what, Build, pkgid, result); debug!("output_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -206,14 +158,12 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt /// Figure out what the library name for <pkgid> in <workspace>'s build /// directory is, and if the file exists, return it. pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { - library_in_workspace(&pkgid.local_path, pkgid.short_name, - Build, workspace, "build") + library_in_workspace(&pkgid.path, pkgid.short_name, Build, workspace, "build") } /// Does the actual searching stuff pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> { - library_in_workspace(&normalize(RemotePath(Path(short_name))), - short_name, Install, workspace, "lib") + library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib") } @@ -221,7 +171,7 @@ pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Opt /// don't know the entire package ID. /// `workspace` is used to figure out the directory to search. /// `short_name` is taken as the link name of the library. -pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, +pub fn library_in_workspace(path: &Path, short_name: &str, where: Target, workspace: &Path, prefix: &str) -> Option<Path> { debug!("library_in_workspace: checking whether a library named %s exists", short_name); @@ -233,7 +183,7 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, prefix = %s", short_name, where, workspace.to_str(), prefix); let dir_to_search = match where { - Build => workspace.push(prefix).push_rel(&**path), + Build => workspace.push(prefix).push_rel(path), Install => workspace.push(prefix) }; debug!("Listing directory %s", dir_to_search.to_str()); @@ -349,7 +299,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, // Artifacts in the build directory live in a package-ID-specific subdirectory, // but installed ones don't. let result = match where { - Build => workspace.push(subdir).push_rel(&*pkgid.local_path), + Build => workspace.push(subdir).push_rel(&pkgid.path), _ => workspace.push(subdir) }; if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) { @@ -357,7 +307,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, create the %s dir (pkgid=%s, workspace=%s, what=%?, where=%?", subdir, pkgid.to_str(), workspace.to_str(), what, where))); } - mk_output_path(what, where, pkgid, &result) + mk_output_path(what, where, pkgid, result) } /// Return the directory for <pkgid>'s build artifacts in <workspace>. @@ -368,7 +318,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { let mut result = workspace.push("build"); // n.b. Should actually use a target-specific // subdirectory of build/ - result = result.push_rel(&*pkgid.local_path); + result = result.push_rel(&pkgid.path); if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { result } @@ -380,19 +330,16 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, 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: &PkgId, workspace: &Path) -> Path { + pkg_id: &PkgId, workspace: Path) -> Path { let short_name_with_version = fmt!("%s-%s", pkg_id.short_name, pkg_id.version.to_str()); // 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 => { - // bad copy, but I just couldn't make the borrow checker happy - (*workspace).clone() - } + Install => workspace, // and if we're just building, it goes in a package-specific subdir - Build => workspace.push_rel(&*pkg_id.local_path) + Build => workspace.push_rel(&pkg_id.path) }; debug!("[%?:%?] mk_output_path: short_name = %s, path = %s", what, where, if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() }, diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index fa03a5bbfc2..26dab4120fd 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -33,12 +33,13 @@ use std::hashmap::HashMap; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; +use rustc::metadata::filesearch::rust_path; use extra::{getopts}; use syntax::{ast, diagnostic}; use util::*; use messages::*; use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace}; -use path_util::{U_RWX, rust_path, in_rust_path}; +use path_util::{U_RWX, in_rust_path}; use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace}; use source_control::is_git_dir; @@ -54,7 +55,6 @@ mod crate; mod installed_packages; mod messages; mod package_id; -mod package_path; mod package_source; mod path_util; mod search; @@ -138,35 +138,28 @@ impl<'self> PkgScript<'self> { let crate = util::ready_crate(sess, self.crate); debug!("Building output filenames with script name %s", driver::source_name(&self.input)); - match filesearch::get_rustpkg_sysroot() { - Ok(r) => { - let root = r.pop().pop().pop().pop(); // :-\ - debug!("Root is %s, calling compile_rest", root.to_str()); - let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); - util::compile_crate_from_input(&self.input, - &self.build_dir, - sess, - crate); - debug!("Running program: %s %s %s %s", exe.to_str(), - sysroot.to_str(), root.to_str(), "install"); - // FIXME #7401 should support commands besides `install` - let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); - if status != 0 { - return (~[], status); - } - else { - debug!("Running program (configs): %s %s %s", - exe.to_str(), root.to_str(), "configs"); - let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); - // Run the configs() function to get the configs - let cfgs = str::from_bytes_slice(output.output).word_iter() - .transform(|w| w.to_owned()).collect(); - (cfgs, output.status) - } - } - Err(e) => { - fail!("Running package script, couldn't find rustpkg sysroot (%s)", e) - } + let root = filesearch::get_or_default_sysroot().pop().pop(); // :-\ + debug!("Root is %s, calling compile_rest", root.to_str()); + let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); + util::compile_crate_from_input(&self.input, + &self.build_dir, + sess, + crate); + debug!("Running program: %s %s %s %s", exe.to_str(), + sysroot.to_str(), root.to_str(), "install"); + // FIXME #7401 should support commands besides `install` + let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); + if status != 0 { + return (~[], status); + } + else { + debug!("Running program (configs): %s %s %s", + exe.to_str(), root.to_str(), "configs"); + let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); + // Run the configs() function to get the configs + let cfgs = str::from_bytes_slice(output.output).word_iter() + .transform(|w| w.to_owned()).collect(); + (cfgs, output.status) } } @@ -205,7 +198,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); do each_pkg_parent_workspace(&pkgid) |workspace| { debug!("found pkg %s in workspace %s, trying to build", pkgid.to_str(), workspace.to_str()); @@ -228,7 +221,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); let cwd = os::getcwd(); self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd } @@ -254,13 +247,12 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0], &os::getcwd()); + let pkgid = PkgId::new(args[0]); let workspaces = pkg_parent_workspaces(&pkgid); if workspaces.is_empty() { let rp = rust_path(); assert!(!rp.is_empty()); - let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]), - &pkgid); + let src = PkgSrc::new(&rp[0], &pkgid); src.fetch_git(); self.install(&rp[0], &pkgid); } @@ -275,7 +267,7 @@ impl CtxMethods for Ctx { "list" => { io::println("Installed packages:"); do installed_packages::list_installed_packages |pkg_id| { - println(pkg_id.local_path.to_str()); + println(pkg_id.path.to_str()); true }; } @@ -294,7 +286,7 @@ impl CtxMethods for Ctx { return usage::uninstall(); } - let pkgid = PkgId::new(args[0], &os::getcwd()); // ?? + let pkgid = PkgId::new(args[0]); if !installed_packages::package_is_installed(&pkgid) { warn(fmt!("Package %s doesn't seem to be installed! Doing nothing.", args[0])); return; @@ -329,20 +321,18 @@ impl CtxMethods for Ctx { fn build(&self, workspace: &Path, pkgid: &PkgId) { debug!("build: workspace = %s (in Rust path? %? is git dir? %? \ pkgid = %s", workspace.to_str(), - in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)), pkgid.to_str()); let src_dir = first_pkgid_src_in_workspace(pkgid, workspace); - let build_dir = build_pkg_id_in_workspace(pkgid, workspace); - debug!("Destination dir = %s", build_dir.to_str()); // 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 debug!("%? %? %s", in_rust_path(workspace), - is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + is_git_dir(&workspace.push_rel(&pkgid.path)), workspace.to_str()); - if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&*pkgid.local_path)) { - let out_dir = default_workspace().push("src").push_rel(&*pkgid.local_path); - source_control::git_clone(&workspace.push_rel(&*pkgid.local_path), + if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) { + let out_dir = default_workspace().push("src").push_rel(&pkgid.path); + source_control::git_clone(&workspace.push_rel(&pkgid.path), &out_dir, &pkgid.version); let default_ws = default_workspace(); debug!("Calling build recursively with %? and %?", default_ws.to_str(), @@ -351,7 +341,7 @@ impl CtxMethods for Ctx { } // Create the package source - let mut src = PkgSrc::new(workspace, &build_dir, pkgid); + let mut src = PkgSrc::new(workspace, pkgid); debug!("Package src = %?", src); // Is there custom build logic? If so, use it @@ -385,7 +375,7 @@ impl CtxMethods for Ctx { // Find crates inside the workspace src.find_crates(); // Build it! - src.build(self, build_dir, cfgs); + src.build(self, cfgs); } } @@ -444,6 +434,7 @@ impl CtxMethods for Ctx { for lib in maybe_library.iter() { let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \ didn't install it!", lib.to_str())); + let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib")); debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) && os::copy_file(lib, &target_lib)) { @@ -518,9 +509,7 @@ pub fn main() { }; } - let sroot = match filesearch::get_rustpkg_sysroot() { - Ok(r) => Some(@r.pop().pop()), Err(_) => None - }; + let sroot = Some(@filesearch::get_or_default_sysroot()); debug!("Using sysroot: %?", sroot); Ctx { sysroot_opt: sroot, // Currently, only tests override this diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index e3b796a03bb..caa004a53b2 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,7 +10,7 @@ // Utils for working with version control repositories. Just git right now. -use std::{os, run, str}; +use std::{io, os, run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use version::*; @@ -19,14 +19,37 @@ pub fn git_clone(source: &Path, target: &Path, v: &Version) { assert!(os::path_is_dir(source)); assert!(is_git_dir(source)); if !os::path_exists(target) { - debug!("Running: git clone %s %s", source.to_str(), - target.to_str()); - assert!(git_clone_general(source.to_str(), target, v)); + debug!("Running: git clone %s %s", source.to_str(), target.to_str()); + let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git clone` %s", source.to_str()); + } + else { + match v { + &ExactRevision(ref s) => { + debug!("`Running: git --work-tree=%s --git-dir=%s checkout %s", + *s, target.to_str(), target.push(".git").to_str()); + let outp = run::process_output("git", + [fmt!("--work-tree=%s", target.to_str()), + fmt!("--git-dir=%s", target.push(".git").to_str()), + ~"checkout", fmt!("%s", *s)]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git checkout %s` in %s", + *s, target.to_str()); + } + } + _ => () + } + } } else { - // Pull changes - // Note that this ignores tags, which is probably wrong. There are no tests for - // it, though. + // Check that no version was specified. There's no reason to not handle the + // case where a version was requested, but I haven't implemented it. + assert!(*v == NoVersion); debug!("Running: git --work-tree=%s --git-dir=%s pull --no-edit %s", target.to_str(), target.push(".git").to_str(), source.to_str()); let outp = run::process_output("git", [fmt!("--work-tree=%s", target.to_str()), diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 9fea8662129..121dcf40150 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -12,11 +12,10 @@ use context::Ctx; use std::hashmap::HashMap; -use std::{io, libc, os, result, run, str}; +use std::{io, libc, os, run, str}; use extra::tempfile::mkdtemp; use std::run::ProcessOutput; use installed_packages::list_installed_packages; -use package_path::*; use package_id::{PkgId}; use version::{ExactRevision, NoVersion, Version, Tagged}; use path_util::{target_executable_in_workspace, target_library_in_workspace, @@ -24,7 +23,9 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, U_RWX, library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, - installed_library_in_workspace, rust_path}; + installed_library_in_workspace}; +use rustc::metadata::filesearch::rust_path; +use rustc::driver::driver::host_triple; use target::*; /// Returns the last-modified date as an Option @@ -42,31 +43,25 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { fn fake_pkg() -> PkgId { let sn = ~"bogus"; - let remote = RemotePath(Path(sn)); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, + path: Path(sn), short_name: sn, version: NoVersion } } fn git_repo_pkg() -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: NoVersion } } fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: Tagged(a_tag) } } @@ -76,13 +71,13 @@ fn writeFile(file_path: &Path, contents: &str) { out.write_line(contents); } -fn mk_empty_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path { let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); mk_workspace(&workspace_dir, short_name, version); workspace_dir } -fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> Path { +fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path { // include version number in directory name let package_dir = workspace.push("src").push(fmt!("%s-%s", short_name.to_str(), version.to_str())); @@ -90,7 +85,7 @@ fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> package_dir } -fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path { let package_dir = mk_empty_workspace(short_name, version).push("src").push(fmt!("%s-%s", short_name.to_str(), @@ -116,6 +111,22 @@ fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { package_dir } +fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) { + let cwd = (*cwd).clone(); + let mut prog = run::Process::new("git", args, run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + let rslt = prog.finish_with_output(); + if rslt.status != 0 { + fail!("%s [git returned %?, output = %s, error = %s]", err_msg, + rslt.status, str::from_bytes(rslt.output), str::from_bytes(rslt.error)); + } +} + /// Should create an empty git repo in p, relative to the tmp dir, and return the new /// absolute path fn init_git_repo(p: &Path) -> Path { @@ -125,37 +136,14 @@ fn init_git_repo(p: &Path) -> Path { let work_dir_for_opts = work_dir.clone(); assert!(os::mkdir_recursive(&work_dir, U_RWX)); debug!("Running: git init in %s", work_dir.to_str()); - let opts = run::ProcessOptions { - env: None, - dir: Some(&work_dir_for_opts), - in_fd: None, - out_fd: None, - err_fd: None - }; - let mut prog = run::Process::new("git", [~"init"], opts); - let mut output = prog.finish_with_output(); - if output.status == 0 { - // Add stuff to the dir so that git tag succeeds - writeFile(&work_dir.push("README"), ""); - prog = run::Process::new("git", [~"add", ~"README"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - prog = run::Process::new("git", [~"commit", ~"-m", ~"whatever"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - tmp - } - else { - fail!("Couldn't commit in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't add in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't initialize git repository in %s", work_dir.to_str()) - } + let ws = work_dir.to_str(); + run_git([~"init"], None, &work_dir_for_opts, + fmt!("Couldn't initialize git repository in %s", ws)); + // Add stuff to the dir so that git tag succeeds + writeFile(&work_dir.push("README"), ""); + run_git([~"add", ~"README"], None, &work_dir_for_opts, fmt!("Couldn't add in %s", ws)); + git_commit(&work_dir_for_opts, ~"whatever"); + tmp } fn add_all_and_commit(repo: &Path) { @@ -164,51 +152,20 @@ fn add_all_and_commit(repo: &Path) { } fn git_commit(repo: &Path, msg: ~str) { - let mut prog = run::Process::new("git", [~"commit", ~"-m", msg], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't commit in %s: output was %s", repo.to_str(), - str::from_bytes(output.output + output.error)) - } - + run_git([~"commit", ~"--author=tester <test@mozilla.com>", ~"-m", msg], + None, repo, fmt!("Couldn't commit in %s", repo.to_str())); } fn git_add_all(repo: &Path) { - let mut prog = run::Process::new("git", [~"add", ~"-A"], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add all files in %s: output was %s", - repo.to_str(), str::from_bytes(output.output + output.error)) - } + run_git([~"add", ~"-A"], None, repo, fmt!("Couldn't add all files in %s", repo.to_str())); } fn add_git_tag(repo: &Path, tag: ~str) { assert!(repo.is_absolute()); git_add_all(repo); git_commit(repo, ~"whatever"); - let mut prog = run::Process::new("git", [~"tag", tag.clone()], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add git tag %s in %s", tag, repo.to_str()) - } + run_git([~"tag", tag.clone()], None, repo, + fmt!("Couldn't add git tag %s in %s", tag, repo.to_str())); } fn is_rwx(p: &Path) -> bool { @@ -231,6 +188,25 @@ fn test_sysroot() -> Path { self_path.pop() } +// Returns the path to rustpkg +fn rustpkg_exec() -> Path { + // Ugh + let first_try = test_sysroot().push("lib").push("rustc") + .push(host_triple()).push("bin").push("rustpkg"); + if is_executable(&first_try) { + first_try + } + else { + let second_try = test_sysroot().push("bin").push("rustpkg"); + if is_executable(&second_try) { + second_try + } + else { + fail!("in rustpkg test, can't find an installed rustpkg"); + } + } +} + fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { command_line_test_with_env(args, cwd, None) } @@ -240,8 +216,9 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { /// Returns the process's output. fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>) -> ProcessOutput { - let cmd = test_sysroot().push("bin").push("rustpkg").to_str(); - debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str()); + let cmd = rustpkg_exec().to_str(); + debug!("cd %s; %s %s", + cwd.to_str(), cmd, args.connect(" ")); assert!(os::path_is_dir(&*cwd)); let cwd = (*cwd).clone(); let mut prog = run::Process::new(cmd, args, run::ProcessOptions { @@ -263,14 +240,15 @@ So tests that use this need to check the existence of a file to make sure the command succeeded */ if output.status != 0 { - fail!("Command %s %? failed with exit code %?", - cmd, args, output.status); + fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}", + cmd, args, output.status, + str::from_bytes(output.output) + str::from_bytes(output.error)); } output } fn create_local_package(pkgid: &PkgId) -> Path { - let parent_dir = mk_temp_workspace(&pkgid.local_path, &pkgid.version); + let parent_dir = mk_temp_workspace(&pkgid.path, &pkgid.version); debug!("Created empty package dir for %s, returning %s", pkgid.to_str(), parent_dir.to_str()); parent_dir.pop().pop() } @@ -327,26 +305,26 @@ fn create_local_package_with_custom_build_hook(pkgid: &PkgId, } -fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) { +fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version? debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let lib = target_library_in_workspace(&(PkgId { - version: v, ..PkgId::new(short_name, repo)} - ), repo); - debug!("assert_lib_exists: checking whether %s exists", lib.to_str()); - assert!(os::path_exists(&lib)); - assert!(is_rwx(&lib)); + let lib = installed_library_in_workspace(short_name, repo); + debug!("assert_lib_exists: checking whether %? exists", lib); + assert!(lib.is_some()); + let libname = lib.get_ref(); + assert!(os::path_exists(libname)); + assert!(is_rwx(libname)); } fn assert_executable_exists(repo: &Path, short_name: &str) { debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = target_executable_in_workspace(&PkgId::new(short_name, repo), repo); + let exec = target_executable_in_workspace(&PkgId::new(short_name), repo); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); } fn assert_built_executable_exists(repo: &Path, short_name: &str) { debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = built_executable_in_workspace(&PkgId::new(short_name, repo), + let exec = built_executable_in_workspace(&PkgId::new(short_name), repo).expect("assert_built_executable_exists failed"); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); @@ -372,11 +350,11 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~ result } -// assumes short_name and local_path are one and the same -- I should fix +// assumes short_name and path are one and the same -- I should fix fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path { debug!("lib_output_file_name: given %s and parent %s and short name %s", workspace.to_str(), parent, short_name); - library_in_workspace(&normalize(RemotePath(Path(short_name))), + library_in_workspace(&Path(short_name), short_name, Build, workspace, @@ -451,7 +429,7 @@ fn test_install_valid() { debug!("sysroot = %s", sysroot.to_str()); let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path, &NoVersion).pop().pop(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop(); debug!("temp_workspace = %s", temp_workspace.to_str()); // should have test, bench, lib, and main ctxt.install(&temp_workspace, &temp_pkg_id); @@ -504,7 +482,7 @@ fn test_install_git() { let sysroot = test_sysroot(); debug!("sysroot = %s", sysroot.to_str()); let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); + let repo = init_git_repo(&temp_pkg_id.path); let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); writeFile(&repo_subdir.push("main.rs"), "fn main() { let _x = (); }"); @@ -517,9 +495,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 %s in %s", - temp_pkg_id.local_path.to_str(), repo.to_str()); + temp_pkg_id.path.to_str(), repo.to_str()); // should have test, bench, lib, and main - command_line_test([~"install", temp_pkg_id.local_path.to_str()], &repo); + command_line_test([~"install", temp_pkg_id.path.to_str()], &repo); // Check that all files exist debug!("Checking for files in %s", repo.to_str()); let exec = target_executable_in_workspace(&temp_pkg_id, &repo); @@ -563,18 +541,18 @@ fn test_package_ids_must_be_relative_path_like() { */ - let whatever = PkgId::new("foo", &os::getcwd()); + let whatever = PkgId::new("foo"); assert_eq!(~"foo-0.1", whatever.to_str()); - assert!("github.com/catamorphism/test_pkg-0.1" == - PkgId::new("github.com/catamorphism/test-pkg", &os::getcwd()).to_str()); + assert!("github.com/catamorphism/test-pkg-0.1" == + PkgId::new("github.com/catamorphism/test-pkg").to_str()); do cond.trap(|(p, e)| { assert!("" == p.to_str()); assert!("0-length pkgid" == e); whatever.clone() }).inside { - let x = PkgId::new("", &os::getcwd()); + let x = PkgId::new(""); assert_eq!(~"foo-0.1", x.to_str()); } @@ -583,8 +561,7 @@ fn test_package_ids_must_be_relative_path_like() { assert!("absolute pkgid" == e); whatever.clone() }).inside { - let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str(), - &os::getcwd()); + let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str()); assert_eq!(~"foo-0.1", z.to_str()); } @@ -607,7 +584,7 @@ fn test_package_version() { "#[bench] pub fn f() { (); }"); add_git_tag(&repo_subdir, ~"0.4"); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version"); match temp_pkg_id.version { ExactRevision(~"0.4") => (), _ => fail!(fmt!("test_package_version: package version was %?, expected Some(0.4)", @@ -656,7 +633,7 @@ fn test_package_request_version() { } None => false }); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3"); assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust")) == repo.push(".rust").push("bin").push("test_pkg_version")); @@ -696,12 +673,12 @@ fn rustpkg_library_target() { add_git_tag(&package_dir, ~"1.0"); command_line_test([~"install", ~"foo"], &foo_repo); - assert_lib_exists(&foo_repo, "foo", ExactRevision(~"1.0")); + assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0")); } #[test] fn rustpkg_local_pkg() { - let dir = create_local_package(&PkgId::new("foo", &os::getcwd())); + let dir = create_local_package(&PkgId::new("foo")); command_line_test([~"install", ~"foo"], &dir); assert_executable_exists(&dir, "foo"); } @@ -711,7 +688,7 @@ fn rustpkg_local_pkg() { #[test] #[ignore] fn package_script_with_default_build() { - let dir = create_local_package(&PkgId::new("fancy-lib", &os::getcwd())); + let dir = create_local_package(&PkgId::new("fancy-lib")); debug!("dir = %s", dir.to_str()); let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg"). push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs"); @@ -763,7 +740,7 @@ fn rustpkg_clean_no_arg() { command_line_test([~"build"], &package_dir); assert_built_executable_exists(&tmp, "foo"); command_line_test([~"clean"], &package_dir); - assert!(!built_executable_in_workspace(&PkgId::new("foo", &package_dir), + assert!(!built_executable_in_workspace(&PkgId::new("foo"), &tmp).map_default(false, |m| { os::path_exists(m) })); } @@ -771,14 +748,13 @@ fn rustpkg_clean_no_arg() { #[ignore (reason = "Specifying env doesn't work -- see #8028")] fn rust_path_test() { let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed"); - let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion); + let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion); debug!("dir = %s", dir.to_str()); writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }"); let cwd = os::getcwd(); debug!("cwd = %s", cwd.to_str()); - debug!("Running command: cd %s; RUST_LOG=rustpkg RUST_PATH=%s rustpkg install foo", - cwd.to_str(), dir_for_path.to_str()); + // use command_line_test_with_env let mut prog = run::Process::new("rustpkg", [~"install", ~"foo"], run::ProcessOptions { env: Some(&[(~"RUST_LOG", @@ -830,39 +806,38 @@ fn rust_path_parse() { #[test] fn test_list() { let dir = mkdtemp(&os::tmpdir(), "test_list").expect("test_list failed"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); - let bar = PkgId::new("bar", &dir); + let bar = PkgId::new("bar"); create_local_package_in(&bar, &dir); - let quux = PkgId::new("quux", &dir); + let quux = PkgId::new("quux"); create_local_package_in(&quux, &dir); -// NOTE Not really great output, though... -// NOTE do any tests need to be unignored? +// list doesn't output very much right now... command_line_test([~"install", ~"foo"], &dir); let env_arg = ~[(~"RUST_PATH", dir.to_str())]; debug!("RUST_PATH = %s", dir.to_str()); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); command_line_test([~"install", ~"bar"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); command_line_test([~"install", ~"quux"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); - assert!(list_output.iter().any(|x| x.starts_with("libquux_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); + assert!(list_output.iter().any(|x| x.starts_with("quux"))); } #[test] fn install_remove() { let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); - let bar = PkgId::new("bar", &dir); - let quux = PkgId::new("quux", &dir); + let foo = PkgId::new("foo"); + let bar = PkgId::new("bar"); + let quux = PkgId::new("quux"); create_local_package_in(&foo, &dir); create_local_package_in(&bar, &dir); create_local_package_in(&quux, &dir); @@ -887,7 +862,7 @@ fn install_check_duplicates() { // ("Is already installed -- doing nothing") // check invariant that there are no dups in the pkg database let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); command_line_test([~"install", ~"foo"], &dir); @@ -895,7 +870,7 @@ fn install_check_duplicates() { let mut contents = ~[]; let check_dups = |p: &PkgId| { if contents.contains(p) { - fail!("package %s appears in `list` output more than once", p.local_path.to_str()); + fail!("package %s appears in `list` output more than once", p.path.to_str()); } else { contents.push((*p).clone()); @@ -908,7 +883,7 @@ fn install_check_duplicates() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding() { - let p_id = PkgId::new("foo", &os::getcwd()); + let p_id = PkgId::new("foo"); let workspace = create_local_package(&p_id); command_line_test([~"build", ~"foo"], &workspace); let date = datestamp(&built_library_in_workspace(&p_id, @@ -922,8 +897,8 @@ fn no_rebuilding() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding_dep() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, @@ -935,8 +910,8 @@ fn no_rebuilding_dep() { #[test] fn do_rebuild_dep_dates_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -948,8 +923,8 @@ fn do_rebuild_dep_dates_change() { #[test] fn do_rebuild_dep_only_contents_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -962,8 +937,8 @@ fn do_rebuild_dep_only_contents_change() { #[test] fn test_versions() { - let workspace = create_local_package(&PkgId::new("foo#0.1", &os::getcwd())); - create_local_package(&PkgId::new("foo#0.2", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo#0.1")); + create_local_package(&PkgId::new("foo#0.2")); command_line_test([~"install", ~"foo#0.1"], &workspace); let output = command_line_test_output([~"list"]); // make sure output includes versions @@ -973,7 +948,7 @@ fn test_versions() { #[test] #[ignore(reason = "do not yet implemented")] fn test_build_hooks() { - let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo", &os::getcwd()), + let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo"), "frob"); command_line_test([~"do", ~"foo", ~"frob"], &workspace); } @@ -983,7 +958,7 @@ 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(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let output = command_line_test([~"info", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_info); } @@ -992,7 +967,7 @@ fn test_info() { #[ignore(reason = "test not yet implemented")] fn test_rustpkg_test() { let expected_results = ~"1 out of 1 tests passed"; // fill in - let workspace = create_local_package_with_test(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package_with_test(&PkgId::new("foo")); let output = command_line_test([~"test", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_results); } @@ -1000,7 +975,7 @@ fn test_rustpkg_test() { #[test] #[ignore(reason = "test not yet implemented")] fn test_uninstall() { - let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let _output = command_line_test([~"info", ~"foo"], &workspace); command_line_test([~"uninstall", ~"foo"], &workspace); let output = command_line_test([~"list"], &workspace); @@ -1010,8 +985,8 @@ fn test_uninstall() { #[test] fn test_non_numeric_tag() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); - let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); + let repo = init_git_repo(&temp_pkg_id.path); + let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg"); writeFile(&repo_subdir.push("foo"), "foo"); writeFile(&repo_subdir.push("lib.rs"), "pub fn f() { let _x = (); }"); @@ -1021,13 +996,70 @@ fn test_non_numeric_tag() { writeFile(&repo_subdir.push("not_on_testbranch_only"), "bye bye"); add_all_and_commit(&repo_subdir); - - command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.remote_path.to_str())], - &repo); + command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.path.to_str())], &repo); let file1 = repo.push_many(["mockgithub.com", "catamorphism", - "test_pkg", "testbranch_only"]); - let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test_pkg", + "test-pkg", "testbranch_only"]); + let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]); assert!(os::path_exists(&file1)); assert!(!os::path_exists(&file2)); } + +#[test] +fn test_extern_mod() { + let dir = mkdtemp(&os::tmpdir(), "test_extern_mod").expect("test_extern_mod"); + let main_file = dir.push("main.rs"); + let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod"); + let aux_dir = lib_depend_dir.push_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]); + assert!(os::mkdir_recursive(&aux_dir, U_RWX)); + let aux_pkg_file = aux_dir.push("lib.rs"); + + writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); + assert!(os::path_exists(&aux_pkg_file)); + + writeFile(&main_file, + "extern mod test = \"mockgithub.com/catamorphism/test_pkg\";\nuse test::bar;\ + fn main() { bar::assert_true(); }\n"); + + command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir); + + let exec_file = dir.push("out"); + // Be sure to extend the existing environment + let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env()); + let rustpkg_exec = rustpkg_exec(); + let rustc = rustpkg_exec.with_filename("rustc"); + debug!("RUST_PATH=%s %s %s \n --sysroot %s -o %s", + lib_depend_dir.to_str(), + rustc.to_str(), + main_file.to_str(), + test_sysroot().to_str(), + exec_file.to_str()); + + let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(), + ~"--sysroot", test_sysroot().to_str(), + ~"-o", exec_file.to_str()], + run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&dir), + in_fd: None, + out_fd: None, + err_fd: None + }); + let outp = prog.finish_with_output(); + if outp.status != 0 { + fail!("output was %s, error was %s", + str::from_bytes(outp.output), + str::from_bytes(outp.error)); + } + assert!(os::path_exists(&exec_file) && is_executable(&exec_file)); +} + +/// Returns true if p exists and is executable +fn is_executable(p: &Path) -> bool { + use std::libc::consts::os::posix88::{S_IXUSR}; + + match p.get_mode() { + None => false, + Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint + } +} diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 81b47d6a16c..ed21f8e0872 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{os, result}; +use std::os; use rustc::driver::{driver, session}; -use rustc::metadata::filesearch; use extra::getopts::groups::getopts; use syntax::ast_util::*; use syntax::codemap::{dummy_sp, spanned}; @@ -19,10 +18,10 @@ use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::attr::AttrMetaMethods; use rustc::back::link::output_type_exe; use rustc::driver::session::{lib_crate, bin_crate}; -use context::Ctx; +use context::{Ctx, in_target}; use package_id::PkgId; use search::find_library_in_search_path; -use path_util::target_library_in_workspace; +use path_util::{target_library_in_workspace, U_RWX}; pub use target::{OutputType, Main, Lib, Bench, Test}; // It would be nice to have the list of commands in just one place -- for example, @@ -47,13 +46,6 @@ impl ToStr for Pkg { } } -pub fn root() -> Path { - match filesearch::get_rustpkg_root() { - result::Ok(path) => path, - result::Err(err) => fail!(err) - } -} - pub fn is_cmd(cmd: &str) -> bool { COMMANDS.iter().any(|&c| c == cmd) } @@ -162,25 +154,25 @@ pub fn ready_crate(sess: session::Session, pub fn compile_input(ctxt: &Ctx, pkg_id: &PkgId, in_file: &Path, - out_dir: &Path, + workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - let workspace = out_dir.pop().pop(); - assert!(in_file.components.len() > 1); let input = driver::file_input((*in_file).clone()); debug!("compile_input: %s / %?", in_file.to_str(), what); // tjc: by default, use the package ID name as the link name // not sure if we should support anything else + let out_dir = workspace.push("build").push_rel(&pkg_id.path); + let binary = os::args()[0].to_managed(); debug!("flags: %s", flags.connect(" ")); debug!("cfgs: %s", cfgs.connect(" ")); - debug!("compile_input's sysroot = %?", ctxt.sysroot_opt); + debug!("out_dir = %s", out_dir.to_str()); let crate_type = match what { Lib => lib_crate, @@ -196,12 +188,22 @@ pub fn compile_input(ctxt: &Ctx, + flags + cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }), driver::optgroups()).unwrap(); + // Hack so that rustpkg can run either out of a rustc target dir, + // or the host dir + let sysroot_to_use = if !in_target(ctxt.sysroot_opt) { + ctxt.sysroot_opt + } + else { + ctxt.sysroot_opt.map(|p| { @p.pop().pop().pop() }) + }; + debug!("compile_input's sysroot = %?", ctxt.sysroot_opt_str()); + debug!("sysroot_to_use = %?", sysroot_to_use); let options = @session::options { crate_type: crate_type, optimize: if opt { session::Aggressive } else { session::No }, test: what == Test || what == Bench, - maybe_sysroot: ctxt.sysroot_opt, - addl_lib_search_paths: @mut (~[(*out_dir).clone()]), + maybe_sysroot: sysroot_to_use, + addl_lib_search_paths: @mut (~[out_dir.clone()]), // output_type should be conditional output_type: output_type_exe, // Use this to get a library? That's weird .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone() @@ -211,7 +213,12 @@ pub fn compile_input(ctxt: &Ctx, // Make sure all the library directories actually exist, since the linker will complain // otherwise for p in addl_lib_search_paths.iter() { - assert!(os::path_is_dir(p)); + if os::path_exists(p) { + assert!(os::path_is_dir(p)); + } + else { + assert!(os::mkdir_recursive(p, U_RWX)); + } } let sess = driver::build_session(options, diagnostic::emit); @@ -224,35 +231,44 @@ pub fn compile_input(ctxt: &Ctx, // Not really right. Should search other workspaces too, and the installed // database (which doesn't exist yet) - find_and_install_dependencies(ctxt, sess, &workspace, crate, + find_and_install_dependencies(ctxt, sess, workspace, crate, |p| { debug!("a dependency: %s", p.to_str()); // Pass the directory containing a dependency // as an additional lib search path - addl_lib_search_paths.push(p); + if !addl_lib_search_paths.contains(&p) { + // Might be inefficient, but this set probably + // won't get too large -- tjc + addl_lib_search_paths.push(p); + } }); // Inject the link attributes so we get the right package name and version if attr::find_linkage_metas(crate.attrs).is_empty() { - let short_name_to_use = match what { - Test => fmt!("%stest", pkg_id.short_name), - Bench => fmt!("%sbench", pkg_id.short_name), - _ => pkg_id.short_name.clone() + let name_to_use = match what { + Test => fmt!("%stest", pkg_id.short_name).to_managed(), + Bench => fmt!("%sbench", pkg_id.short_name).to_managed(), + _ => pkg_id.short_name.to_managed() }; - debug!("Injecting link name: %s", short_name_to_use); + debug!("Injecting link name: %s", name_to_use); let link_options = - ~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()), - attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())]; - + ~[attr::mk_name_value_item_str(@"name", name_to_use), + attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] + + if pkg_id.is_complex() { + ~[attr::mk_name_value_item_str(@"package_id", + pkg_id.path.to_str().to_managed())] + } else { ~[] }; + + debug!("link options: %?", link_options); crate = @ast::Crate { attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))], .. (*crate).clone() - }; + } } - debug!("calling compile_crate_from_input, out_dir = %s, + debug!("calling compile_crate_from_input, workspace = %s, building_library = %?", out_dir.to_str(), sess.building_library); - compile_crate_from_input(&input, out_dir, sess, crate); + compile_crate_from_input(&input, &out_dir, sess, crate); true } @@ -262,17 +278,22 @@ pub fn compile_input(ctxt: &Ctx, // call compile_upto and return the crate // also, too many arguments pub fn compile_crate_from_input(input: &driver::input, - build_dir: &Path, + // should be of the form <workspace>/build/<pkg id's path> + out_dir: &Path, sess: session::Session, crate: @ast::Crate) { debug!("Calling build_output_filenames with %s, building library? %?", - build_dir.to_str(), sess.building_library); + out_dir.to_str(), sess.building_library); // bad copy - let outputs = driver::build_output_filenames(input, &Some((*build_dir).clone()), &None, + debug!("out_dir = %s", out_dir.to_str()); + let outputs = driver::build_output_filenames(input, &Some(out_dir.clone()), &None, crate.attrs, sess); - debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); + debug!("Outputs are out_filename: %s and obj_filename: %s and output type = %?", + outputs.out_filename.to_str(), + outputs.obj_filename.to_str(), + sess.opts.output_type); debug!("additional libraries:"); for lib in sess.opts.addl_lib_search_paths.iter() { debug!("an additional library: %s", lib.to_str()); @@ -298,15 +319,15 @@ pub fn exe_suffix() -> ~str { ~"" } // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, - crate: &Path, dir: &Path, + crate: &Path, workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); + debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); for fl in flags.iter() { debug!("+++ %s", *fl); } - compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) + compile_input(ctxt, pkg_id, crate, workspace, flags, cfgs, opt, what) } @@ -327,19 +348,20 @@ pub fn find_and_install_dependencies(ctxt: &Ctx, debug!("A view item!"); match vi.node { // ignore metadata, I guess - ast::view_item_extern_mod(lib_ident, _, _) => { + ast::view_item_extern_mod(lib_ident, path_opt, _, _) => { match my_ctxt.sysroot_opt { - Some(ref x) => debug!("sysroot: %s", x.to_str()), + Some(ref x) => debug!("*** sysroot: %s", x.to_str()), None => debug!("No sysroot given") }; - let lib_name = sess.str_of(lib_ident); + let lib_name = match path_opt { // ??? + Some(p) => p, None => sess.str_of(lib_ident) }; match find_library_in_search_path(my_ctxt.sysroot_opt, lib_name) { Some(installed_path) => { debug!("It exists: %s", installed_path.to_str()); } None => { // Try to install it - let pkg_id = PkgId::new(lib_name, &os::getcwd()); + let pkg_id = PkgId::new(lib_name); my_ctxt.install(&my_workspace, &pkg_id); // Also, add an additional search path debug!("let installed_path...") diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 88391850891..ab4f47ba69a 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -15,8 +15,8 @@ extern mod std; use extra::semver; use std::{char, os, result, run, str}; -use package_path::RemotePath; use extra::tempfile::mkdtemp; +use path_util::rust_path; #[deriving(Clone)] pub enum Version { @@ -92,19 +92,22 @@ pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> { } } -/// If `local_path` is a git repo, and the most recent tag in that repo denotes a version, -/// return it; otherwise, `None` +/// If `local_path` is a git repo in the RUST_PATH, and the most recent tag +/// in that repo denotes a version, return it; otherwise, `None` pub fn try_getting_local_version(local_path: &Path) -> Option<Version> { - debug!("in try_getting_local_version"); - let outp = run::process_output("git", + let rustpath = rust_path(); + for rp in rustpath.iter() { + let local_path = rp.push_rel(local_path); + debug!("in try_getting_local_version"); + let outp = run::process_output("git", [fmt!("--git-dir=%s", local_path.push(".git").to_str()), ~"tag", ~"-l"]); - debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); + debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); - if outp.status != 0 { - return None; - } + if outp.status != 0 { + loop; + } let mut output = None; let output_text = str::from_bytes(outp.output); @@ -112,14 +115,19 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> { if !l.is_whitespace() { output = Some(l); } + match output.chain(try_parsing_version) { + Some(v) => return Some(v), + None => () + } } - output.chain(try_parsing_version) + } + None } /// If `remote_path` refers to a git repo that can be downloaded, /// and the most recent tag in that repo denotes a version, return it; /// otherwise, `None` -pub fn try_getting_version(remote_path: &RemotePath) -> Option<Version> { +pub fn try_getting_version(remote_path: &Path) -> Option<Version> { debug!("try_getting_version: %s", remote_path.to_str()); if is_url_like(remote_path) { debug!("Trying to fetch its sources.."); @@ -190,7 +198,7 @@ fn try_parsing_version(s: &str) -> Option<Version> { } /// Just an approximation -fn is_url_like(p: &RemotePath) -> bool { +fn is_url_like(p: &Path) -> bool { let str = p.to_str(); str.split_iter('/').len_() > 2 } diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index d877b4ff489..3e0e08dfe2d 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -12,9 +12,11 @@ use std::os; use std::path::Path; -use path_util::{rust_path, workspace_contains_package_id}; +use path_util::workspace_contains_package_id; use package_id::PkgId; +use rustc::metadata::filesearch::rust_path; + pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain // this package ID @@ -23,7 +25,7 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b // tjc: make this a condition fail!("Package %s not found in any of \ the following workspaces: %s", - pkgid.remote_path.to_str(), + pkgid.path.to_str(), rust_path().to_str()); } for ws in workspaces.iter() { @@ -58,5 +60,5 @@ pub fn cwd_to_workspace() -> (Path, PkgId) { let ws = cwd.pop().pop(); let cwd_ = cwd.clone(); let pkgid = cwd_.components.last().to_str(); - (ws, PkgId::new(pkgid, &cwd)) + (ws, PkgId::new(pkgid)) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 76001ae4188..3e1cb50ce4e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -19,13 +19,14 @@ Cross-platform file path handling use clone::Clone; use container::Container; use cmp::Eq; -use iterator::{Iterator, IteratorUtil}; +use iterator::{Iterator, IteratorUtil, range}; use libc; +use num; use option::{None, Option, Some}; use str::{OwnedStr, Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; -use vec::{OwnedVector, ImmutableVector}; +use vec::{OwnedVector, ImmutableVector, OwnedCopyableVector}; #[cfg(windows)] pub use Path = self::WindowsPath; @@ -124,6 +125,43 @@ pub trait GenericPath { /// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples fn is_ancestor_of(&self, (&Self)) -> bool; + + /// Find the relative path from one file to another + fn get_relative_to(&self, abs2: (&Self)) -> Self { + assert!(self.is_absolute()); + assert!(abs2.is_absolute()); + let abs1 = self.normalize(); + let abs2 = abs2.normalize(); + + let split1: &[~str] = abs1.components(); + let split2: &[~str] = abs2.components(); + let len1 = split1.len(); + let len2 = split2.len(); + assert!(len1 > 0); + assert!(len2 > 0); + + let max_common_path = num::min(len1, len2) - 1; + let mut start_idx = 0; + while start_idx < max_common_path + && split1[start_idx] == split2[start_idx] { + start_idx += 1; + } + + let mut path: ~[~str] = ~[]; + for _ in range(start_idx, len1 - 1) { path.push(~".."); }; + + path.push_all(split2.slice(start_idx, len2 - 1)); + + let mut result: Self = GenericPath::from_str("."); + if !path.is_empty() { + // Without this type hint, the typechecker doesn't seem to like it + let p: Self = GenericPath::from_str(""); + result = p.push_many(path); + }; + result + } + + fn components(self) -> ~[~str]; } #[cfg(target_os = "linux")] @@ -703,6 +741,7 @@ impl GenericPath for PosixPath { self.is_ancestor_of(&other.pop())) } + fn components(self) -> ~[~str] { self.components } } @@ -985,6 +1024,8 @@ impl GenericPath for WindowsPath { (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) && self.is_ancestor_of(&other.pop())) } + + fn components(self) -> ~[~str] { self.components } } pub fn normalize(components: &[~str]) -> ~[~str] { @@ -1341,4 +1382,124 @@ mod tests { } + #[test] + fn test_relative_to1() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + + } + + #[test] + fn test_relative_to2() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/bin/../lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\bin\\..\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to3() { + let p1 = PosixPath("/usr/bin/whatever/rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to4() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to5() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/../mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin/whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\..\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to6() { + let p1 = PosixPath("/1"); + let p2 = PosixPath("/2/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("2")); + + let p1 = WindowsPath("C:\\1"); + let p2 = WindowsPath("C:\\2\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("2")); + + } + + #[test] + fn test_relative_to7() { + let p1 = PosixPath("/1/2"); + let p2 = PosixPath("/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("..")); + + let p1 = WindowsPath("C:\\1\\2"); + let p2 = WindowsPath("C:\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..")); + + } + + #[test] + fn test_relative_to8() { + let p1 = PosixPath("/home/brian/Dev/rust/build/").push_rel( + &PosixPath("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); + let p2 = PosixPath("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( + &PosixPath("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + PosixPath(".").to_str()); + assert_eq!(res, PosixPath(".")); + + let p1 = WindowsPath("C:\\home\\brian\\Dev\\rust\\build\\").push_rel( + &WindowsPath("stage2\\lib\\rustc\\i686-unknown-linux-gnu\\lib\\librustc.so")); + let p2 = WindowsPath("\\home\\brian\\Dev\\rust\\build\\stage2\\bin\\..").push_rel( + &WindowsPath("lib\\rustc\\i686-unknown-linux-gnu\\lib\\libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + WindowsPath(".").to_str()); + assert_eq!(res, WindowsPath(".")); + + } + } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 435be3c71af..17247222c3f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -951,7 +951,11 @@ pub struct view_item { #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum view_item_ { - view_item_extern_mod(ident, ~[@MetaItem], NodeId), + // ident: name used to refer to this crate in the code + // optional @str: if present, this is a location (containing + // arbitrary characters) from which to fetch the crate sources + // For example, extern mod whatever = "github.com/mozilla/rust" + view_item_extern_mod(ident, Option<@str>, ~[@MetaItem], NodeId), view_item_use(~[@view_path]), } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ba167fe6714..9a8a3bc25d8 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -419,7 +419,7 @@ impl Visitor<()> for IdVisitor { fn visit_view_item(@mut self, view_item: &view_item, env: ()) { match view_item.node { - view_item_extern_mod(_, _, node_id) => { + view_item_extern_mod(_, _, _, node_id) => { (self.visit_callback)(node_id) } view_item_use(ref view_paths) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7d6dce22fb7..ddb0e3bfa68 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4181,8 +4181,16 @@ impl Parser { self.this_token_to_str())); } - let (sort, ident) = match *self.token { - token::IDENT(*) => (ast::named, self.parse_ident()), + let (sort, maybe_path, ident) = match *self.token { + token::IDENT(*) => { + let the_ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; + (ast::named, path, the_ident) + } _ => { if must_be_named_mod { self.span_fatal(*self.span, @@ -4191,7 +4199,7 @@ impl Parser { self.this_token_to_str())); } - (ast::anonymous, + (ast::anonymous, None, special_idents::clownshoes_foreign_mod) } }; @@ -4230,7 +4238,7 @@ impl Parser { let metadata = self.parse_optional_meta(); self.expect(&token::SEMI); iovi_view_item(ast::view_item { - node: view_item_extern_mod(ident, metadata, self.get_id()), + node: view_item_extern_mod(ident, maybe_path, metadata, self.get_id()), attrs: attrs, vis: visibility, span: mk_sp(lo, self.last_span.hi) @@ -4812,8 +4820,13 @@ impl Parser { } else if self.eat_keyword(keywords::Extern) { self.expect_keyword(keywords::Mod); let ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; let metadata = self.parse_optional_meta(); - view_item_extern_mod(ident, metadata, self.get_id()) + view_item_extern_mod(ident, path, metadata, self.get_id()) } else { self.bug("expected view item"); }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f517179f603..ffe9575a864 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1856,9 +1856,13 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) { print_outer_attributes(s, item.attrs); print_visibility(s, item.vis); match item.node { - ast::view_item_extern_mod(id, ref mta, _) => { + ast::view_item_extern_mod(id, ref optional_path, ref mta, _) => { head(s, "extern mod"); print_ident(s, id); + for p in optional_path.iter() { + word(s.s, "="); + print_string(s, *p); + } if !mta.is_empty() { popen(s); commasep(s, consistent, *mta, |p, &i| print_meta_item(p, i)); diff --git a/src/test/run-pass/extern-mod-url.rs b/src/test/run-pass/extern-mod-url.rs deleted file mode 100644 index 363c54f6812..00000000000 --- a/src/test/run-pass/extern-mod-url.rs +++ /dev/null @@ -1,16 +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. - -// Just a test that new-style extern mods parse - -// xfail-test FIXME #6407 -extern mod test = "github.com/catamorphism/test-pkg"; - -fn main() {} |
