auto merge of #7419 : catamorphism/rust/default-package, r=graydon

r? @brson `rustpkg build`, if executed in a package source directory inside
a workspace, will now build that package. By "inside a workspace"
I mean that the parent directory has to be called `src`, and rustpkg
will create a `build` directory in .. if there isn't already one.

Same goes for `rustpkg install` and `rustpkg clean`.

For the time being, `rustpkg build` (etc.) will still error out if
you run it inside a directory whose parent isn't called `src`.
I'm not sure whether or not it's desirable to have it do something
in a non-workspace directory.
This commit is contained in:
bors 2013-07-20 02:16:41 -07:00
commit fdbd56ca38
7 changed files with 210 additions and 70 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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" => {

View File

@ -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());

View File

@ -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");

View File

@ -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))
}

View File

@ -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")));
}
}