diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 6d146145f36f1..c0425b4d26064 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -22,11 +22,40 @@ use core::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 the value of RUST_PATH, as a list -/// of Paths. In general this should be read from the -/// environment; for now, it's hard-wired to just be "." +/// 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] { - ~[Path(".")] + let env_path: ~str = os::getenv("RUST_PATH").get_or_default(~""); + let mut env_rust_path: ~[Path] = match os::getenv("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 + env_rust_path.push(copy cwd); + do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; + let h = os::homedir(); + for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); } + env_rust_path } pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index afeb64075335b..8d8628c77181d 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -12,7 +12,7 @@ use context::Ctx; use core::hashmap::HashMap; -use core::{io, libc, os, result, run, str}; +use core::{io, libc, os, result, run, str, vec}; use core::prelude::*; use extra::tempfile::mkdtemp; use core::run::ProcessOutput; @@ -25,7 +25,7 @@ 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}; + installed_library_in_workspace, rust_path}; use target::*; /// Returns the last-modified date as an Option @@ -562,13 +562,58 @@ fn package_script_with_default_build() { } #[test] -#[ignore (reason = "RUST_PATH not yet implemented -- #5682")] +#[ignore (reason = "Un-ignore when #7071 is fixed")] fn rust_path_test() { - let dir = mk_workspace(&Path("/home/more_rust"), - &normalize(RemotePath(Path("foo"))), - &NoVersion); - // command_line_test("RUST_PATH=/home/rust:/home/more_rust rustpkg install foo"); - command_line_test([~"install", ~"foo"], &dir); + 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); + debug!("dir = %s", dir.to_str()); + writeFile(&Path("/Users/tjc/more_rust/src/foo-0.1/main.rs"), + "fn main() { let _x = (); }"); + + let cwd = os::getcwd(); + debug!("cwd = %s", cwd.to_str()); + let mut prog = run::Process::new("rustpkg", + [~"install", ~"foo"], + run::ProcessOptions { env: Some(&[(~"RUST_PATH", + dir_for_path.to_str())]), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + prog.finish_with_output(); + assert_executable_exists(&dir_for_path, "foo"); +} + +#[test] +fn rust_path_contents() { + let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed"); + let abc = &dir.push("A").push("B").push("C"); + assert!(os::mkdir_recursive(&abc.push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), u_rwx)); + assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) { + let p = rust_path(); + let cwd = os::getcwd().push(".rust"); + let parent = cwd.pop().pop().push(".rust"); + let grandparent = cwd.pop().pop().pop().push(".rust"); + assert!(vec::contains(p, &cwd)); + assert!(vec::contains(p, &parent)); + assert!(vec::contains(p, &grandparent)); + for p.iter().advance() |a_path| { + assert!(!a_path.components.is_empty()); + } + }); +} + +#[test] +fn rust_path_parse() { + os::setenv("RUST_PATH", "/a/b/c:/d/e/f:/g/h/i"); + let paths = rust_path(); + assert!(vec::contains(paths, &Path("/g/h/i"))); + assert!(vec::contains(paths, &Path("/d/e/f"))); + assert!(vec::contains(paths, &Path("/a/b/c"))); + os::unsetenv("RUST_PATH"); } #[test] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 700bfff3f5d79..897926940116f 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -382,6 +382,15 @@ impl Path { Some(ref st) => Some(st.st_mode as uint), } } + + /// Execute a function on p as well as all of its ancestors + pub fn each_parent(&self, f: &fn(&Path)) { + if !self.components.is_empty() { + f(self); + self.pop().each_parent(f); + } + } + } #[cfg(target_os = "freebsd")]