use std::os;
use std::hashmap::HashSet;
+pub enum FileMatch { FileMatches, FileDoesntMatch }
+
// 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 type pick<'self> = &'self fn(path: &Path) -> FileMatch;
pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
if path.file_path() == file {
pub trait FileSearch {
fn sysroot(&self) -> @Path;
- fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool;
+ fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch);
fn get_target_lib_path(&self) -> Path;
fn get_target_lib_file_path(&self, file: &Path) -> Path;
}
}
impl FileSearch for FileSearchImpl {
fn sysroot(&self) -> @Path { self.sysroot }
- fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
+ fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch) {
let mut visited_dirs = HashSet::new();
+ let mut found = false;
debug!("filesearch: searching additional lib search paths [%?]",
self.addl_lib_search_paths.len());
for path in self.addl_lib_search_paths.iter() {
- f(path);
+ match f(path) {
+ FileMatches => found = true,
+ FileDoesntMatch => ()
+ }
visited_dirs.insert(path.to_str());
}
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;
+ match f(&tlib_path) {
+ FileMatches => found = true,
+ FileDoesntMatch => ()
}
}
visited_dirs.insert(tlib_path.to_str());
// Try RUST_PATH
- let rustpath = rust_path();
- for path in rustpath.iter() {
+ if !found {
+ let rustpath = rust_path();
+ for path in rustpath.iter() {
+ debug!("is %s in visited_dirs? %?",
+ path.push("lib").to_str(),
+ visited_dirs.contains(&path.push("lib").to_str()));
+
if !visited_dirs.contains(&path.push("lib").to_str()) {
- f(&path.push("lib"));
visited_dirs.insert(path.push("lib").to_str());
+ // Don't keep searching the RUST_PATH if one match turns up --
+ // if we did, we'd get a "multiple matching crates" error
+ match f(&path.push("lib")) {
+ FileMatches => {
+ break;
+ }
+ FileDoesntMatch => ()
+ }
}
+ }
}
- true
}
fn get_target_lib_path(&self) -> Path {
make_target_lib_path(self.sysroot, self.target_triple)
} as @FileSearch
}
-pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> {
- let mut rslt = None;
+pub fn search(filesearch: @FileSearch, pick: pick) {
do filesearch.for_each_lib_search_path() |lib_search_path| {
debug!("searching %s", lib_search_path.to_str());
let r = os::list_dir_path(lib_search_path);
+ let mut rslt = FileDoesntMatch;
for path in r.iter() {
debug!("testing %s", path.to_str());
let maybe_picked = pick(path);
match maybe_picked {
- Some(_) => {
+ FileMatches => {
debug!("picked %s", path.to_str());
- rslt = maybe_picked;
- break;
+ rslt = FileMatches;
}
- None => {
+ FileDoesntMatch => {
debug!("rejected %s", path.to_str());
}
}
}
- rslt.is_none()
+ rslt
};
- return rslt;
}
pub fn relative_target_lib_path(target_triple: &str) -> Path {
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
-use metadata::filesearch::FileSearch;
+use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
use metadata::filesearch;
use syntax::codemap::span;
use syntax::diagnostic::span_handler;
// 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<()> {
+ filesearch::search(filesearch, |path| -> FileMatch {
let path_str = path.filename();
match path_str {
- None => None,
+ None => FileDoesntMatch,
Some(path_str) =>
if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
debug!("%s is a candidate", path.to_str());
if !crate_matches(cvec, cx.metas, cx.hash) {
debug!("skipping %s, metadata doesn't match",
path.to_str());
- None
+ FileDoesntMatch
} else {
debug!("found %s with matching metadata", path.to_str());
matches.push((path.to_str(), cvec));
- None
+ FileMatches
},
_ => {
debug!("could not load metadata for %s", path.to_str());
- None
+ FileDoesntMatch
}
}
}
else {
- None
+ FileDoesntMatch
}
}
});
/// True if there's a directory in <workspace> with
/// pkgid's short name
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
+ debug!("Checking in src dir of %s for %s",
+ workspace.to_str(), pkgid.to_str());
+
let src_dir = workspace.push("src");
let mut found = false;
}
true
};
+
+ debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
+ else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
found
}
// argument
let pkgid = PkgId::new(args[0]);
let workspaces = pkg_parent_workspaces(&pkgid);
+ debug!("package ID = %s, found it in %? workspaces",
+ pkgid.to_str(), workspaces.len());
if workspaces.is_empty() {
let rp = rust_path();
assert!(!rp.is_empty());
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use path_util::installed_library_in_workspace;
+use path_util::{installed_library_in_workspace, rust_path};
+use version::Version;
/// If a library with path `p` matching pkg_id's name exists under sroot_opt,
/// return Some(p). Return None if there's no such path or if sroot_opt is None.
installed_library_in_workspace(short_name, sroot)
}
}
+
+/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
+/// return Some(p) (returns the first one of there are multiple matches.) Return
+/// None if there's no such path.
+/// FIXME #8711: This ignores the desired version.
+pub fn find_installed_library_in_rust_path(short_name: &str, _version: &Version) -> Option<Path> {
+ let rp = rust_path();
+ for p in rp.iter() {
+ match installed_library_in_workspace(short_name, p) {
+ Some(path) => return Some(path),
+ None => ()
+ }
+ }
+ None
+}
push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
debug!("package_script_with_default_build: %s", source.to_str());
if !os::copy_file(&source,
- & dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
+ &dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
fail!("Couldn't copy file");
}
command_line_test([~"install", ~"fancy-lib"], &dir);
assert!(bar_date < foo_date);
}
+// n.b. The following two tests are ignored; they worked "accidentally" before,
+// when the behavior was "always rebuild libraries" (now it's "never rebuild
+// libraries if they already exist"). They can be un-ignored once #7075 is done.
#[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
fn do_rebuild_dep_dates_change() {
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"));
+ let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+ let bar_date = datestamp(&bar_lib_name);
+ debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
touch_source_file(&workspace, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+ let new_bar_date = datestamp(&bar_lib_name);
+ debug!("Datestamp on %s is %?", bar_lib_name.to_str(), new_bar_date);
assert!(new_bar_date > bar_date);
}
#[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
fn do_rebuild_dep_only_contents_change() {
let p_id = PkgId::new("foo");
let dep_id = PkgId::new("bar");
os::EXE_SUFFIX))));
}
+#[test]
+fn multiple_workspaces() {
+// Make a package foo; build/install in directory A
+// Copy the exact same package into directory B and install it
+// Set the RUST_PATH to A:B
+// Make a third package that uses foo, make sure we can build/install it
+ let a_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+ let b_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+ debug!("Trying to install foo in %s", a_loc.to_str());
+ command_line_test([~"install", ~"foo"], &a_loc);
+ debug!("Trying to install foo in %s", b_loc.to_str());
+ command_line_test([~"install", ~"foo"], &b_loc);
+ let env = Some(~[(~"RUST_PATH", fmt!("%s:%s", a_loc.to_str(), b_loc.to_str()))]);
+ let c_loc = create_local_package_with_dep(&PkgId::new("bar"), &PkgId::new("foo"));
+ command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
+}
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
use rustc::driver::session::{lib_crate, bin_crate};
use context::{Ctx, in_target};
use package_id::PkgId;
-use search::find_library_in_search_path;
+use search::{find_library_in_search_path, find_installed_library_in_rust_path};
use path_util::{target_library_in_workspace, U_RWX};
pub use target::{OutputType, Main, Lib, Bench, Test};
+use version::NoVersion;
// It would be nice to have the list of commands in just one place -- for example,
// you could update the match in rustpkg.rc but forget to update this list. I think
debug!("It exists: %s", installed_path.to_str());
}
None => {
- // Try to install it
- let pkg_id = PkgId::new(lib_name);
- my_ctxt.install(&my_workspace, &pkg_id);
- // Also, add an additional search path
- debug!("let installed_path...")
- let installed_path = target_library_in_workspace(&pkg_id,
+ // FIXME #8711: need to parse version out of path_opt
+ match find_installed_library_in_rust_path(lib_name, &NoVersion) {
+ Some(installed_path) => {
+ debug!("Found library %s, not rebuilding it",
+ installed_path.to_str());
+ // Once workcache is implemented, we'll actually check
+ // whether or not the library at installed_path is fresh
+ save(installed_path.pop());
+ }
+ None => {
+ debug!("Trying to install library %s, rebuilding it",
+ lib_name.to_str());
+ // Try to install it
+ let pkg_id = PkgId::new(lib_name);
+ my_ctxt.install(&my_workspace, &pkg_id);
+ // Also, add an additional search path
+ debug!("let installed_path...")
+ let installed_path = target_library_in_workspace(&pkg_id,
&my_workspace).pop();
- debug!("Great, I installed %s, and it's in %s",
- lib_name, installed_path.to_str());
- save(installed_path);
+ debug!("Great, I installed %s, and it's in %s",
+ lib_name, installed_path.to_str());
+ save(installed_path);
+ }
}
}
+ }
}
// Ignore `use`s
_ => ()
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
// Check for extra '#' characters separately
if s.split_iter('#').len() > 2 {
- None
- }
- else {
- split_version_general(s, '#')
+ return None;
}
+ split_version_general(s, '#')
}
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {