diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index 6b28b7ed6a1..5f1e0594c47 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -18,11 +18,18 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { for workspaces.iter().advance |p| { let binfiles = os::list_dir(&p.push("bin")); for binfiles.iter().advance() |exec| { - f(&PkgId::new(*exec, p)); + let exec_path = Path(*exec).filestem(); + do exec_path.iter().advance |s| { + f(&PkgId::new(*s, p)) + }; } let libfiles = os::list_dir(&p.push("lib")); for libfiles.iter().advance() |lib| { - f(&PkgId::new(*lib, p)); + debug!("Full name: %s", *lib); + let lib_path = Path(*lib).filestem(); + do lib_path.iter().advance |s| { + f(&PkgId::new(*s, p)) + }; } } true diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index a2cae3ab20e..ed5b1118a9c 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -54,11 +54,17 @@ pub fn rust_path() -> ~[Path] { }; let cwd = os::getcwd(); // now add in default entries - env_rust_path.push(cwd.push(".rust")); env_rust_path.push(cwd.clone()); 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); } + // Avoid adding duplicates + // could still add dups if someone puts one of these in the RUST_PATH + // manually, though... + for h.iter().advance |hdir| { + if !(cwd.is_ancestor_of(hdir) || hdir.is_ancestor_of(&cwd)) { + push_if_exists(&mut env_rust_path, hdir); + } + } env_rust_path } diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index f2845c00ea6..f2e39a8e5ed 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -42,7 +42,7 @@ use path_util::{U_RWX, rust_path, 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; -use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces}; +use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, in_workspace, cwd_to_workspace}; use context::Ctx; use package_id::PkgId; use package_source::PkgSrc; @@ -199,26 +199,41 @@ impl CtxMethods for Ctx { match cmd { "build" => { if args.len() < 1 { - return usage::build(); + if !in_workspace(|| { usage::build() } ) { + return; + } + let (workspace, pkgid) = cwd_to_workspace(); + self.build(&workspace, &pkgid); } - // The package id is presumed to be the first command-line - // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); - for each_pkg_parent_workspace(&pkgid) |workspace| { - debug!("found pkg %s in workspace %s, trying to build", - pkgid.to_str(), workspace.to_str()); - self.build(workspace, &pkgid); + else { + // The package id is presumed to be the first command-line + // argument + let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + for each_pkg_parent_workspace(&pkgid) |workspace| { + debug!("found pkg %s in workspace %s, trying to build", + pkgid.to_str(), workspace.to_str()); + self.build(workspace, &pkgid); + } } } "clean" => { if args.len() < 1 { - return usage::build(); + if !in_workspace(|| { usage::clean() } ) { + return; + } + // tjc: Maybe clean should clean all the packages in the + // current workspace, though? + let (workspace, pkgid) = cwd_to_workspace(); + self.clean(&workspace, &pkgid); + + } + else { + // The package id is presumed to be the first command-line + // argument + let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let cwd = os::getcwd(); + self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd } - // The package id is presumed to be the first command-line - // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); - let cwd = os::getcwd(); - self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd } "do" => { if args.len() < 2 { @@ -232,37 +247,36 @@ impl CtxMethods for Ctx { } "install" => { if args.len() < 1 { - return usage::install(); - } - - // The package id is presumed to be the first command-line - // argument - let pkgid = PkgId::new(args[0], &os::getcwd()); - let workspaces = pkg_parent_workspaces(&pkgid); - if workspaces.is_empty() { - debug!("install! workspaces was empty"); - let rp = rust_path(); - assert!(!rp.is_empty()); - let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]), - &pkgid); - src.fetch_git(); - self.install(&rp[0], &pkgid); + if !in_workspace(|| { usage::install() }) { + return; + } + let (workspace, pkgid) = cwd_to_workspace(); + self.install(&workspace, &pkgid); } else { - for each_pkg_parent_workspace(&pkgid) |workspace| { - debug!("install: found pkg %s in workspace %s, trying to build", - pkgid.to_str(), workspace.to_str()); - - self.install(workspace, &pkgid); + // The package id is presumed to be the first command-line + // argument + let pkgid = PkgId::new(args[0], &os::getcwd()); + 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); + src.fetch_git(); + self.install(&rp[0], &pkgid); + } + else { + for each_pkg_parent_workspace(&pkgid) |workspace| { + self.install(workspace, &pkgid); + } } } } "list" => { io::println("Installed packages:"); for installed_packages::list_installed_packages |pkg_id| { - io::println(fmt!("%s-%s", - pkg_id.local_path.to_str(), - pkg_id.version.to_str())); + io::println(pkg_id.local_path.to_str()); } } "prefer" => { diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index f6044cbf01f..7953d4545a8 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -218,7 +218,6 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { 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(); - let cwd = normalize(RemotePath((*cwd).clone())); debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str()); assert!(os::path_is_dir(&*cwd)); let cwd = (*cwd).clone(); @@ -322,6 +321,14 @@ fn assert_executable_exists(repo: &Path, short_name: &str) { 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), + repo).expect("assert_built_executable_exists failed"); + assert!(os::path_exists(&exec)); + assert!(is_rwx(&exec)); +} + fn command_line_test_output(args: &[~str]) -> ~[~str] { let mut result = ~[]; let p_output = command_line_test(args, &os::getcwd()); @@ -490,30 +497,29 @@ fn test_install_git() { // should have test, bench, lib, and main command_line_test([~"install", temp_pkg_id.local_path.to_str()], &repo); // Check that all files exist - let ws = repo.push(".rust"); - debug!("Checking for files in %s", ws.to_str()); - let exec = target_executable_in_workspace(&temp_pkg_id, &ws); + debug!("Checking for files in %s", repo.to_str()); + let exec = target_executable_in_workspace(&temp_pkg_id, &repo); debug!("exec = %s", exec.to_str()); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); let _built_lib = built_library_in_workspace(&temp_pkg_id, - &ws).expect("test_install_git: built lib should exist"); - let lib = target_library_in_workspace(&temp_pkg_id, &ws); + &repo).expect("test_install_git: built lib should exist"); + let lib = target_library_in_workspace(&temp_pkg_id, &repo); debug!("lib = %s", lib.to_str()); assert!(os::path_exists(&lib)); assert!(is_rwx(&lib)); let built_test = built_test_in_workspace(&temp_pkg_id, - &ws).expect("test_install_git: built test should exist"); + &repo).expect("test_install_git: built test should exist"); assert!(os::path_exists(&built_test)); let built_bench = built_bench_in_workspace(&temp_pkg_id, - &ws).expect("test_install_git: built bench should exist"); + &repo).expect("test_install_git: built bench should exist"); assert!(os::path_exists(&built_bench)); // And that the test and bench executables aren't installed - let test = target_test_in_workspace(&temp_pkg_id, &ws); + let test = target_test_in_workspace(&temp_pkg_id, &repo); assert!(!os::path_exists(&test)); debug!("test = %s", test.to_str()); - let bench = target_bench_in_workspace(&temp_pkg_id, &ws); + let bench = target_bench_in_workspace(&temp_pkg_id, &repo); debug!("bench = %s", bench.to_str()); assert!(!os::path_exists(&bench)); } @@ -586,12 +592,12 @@ fn test_package_version() { command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg_version"], &repo); assert!(match built_library_in_workspace(&temp_pkg_id, - &repo.push(".rust")) { + &repo) { Some(p) => p.to_str().ends_with(fmt!("0.4%s", os::consts::DLL_SUFFIX)), None => false }); - assert!(built_executable_in_workspace(&temp_pkg_id, &repo.push(".rust")) - == Some(repo.push(".rust").push("build"). + assert!(built_executable_in_workspace(&temp_pkg_id, &repo) + == Some(repo.push("build"). push("mockgithub.com"). push("catamorphism"). push("test_pkg_version"). @@ -689,7 +695,7 @@ fn rustpkg_library_target() { add_git_tag(&package_dir, ~"1.0"); command_line_test([~"install", ~"foo"], &foo_repo); - assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0")); + assert_lib_exists(&foo_repo, "foo", ExactRevision(~"1.0")); } #[test] @@ -716,14 +722,55 @@ fn package_script_with_default_build() { assert!(os::path_exists(&dir.push("build").push("fancy_lib").push("generated.rs"))); } +#[test] +fn rustpkg_build_no_arg() { + let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed"); + let package_dir = tmp.push("src").push("foo"); + assert!(os::mkdir_recursive(&package_dir, U_RWX)); + + writeFile(&package_dir.push("main.rs"), + "fn main() { let _x = (); }"); + debug!("build_no_arg: dir = %s", package_dir.to_str()); + command_line_test([~"build"], &package_dir); + assert_built_executable_exists(&tmp, "foo"); +} + +#[test] +fn rustpkg_install_no_arg() { + let tmp = mkdtemp(&os::tmpdir(), + "rustpkg_install_no_arg").expect("rustpkg_build_no_arg failed"); + let package_dir = tmp.push("src").push("foo"); + assert!(os::mkdir_recursive(&package_dir, U_RWX)); + writeFile(&package_dir.push("lib.rs"), + "fn main() { let _x = (); }"); + debug!("install_no_arg: dir = %s", package_dir.to_str()); + command_line_test([~"install"], &package_dir); + assert_lib_exists(&tmp, "foo", NoVersion); +} + +#[test] +fn rustpkg_clean_no_arg() { + let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed"); + let package_dir = tmp.push("src").push("foo"); + assert!(os::mkdir_recursive(&package_dir, U_RWX)); + + writeFile(&package_dir.push("main.rs"), + "fn main() { let _x = (); }"); + debug!("clean_no_arg: dir = %s", package_dir.to_str()); + 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), + &tmp).map_default(false, |m| { os::path_exists(m) })); +} + #[test] #[ignore (reason = "Un-ignore when #7071 is fixed")] 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); debug!("dir = %s", dir.to_str()); - writeFile(&Path("/Users/tjc/more_rust/src/foo-0.1/main.rs"), - "fn main() { let _x = (); }"); + writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }"); let cwd = os::getcwd(); debug!("cwd = %s", cwd.to_str()); @@ -781,21 +828,24 @@ fn test_list() { let quux = PkgId::new("quux", &dir); create_local_package_in(&quux, &dir); +// NOTE Not really great output, though... +// NOTE do any tests need to be unignored? 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("foo-"))); + assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); 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("foo-"))); - assert!(list_output.iter().any(|x| x.starts_with("bar-"))); + assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); + assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); 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("foo-"))); - assert!(list_output.iter().any(|x| x.starts_with("bar-"))); - assert!(list_output.iter().any(|x| x.starts_with("quux-"))); + 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_"))); } #[test] @@ -836,7 +886,7 @@ fn install_check_duplicates() { let mut contents = ~[]; let check_dups = |p: &PkgId| { if contents.contains(p) { - fail!("package database contains duplicate ID"); + fail!("package %s appears in `list` output more than once", p.local_path.to_str()); } else { contents.push((*p).clone()); diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs index 59e9e57d643..87ab3882df1 100644 --- a/src/librustpkg/usage.rs +++ b/src/librustpkg/usage.rs @@ -23,10 +23,11 @@ Options: } pub fn build() { - io::println("rustpkg [options..] build + io::println("rustpkg [options..] build [package-ID] -Build all targets described in the package script in the current -directory. +Build the given package ID if specified. With no package ID argument, +build the package in the current directory. In that case, the current +directory must be a direct child of an `src` directory in a workspace. Options: -c, --cfg Pass a cfg flag to the package script"); diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 5876dbdc9de..952352a02a5 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -10,9 +10,10 @@ // rustpkg utilities having to do with workspaces +use std::os; +use std::path::Path; use path_util::{rust_path, workspace_contains_package_id}; use package_id::PkgId; -use std::path::Path; pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain @@ -38,3 +39,24 @@ pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] { .filter(|ws| workspace_contains_package_id(pkgid, ws)) .collect() } + +pub fn in_workspace(complain: &fn()) -> bool { + let dir_part = os::getcwd().pop().components.clone(); + if *(dir_part.last()) != ~"src" { + complain(); + false + } + else { + true + } +} + +/// Construct a workspace and package-ID name based on the current directory. +/// This gets used when rustpkg gets invoked without a package-ID argument. +pub fn cwd_to_workspace() -> (Path, PkgId) { + let cwd = os::getcwd(); + let ws = cwd.pop().pop(); + let cwd_ = cwd.clone(); + let pkgid = cwd_.components.last().to_str(); + (ws, PkgId::new(pkgid, &cwd)) +} diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fe298931d42..3ec3407b1cc 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -122,6 +122,9 @@ pub trait GenericPath { /// Returns `true` if `self` is an absolute path. fn is_absolute(&self) -> bool; + + /// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples + fn is_ancestor_of(&self, (&Self)) -> bool; } #[cfg(target_os = "linux")] @@ -698,6 +701,15 @@ impl GenericPath for PosixPath { fn is_absolute(&self) -> bool { self.is_absolute } + + fn is_ancestor_of(&self, other: &PosixPath) -> bool { + debug!("%s / %s %? %?", self.to_str(), other.to_str(), self.is_absolute, + self.components.len()); + self == other || + (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) && + self.is_ancestor_of(&other.pop())) + } + } @@ -974,8 +986,13 @@ impl GenericPath for WindowsPath { fn is_absolute(&self) -> bool { self.is_absolute } -} + fn is_ancestor_of(&self, other: &WindowsPath) -> bool { + self == other || + (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) && + self.is_ancestor_of(&other.pop())) + } +} pub fn normalize(components: &[~str]) -> ~[~str] { let mut cs = ~[]; @@ -1290,4 +1307,27 @@ mod tests { assert_eq!(WindowsPath("C:\\COM1.TXT").is_restricted(), true); assert_eq!(WindowsPath("c:\\prn.exe").is_restricted(), true); } + + #[test] + fn test_is_ancestor_of() { + assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d"))); + assert!(!&PosixPath("/a/b/c/d").is_ancestor_of(&PosixPath("/a/b"))); + assert!(!&PosixPath("/a/b").is_ancestor_of(&PosixPath("/c/d"))); + assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d"))); + assert!(&PosixPath("/").is_ancestor_of(&PosixPath("/a/b/c"))); + assert!(!&PosixPath("/").is_ancestor_of(&PosixPath(""))); + assert!(!&PosixPath("/a/b/c").is_ancestor_of(&PosixPath(""))); + assert!(!&PosixPath("").is_ancestor_of(&PosixPath("/a/b/c"))); + + assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d"))); + assert!(!&WindowsPath("C:\\a\\b\\c\\d").is_ancestor_of(&WindowsPath("C:\\a\\b"))); + assert!(!&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\c\\d"))); + assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d"))); + assert!(&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("C:\\a\\b\\c"))); + assert!(!&WindowsPath("C:\\").is_ancestor_of(&WindowsPath(""))); + assert!(!&WindowsPath("C:\\a\\b\\c").is_ancestor_of(&WindowsPath(""))); + assert!(!&WindowsPath("").is_ancestor_of(&WindowsPath("C:\\a\\b\\c"))); + + } + }