diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2013-04-22 17:54:54 -0700 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2013-04-24 17:51:30 -0700 |
| commit | 6a3e26aa4062019629e144196a7852ef039f8b0a (patch) | |
| tree | 47fdbee5268417865977956dd690b9418aa61c7a | |
| parent | c2af1de95b65a0cc2225565f47aa9c08fd072371 (diff) | |
rustpkg: Make path searching work as described in the rustpkg doc
rustpkg now searches for package directories in ./src rather than in . . I also added a rudimentary RUST_PATH that's currently hard-wired to the current directory. rustpkg now uses src/, lib/, and build/ directories as described in the manual. Most of the existing test scenarios build now; the README file (in a separate commit) explains which ones.
| -rw-r--r-- | src/librustpkg/path_util.rs | 168 | ||||
| -rw-r--r-- | src/librustpkg/rustpkg.rc | 158 | ||||
| -rw-r--r-- | src/librustpkg/util.rs | 15 |
3 files changed, 190 insertions, 151 deletions
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index cd9b44c278e..a8931e52747 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -15,39 +15,43 @@ use core::{os, str}; use core::option::*; use util::PkgId; -/// Returns the output directory to use. -/// Right now is always the default, should -/// support changing it. -pub fn dest_dir(pkgid: PkgId) -> Path { - default_dest_dir(&pkgid.path) +#[deriving(Eq)] +pub enum OutputType { Main, Lib, Bench, Test } + +/// 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 "." +pub fn rust_path() -> ~[Path] { + ~[Path(".")] } -/// Returns the default output directory for compilation. -/// Creates that directory if it doesn't exist. -pub fn default_dest_dir(pkg_dir: &Path) -> Path { +/// Creates a directory that is readable, writeable, +/// and executable by the user. Returns true iff creation +/// succeeded. +pub fn make_dir_rwx(p: &Path) -> bool { use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - use conditions::bad_path::cond; - // For now: assumes that pkg_dir exists and is relative - // to the CWD. Change this later when we do path searching. - let rslt = pkg_dir.push("build"); - let is_dir = os::path_is_dir(&rslt); - if os::path_exists(&rslt) { - if is_dir { - rslt - } - else { - cond.raise((rslt, ~"Path names a file that isn't a directory")) - } + os::make_dir(p, (S_IRUSR | S_IWUSR | S_IXUSR) as i32) +} + +/// Creates a directory that is readable, writeable, +/// and executable by the user. Returns true iff creation +/// succeeded. Also creates all intermediate subdirectories +/// if they don't already exist. +pub fn mkdir_recursive(p: &Path) -> bool { + if os::path_is_dir(p) { + return true; + } + let parent = p.dir_path(); + debug!("mkdir_recursive: parent = %s", + parent.to_str()); + if parent.to_str() == ~"." + || parent.to_str() == ~"/" { // !!! + // No parent directories to create + os::path_is_dir(&parent) && make_dir_rwx(p) } else { - // Create it - if os::make_dir(&rslt, (S_IRUSR | S_IWUSR | S_IXUSR) as i32) { - rslt - } - else { - cond.raise((rslt, ~"Could not create directory")) - } + mkdir_recursive(&parent) && make_dir_rwx(p) } } @@ -69,34 +73,94 @@ pub fn normalize(p: ~Path) -> ~Path { } } +// n.b. So far this only handles local workspaces +// n.b. The next three functions ignore the package version right +// now. Should fix that. + +/// True if there's a directory in <workspace> with +/// pkgid's short name +pub fn workspace_contains_package_id(pkgid: PkgId, workspace: &Path) -> bool { + let pkgpath = workspace.push("src").push(pkgid.path.to_str()); + os::path_is_dir(&pkgpath) +} + +/// Return the directory for <pkgid>'s source files in <workspace>. +/// Doesn't check that it exists. +pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + let result = workspace.push("src"); + result.push(pkgid.path.to_str()) +} + +/// Returns the executable that would be installed for <pkgid> +/// in <workspace> +pub fn target_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + let result = workspace.push("bin"); + // should use a target-specific subdirectory + mk_output_path(Main, pkgid.path.to_str(), result) +} + + +/// Returns the executable that would be installed for <pkgid> +/// in <workspace> +pub fn target_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + let result = workspace.push("lib"); + mk_output_path(Lib, pkgid.path.to_str(), result) +} + +/// Returns the test executable that would be installed for <pkgid> +/// in <workspace> +pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + let result = workspace.push("build"); + mk_output_path(Test, pkgid.path.to_str(), result) +} + +/// Returns the bench executable that would be installed for <pkgid> +/// in <workspace> +pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + let result = workspace.push("build"); + mk_output_path(Bench, pkgid.path.to_str(), result) +} + +/// Return the directory for <pkgid>'s build artifacts in <workspace>. +/// Creates it if it doesn't exist. +pub fn build_pkg_id_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { + use conditions::bad_path::cond; + + let mut result = workspace.push("build"); + // n.b. Should actually use a target-specific + // subdirectory of build/ + result = result.push(normalize(~pkgid.path).to_str()); + if os::path_exists(&result) || mkdir_recursive(&result) { + result + } + else { + cond.raise((result, fmt!("Could not create directory for package %s", pkgid.to_str()))) + } +} + +/// Return the output file for a given directory name, +/// given whether we're building a library and whether we're building tests +pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path { + match what { + Lib => dir.push(os::dll_filename(short_name)), + _ => dir.push(fmt!("%s%s%s", short_name, + if what == Test { ~"test" } else { ~"" }, + os::EXE_SUFFIX)) + } +} + #[cfg(test)] mod test { - use core::{os, rand}; - use core::path::Path; - use path_util::*; - use core::rand::RngUtil; - - // Helper function to create a directory name that doesn't exist - pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path { - let r = rand::rng(); - for 1000.times { - let p = tmpdir.push(r.gen_str(16) + suffix); - if !os::path_exists(&p) { - return p; - } - } - fail!(~"Couldn't compute a non-existent path name; this is worrisome") - } + use core::os; #[test] - fn default_dir_ok() { - let the_path = os::tmpdir(); - let substitute_path = Path("xyzzy"); - assert!(default_dest_dir(&the_path) == the_path.push(~"build")); - let nonexistent_path = mk_nonexistent(&the_path, "quux"); - let bogus = do ::conditions::bad_path::cond.trap(|_| { - substitute_path - }).in { default_dest_dir(&nonexistent_path) }; - assert!(bogus == substitute_path); + fn recursive_mkdir_ok() { + let root = os::tmpdir(); + let path = "xy/z/zy"; + let nested = root.push(path); + assert!(super::mkdir_recursive(&nested)); + assert!(os::path_is_dir(&root.push("xy"))); + assert!(os::path_is_dir(&root.push("xy/z"))); + assert!(os::path_is_dir(&nested)); } } diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 705bcc82427..8381e6ad816 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -36,7 +36,8 @@ use rustc::metadata::filesearch; use std::{getopts}; use syntax::{ast, diagnostic}; use util::*; -use path_util::{dest_dir, normalize}; +use path_util::{normalize, workspace_contains_package_id}; +use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, rust_path}; use rustc::driver::session::{lib_crate, bin_crate, crate_type}; mod conditions; @@ -70,7 +71,7 @@ impl PkgScript { /// Given the path name for a package script /// and a package ID, parse the package script into /// a PkgScript that we can then execute - fn parse(script: Path, id: PkgId) -> PkgScript { + fn parse(script: Path, workspace: &Path, id: PkgId) -> PkgScript { // Get the executable name that was invoked let binary = os::args()[0]; // Build the rustc session data structures to pass @@ -85,7 +86,7 @@ impl PkgScript { let cfg = driver::build_configuration(sess, @binary, &input); let (crate, _) = driver::compile_upto(sess, cfg, &input, driver::cu_parse, None); - let work_dir = dest_dir(id); + let work_dir = build_pkg_id_in_workspace(id, workspace); debug!("Returning package script with id %?", id); @@ -193,54 +194,60 @@ impl Ctx { // The package id is presumed to be the first command-line // argument let pkgid = PkgId::new(args[0]); - // Should allow the build directory to be configured. - // Right now it's always the "build" subdirectory in - // the package directory - let dst_dir = dest_dir(pkgid); - debug!("Destination dir = %s", dst_dir.to_str()); - // Right now, we assume the pkgid path is a valid dir - // relative to the CWD. In the future, we should search - // paths - let cwd = os::getcwd().normalize(); - debug!("Current working directory = %s", cwd.to_str()); - - // Create the package source - let mut src = PkgSrc::new(&cwd, &dst_dir, &pkgid); - debug!("Package src = %?", src); - - // Is there custom build logic? If so, use it - let pkg_src_dir = cwd.push_rel(&pkgid.path); - let mut custom = false;; - debug!("Package source directory = %s", pkg_src_dir.to_str()); - let cfgs = match src.package_script_option(&pkg_src_dir) { - Some(package_script_path) => { - let pscript = PkgScript::parse(package_script_path, - pkgid); - // Limited right now -- we're only running the post_build - // hook and probably fail otherwise - // also post_build should be called pre_build - let (cfgs, hook_result) = pscript.run_custom(~"post_build"); - debug!("Command return code = %?", hook_result); - if hook_result != 0 { - fail!(fmt!("Error running custom build command")) + // Using the RUST_PATH, find workspaces that contain + // this package ID + let workspaces = rust_path().filtered(|ws| + workspace_contains_package_id(pkgid, ws)); + if workspaces.is_empty() { + fail!(fmt!("Package %s not found in any of \ + the following workspaces: %s", + pkgid.path.to_str(), + rust_path().to_str())); + } + for workspaces.each |workspace| { + let src_dir = pkgid_src_in_workspace(pkgid, workspace); + let build_dir = build_pkg_id_in_workspace(pkgid, workspace); + debug!("Destination dir = %s", build_dir.to_str()); + + // Create the package source + let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid); + debug!("Package src = %?", src); + + // Is there custom build logic? If so, use it + let pkg_src_dir = src_dir; + let mut custom = false; + debug!("Package source directory = %s", pkg_src_dir.to_str()); + let cfgs = match src.package_script_option(&pkg_src_dir) { + Some(package_script_path) => { + let pscript = PkgScript::parse(package_script_path, + workspace, + pkgid); + // Limited right now -- we're only running the post_build + // hook and probably fail otherwise + // also post_build should be called pre_build + let (cfgs, hook_result) = pscript.run_custom(~"post_build"); + debug!("Command return code = %?", hook_result); + if hook_result != 0 { + fail!(fmt!("Error running custom build command")) + } + custom = true; + // otherwise, the package script succeeded + cfgs } - custom = true; - // otherwise, the package script succeeded - cfgs - } - None => { - debug!("No package script, continuing"); - ~[] + None => { + debug!("No package script, continuing"); + ~[] + } + }; + + // If there was a package script, it should have finished + // the build already. Otherwise... + if !custom { + // Find crates inside the workspace + src.find_crates(); + // Build it! + src.build(&build_dir, cfgs); } - }; - - // If there was a package script, it should have finished - // the build already. Otherwise... - if !custom { - // Find crates inside the workspace - src.find_crates(); - // Build it! - src.build(&dst_dir, cfgs); } } ~"clean" => { @@ -250,8 +257,8 @@ impl Ctx { // The package id is presumed to be the first command-line // argument let pkgid = PkgId::new(args[0]); - - self.clean(pkgid); + let cwd = os::getcwd(); + self.clean(&cwd, pkgid); // tjc: should use workspace, not cwd } ~"do" => { if args.len() < 2 { @@ -304,57 +311,16 @@ impl Ctx { } fn do_cmd(&self, cmd: ~str, pkgname: ~str) { - match cmd { - ~"build" | ~"test" => { - util::error(~"that command cannot be manually called"); - fail!(~"do_cmd"); - } - _ => {} - } - - let cwd = &os::getcwd(); - let pkgid = PkgId::new(pkgname); - // Always use the "build" subdirectory of the package dir, - // but we should allow this to be configured - let dst_dir = dest_dir(pkgid); - - let mut src = PkgSrc::new(cwd, &dst_dir, &pkgid); - match src.package_script_option(cwd) { - Some(script_path) => { - let script = PkgScript::parse(script_path, pkgid); - let (_, status) = script.run_custom(cmd); // Ignore cfgs? - if status == 42 { - util::error(~"no fns are listening for that cmd"); - fail!(~"do_cmd"); - } - } - None => { - util::error(fmt!("invoked `do`, but there is no package script in %s", - cwd.to_str())); - fail!(~"do_cmd"); - } - } - } - - fn build(&self, _dir: &Path, _verbose: bool, _opt: bool, - _test: bool) -> Option<PkgScript> { - // either not needed anymore, - // or needed only when we don't have a package script. Not sure which one. - fail!(); - } - - fn compile(&self, _crate: &Path, _dir: &Path, _flags: ~[~str], - _cfgs: ~[~str], _opt: bool, _test: bool) { - // What's the difference between build and compile? - fail!(~"compile not yet implemented"); + // stub + fail!("`do` not yet implemented"); } - fn clean(&self, id: PkgId) { + fn clean(&self, workspace: &Path, id: PkgId) { // Could also support a custom build hook in the pkg // script for cleaning files rustpkg doesn't know about. // Do something reasonable for now - let dir = dest_dir(id); + let dir = build_pkg_id_in_workspace(id, workspace); util::note(fmt!("Cleaning package %s (removing directory %s)", id.to_str(), dir.to_str())); if os::path_exists(&dir) { diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 2ab1ea1e7d2..36d409adcd2 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -116,7 +116,14 @@ pub impl PkgId { impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - fmt!("%s-%s", self.path.to_str(), self.version.to_str()) + fmt!("%s-%s", self.path.to_str(), + // Replace dots with -s in the version + // this is because otherwise rustc will think + // that foo-0.1 has .1 as its extension + // (Temporary hack until I figure out how to + // get rustc to not name the object file + // foo-0.o if I pass in foo-0.1 to build_output_filenames) + str::replace(self.version.to_str(), ".", "-")) } } @@ -438,7 +445,9 @@ pub fn compile_input(sysroot: Option<Path>, test: bool, crate_type: session::crate_type) -> bool { - let short_name = pkg_id.to_str(); + // Want just the directory component here + let pkg_filename = pkg_id.path.filename().expect(~"Weird pkg id"); + let short_name = fmt!("%s-%s", pkg_filename, pkg_id.version.to_str()); assert!(in_file.components.len() > 1); let input = driver::file_input(copy *in_file); @@ -515,7 +524,7 @@ pub fn compile_crate_from_input(input: driver::input, out_file: Path, binary: ~str, what: driver::compile_upto) -> @ast::crate { - debug!("Calling build_output_filenames with %?", build_dir_opt); + debug!("Calling build_output_filenames with %? and %s", build_dir_opt, out_file.to_str()); let outputs = driver::build_output_filenames(&input, &build_dir_opt, &Some(out_file), sess); debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); let cfg = driver::build_configuration(sess, @binary, &input); |
