Skip to content

Commit 1ac7d80

Browse files
committed
auto merge of #8712 : catamorphism/rust/rustpkg-issue-7241, r=pcwalton
r? @brson ...multiple workspaces The test checks that rustpkg uses the first one, rather than complaining about multiple matches. Closes #7241
2 parents 9cd91c8 + 3e4e1a2 commit 1ac7d80

File tree

8 files changed

+122
-43
lines changed

8 files changed

+122
-43
lines changed

src/librustc/metadata/filesearch.rs

+35-18
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ use std::option;
1313
use std::os;
1414
use std::hashmap::HashSet;
1515

16+
pub enum FileMatch { FileMatches, FileDoesntMatch }
17+
1618
// A module for searching for libraries
1719
// FIXME (#2658): I'm not happy how this module turned out. Should
1820
// probably just be folded into cstore.
1921

2022
/// Functions with type `pick` take a parent directory as well as
2123
/// a file found in that directory.
22-
pub type pick<'self, T> = &'self fn(path: &Path) -> Option<T>;
24+
pub type pick<'self> = &'self fn(path: &Path) -> FileMatch;
2325

2426
pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
2527
if path.file_path() == file {
@@ -31,7 +33,7 @@ pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
3133

3234
pub trait FileSearch {
3335
fn sysroot(&self) -> @Path;
34-
fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool;
36+
fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch);
3537
fn get_target_lib_path(&self) -> Path;
3638
fn get_target_lib_file_path(&self, file: &Path) -> Path;
3739
}
@@ -47,34 +49,51 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>,
4749
}
4850
impl FileSearch for FileSearchImpl {
4951
fn sysroot(&self) -> @Path { self.sysroot }
50-
fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
52+
fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch) {
5153
let mut visited_dirs = HashSet::new();
54+
let mut found = false;
5255

5356
debug!("filesearch: searching additional lib search paths [%?]",
5457
self.addl_lib_search_paths.len());
5558
for path in self.addl_lib_search_paths.iter() {
56-
f(path);
59+
match f(path) {
60+
FileMatches => found = true,
61+
FileDoesntMatch => ()
62+
}
5763
visited_dirs.insert(path.to_str());
5864
}
5965

6066
debug!("filesearch: searching target lib path");
6167
let tlib_path = make_target_lib_path(self.sysroot,
6268
self.target_triple);
6369
if !visited_dirs.contains(&tlib_path.to_str()) {
64-
if !f(&tlib_path) {
65-
return false;
70+
match f(&tlib_path) {
71+
FileMatches => found = true,
72+
FileDoesntMatch => ()
6673
}
6774
}
6875
visited_dirs.insert(tlib_path.to_str());
6976
// Try RUST_PATH
70-
let rustpath = rust_path();
71-
for path in rustpath.iter() {
77+
if !found {
78+
let rustpath = rust_path();
79+
for path in rustpath.iter() {
80+
debug!("is %s in visited_dirs? %?",
81+
path.push("lib").to_str(),
82+
visited_dirs.contains(&path.push("lib").to_str()));
83+
7284
if !visited_dirs.contains(&path.push("lib").to_str()) {
73-
f(&path.push("lib"));
7485
visited_dirs.insert(path.push("lib").to_str());
86+
// Don't keep searching the RUST_PATH if one match turns up --
87+
// if we did, we'd get a "multiple matching crates" error
88+
match f(&path.push("lib")) {
89+
FileMatches => {
90+
break;
91+
}
92+
FileDoesntMatch => ()
93+
}
7594
}
95+
}
7696
}
77-
true
7897
}
7998
fn get_target_lib_path(&self) -> Path {
8099
make_target_lib_path(self.sysroot, self.target_triple)
@@ -93,28 +112,26 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>,
93112
} as @FileSearch
94113
}
95114

96-
pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> {
97-
let mut rslt = None;
115+
pub fn search(filesearch: @FileSearch, pick: pick) {
98116
do filesearch.for_each_lib_search_path() |lib_search_path| {
99117
debug!("searching %s", lib_search_path.to_str());
100118
let r = os::list_dir_path(lib_search_path);
119+
let mut rslt = FileDoesntMatch;
101120
for path in r.iter() {
102121
debug!("testing %s", path.to_str());
103122
let maybe_picked = pick(path);
104123
match maybe_picked {
105-
Some(_) => {
124+
FileMatches => {
106125
debug!("picked %s", path.to_str());
107-
rslt = maybe_picked;
108-
break;
126+
rslt = FileMatches;
109127
}
110-
None => {
128+
FileDoesntMatch => {
111129
debug!("rejected %s", path.to_str());
112130
}
113131
}
114132
}
115-
rslt.is_none()
133+
rslt
116134
};
117-
return rslt;
118135
}
119136

120137
pub fn relative_target_lib_path(target_triple: &str) -> Path {

src/librustc/metadata/loader.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
1515
use metadata::decoder;
1616
use metadata::encoder;
17-
use metadata::filesearch::FileSearch;
17+
use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
1818
use metadata::filesearch;
1919
use syntax::codemap::span;
2020
use syntax::diagnostic::span_handler;
@@ -92,10 +92,10 @@ fn find_library_crate_aux(
9292
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
9393
let prefix = fmt!("%s%s-", prefix, crate_name);
9494
let mut matches = ~[];
95-
filesearch::search(filesearch, |path| -> Option<()> {
95+
filesearch::search(filesearch, |path| -> FileMatch {
9696
let path_str = path.filename();
9797
match path_str {
98-
None => None,
98+
None => FileDoesntMatch,
9999
Some(path_str) =>
100100
if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
101101
debug!("%s is a candidate", path.to_str());
@@ -104,20 +104,20 @@ fn find_library_crate_aux(
104104
if !crate_matches(cvec, cx.metas, cx.hash) {
105105
debug!("skipping %s, metadata doesn't match",
106106
path.to_str());
107-
None
107+
FileDoesntMatch
108108
} else {
109109
debug!("found %s with matching metadata", path.to_str());
110110
matches.push((path.to_str(), cvec));
111-
None
111+
FileMatches
112112
},
113113
_ => {
114114
debug!("could not load metadata for %s", path.to_str());
115-
None
115+
FileDoesntMatch
116116
}
117117
}
118118
}
119119
else {
120-
None
120+
FileDoesntMatch
121121
}
122122
}
123123
});

src/librustpkg/path_util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
4949
/// True if there's a directory in <workspace> with
5050
/// pkgid's short name
5151
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
52+
debug!("Checking in src dir of %s for %s",
53+
workspace.to_str(), pkgid.to_str());
54+
5255
let src_dir = workspace.push("src");
5356

5457
let mut found = false;
@@ -81,6 +84,9 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
8184
}
8285
true
8386
};
87+
88+
debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
89+
else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
8490
found
8591
}
8692

src/librustpkg/rustpkg.rs

+2
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ impl CtxMethods for Ctx {
250250
// argument
251251
let pkgid = PkgId::new(args[0]);
252252
let workspaces = pkg_parent_workspaces(&pkgid);
253+
debug!("package ID = %s, found it in %? workspaces",
254+
pkgid.to_str(), workspaces.len());
253255
if workspaces.is_empty() {
254256
let rp = rust_path();
255257
assert!(!rp.is_empty());

src/librustpkg/search.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use path_util::installed_library_in_workspace;
11+
use path_util::{installed_library_in_workspace, rust_path};
12+
use version::Version;
1213

1314
/// If a library with path `p` matching pkg_id's name exists under sroot_opt,
1415
/// return Some(p). Return None if there's no such path or if sroot_opt is None.
@@ -19,3 +20,18 @@ pub fn find_library_in_search_path(sroot_opt: Option<@Path>, short_name: &str) -
1920
installed_library_in_workspace(short_name, sroot)
2021
}
2122
}
23+
24+
/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
25+
/// return Some(p) (returns the first one of there are multiple matches.) Return
26+
/// None if there's no such path.
27+
/// FIXME #8711: This ignores the desired version.
28+
pub fn find_installed_library_in_rust_path(short_name: &str, _version: &Version) -> Option<Path> {
29+
let rp = rust_path();
30+
for p in rp.iter() {
31+
match installed_library_in_workspace(short_name, p) {
32+
Some(path) => return Some(path),
33+
None => ()
34+
}
35+
}
36+
None
37+
}

src/librustpkg/tests.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ fn package_script_with_default_build() {
686686
push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
687687
debug!("package_script_with_default_build: %s", source.to_str());
688688
if !os::copy_file(&source,
689-
& dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
689+
&dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
690690
fail!("Couldn't copy file");
691691
}
692692
command_line_test([~"install", ~"fancy-lib"], &dir);
@@ -890,20 +890,28 @@ fn no_rebuilding_dep() {
890890
assert!(bar_date < foo_date);
891891
}
892892
893+
// n.b. The following two tests are ignored; they worked "accidentally" before,
894+
// when the behavior was "always rebuild libraries" (now it's "never rebuild
895+
// libraries if they already exist"). They can be un-ignored once #7075 is done.
893896
#[test]
897+
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
894898
fn do_rebuild_dep_dates_change() {
895899
let p_id = PkgId::new("foo");
896900
let dep_id = PkgId::new("bar");
897901
let workspace = create_local_package_with_dep(&p_id, &dep_id);
898902
command_line_test([~"build", ~"foo"], &workspace);
899-
let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
903+
let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
904+
let bar_date = datestamp(&bar_lib_name);
905+
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
900906
touch_source_file(&workspace, &dep_id);
901907
command_line_test([~"build", ~"foo"], &workspace);
902-
let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
908+
let new_bar_date = datestamp(&bar_lib_name);
909+
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), new_bar_date);
903910
assert!(new_bar_date > bar_date);
904911
}
905912
906913
#[test]
914+
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
907915
fn do_rebuild_dep_only_contents_change() {
908916
let p_id = PkgId::new("foo");
909917
let dep_id = PkgId::new("bar");
@@ -1060,6 +1068,23 @@ fn test_macro_pkg_script() {
10601068
os::EXE_SUFFIX))));
10611069
}
10621070
1071+
#[test]
1072+
fn multiple_workspaces() {
1073+
// Make a package foo; build/install in directory A
1074+
// Copy the exact same package into directory B and install it
1075+
// Set the RUST_PATH to A:B
1076+
// Make a third package that uses foo, make sure we can build/install it
1077+
let a_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
1078+
let b_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
1079+
debug!("Trying to install foo in %s", a_loc.to_str());
1080+
command_line_test([~"install", ~"foo"], &a_loc);
1081+
debug!("Trying to install foo in %s", b_loc.to_str());
1082+
command_line_test([~"install", ~"foo"], &b_loc);
1083+
let env = Some(~[(~"RUST_PATH", fmt!("%s:%s", a_loc.to_str(), b_loc.to_str()))]);
1084+
let c_loc = create_local_package_with_dep(&PkgId::new("bar"), &PkgId::new("foo"));
1085+
command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
1086+
}
1087+
10631088
/// Returns true if p exists and is executable
10641089
fn is_executable(p: &Path) -> bool {
10651090
use std::libc::consts::os::posix88::{S_IXUSR};

src/librustpkg/util.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ use rustc::back::link::output_type_exe;
2020
use rustc::driver::session::{lib_crate, bin_crate};
2121
use context::{Ctx, in_target};
2222
use package_id::PkgId;
23-
use search::find_library_in_search_path;
23+
use search::{find_library_in_search_path, find_installed_library_in_rust_path};
2424
use path_util::{target_library_in_workspace, U_RWX};
2525
pub use target::{OutputType, Main, Lib, Bench, Test};
26+
use version::NoVersion;
2627

2728
// It would be nice to have the list of commands in just one place -- for example,
2829
// you could update the match in rustpkg.rc but forget to update this list. I think
@@ -360,18 +361,32 @@ pub fn find_and_install_dependencies(ctxt: &Ctx,
360361
debug!("It exists: %s", installed_path.to_str());
361362
}
362363
None => {
363-
// Try to install it
364-
let pkg_id = PkgId::new(lib_name);
365-
my_ctxt.install(&my_workspace, &pkg_id);
366-
// Also, add an additional search path
367-
debug!("let installed_path...")
368-
let installed_path = target_library_in_workspace(&pkg_id,
364+
// FIXME #8711: need to parse version out of path_opt
365+
match find_installed_library_in_rust_path(lib_name, &NoVersion) {
366+
Some(installed_path) => {
367+
debug!("Found library %s, not rebuilding it",
368+
installed_path.to_str());
369+
// Once workcache is implemented, we'll actually check
370+
// whether or not the library at installed_path is fresh
371+
save(installed_path.pop());
372+
}
373+
None => {
374+
debug!("Trying to install library %s, rebuilding it",
375+
lib_name.to_str());
376+
// Try to install it
377+
let pkg_id = PkgId::new(lib_name);
378+
my_ctxt.install(&my_workspace, &pkg_id);
379+
// Also, add an additional search path
380+
debug!("let installed_path...")
381+
let installed_path = target_library_in_workspace(&pkg_id,
369382
&my_workspace).pop();
370-
debug!("Great, I installed %s, and it's in %s",
371-
lib_name, installed_path.to_str());
372-
save(installed_path);
383+
debug!("Great, I installed %s, and it's in %s",
384+
lib_name, installed_path.to_str());
385+
save(installed_path);
386+
}
373387
}
374388
}
389+
}
375390
}
376391
// Ignore `use`s
377392
_ => ()

src/librustpkg/version.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,9 @@ fn is_url_like(p: &Path) -> bool {
213213
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
214214
// Check for extra '#' characters separately
215215
if s.split_iter('#').len() > 2 {
216-
None
217-
}
218-
else {
219-
split_version_general(s, '#')
216+
return None;
220217
}
218+
split_version_general(s, '#')
221219
}
222220

223221
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {

0 commit comments

Comments
 (0)