about summary refs log tree commit diff
path: root/src/librustpkg
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2013-05-02 13:09:28 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2013-05-03 16:06:07 -0700
commit4d4cabff9ede49ae3642b05c4cfb023a0a9222b2 (patch)
tree18a2cb8d37c681056772201e2115f1b5bb61a7de /src/librustpkg
parentbfd3cd8171bee519093f570264e5a2b1dc17e9d8 (diff)
downloadrust-4d4cabff9ede49ae3642b05c4cfb023a0a9222b2.tar.gz
rust-4d4cabff9ede49ae3642b05c4cfb023a0a9222b2.zip
rustpkg: Implement install command
    The install command should work now, though it only installs
    in-place (anything else has to wait until I implement RUST_PATH).

Also including:
    core: Add remove_directory_recursive, change copy_file

    Make copy_file preserve permissions, and add a remove_directory_recursive
    function.
Diffstat (limited to 'src/librustpkg')
-rw-r--r--src/librustpkg/conditions.rs10
-rw-r--r--src/librustpkg/path_util.rs130
-rw-r--r--src/librustpkg/rustpkg.rc132
-rw-r--r--src/librustpkg/tests.rs71
-rw-r--r--src/librustpkg/util.rs7
5 files changed, 266 insertions, 84 deletions
diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs
index 35e70af7914..5b19a3bd660 100644
--- a/src/librustpkg/conditions.rs
+++ b/src/librustpkg/conditions.rs
@@ -18,5 +18,13 @@ condition! {
 }
 
 condition! {
-    nonexistent_package: (super::PkgId, ~str) -> super::Path;
+    nonexistent_package: (super::PkgId, ~str) -> ();
+}
+
+condition! {
+    copy_failed: (super::Path, super::Path) -> ();
+}
+
+condition! {
+    missing_pkg_files: (super::PkgId) -> ();
 }
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs
index 0490f066f0b..161cb75e9e5 100644
--- a/src/librustpkg/path_util.rs
+++ b/src/librustpkg/path_util.rs
@@ -12,6 +12,7 @@
 
 use util::PkgId;
 use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
+use core::os::mkdir_recursive;
 
 #[deriving(Eq)]
 pub enum OutputType { Main, Lib, Bench, Test }
@@ -23,7 +24,7 @@ pub fn rust_path() -> ~[Path] {
     ~[Path(".")]
 }
 
-static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
+pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
 
 /// Creates a directory that is readable, writeable,
 /// and executable by the user. Returns true iff creation
@@ -70,34 +71,137 @@ pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
     result.push(pkgid.path.to_str())
 }
 
+/// Figure out what the executable name for <pkgid> in <workspace>'s build
+/// directory is, and if the file exists, return it.
+pub fn built_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Option<Path> {
+    let mut result = workspace.push("build");
+    result = result.push_rel(&pkgid.path);
+    // should use a target-specific subdirectory
+    result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()),
+                                       result);
+    debug!("built_executable_in_workspace: checking whether %s exists",
+           result.to_str());
+    if os::path_exists(&result) {
+        Some(result)
+    }
+    else {
+        None
+    }
+}
+
+/// Figure out what the library name for <pkgid> in <workspace>'s build
+/// directory is, and if the file exists, return it.
+pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option<Path> {
+    let mut result = workspace.push("build");
+    result = result.push_rel(&pkgid.path);
+    // should use a target-specific subdirectory
+    result = mk_output_path(Lib, pkgid.path.to_str(), result);
+    debug!("built_library_in_workspace: checking whether %s exists",
+           result.to_str());
+
+    // We don't know what the hash is, so we have to search through the directory
+    // contents
+    let dir_contents = os::list_dir(&result.pop());
+    debug!("dir has %? entries", dir_contents.len());
+
+    // n.b. This code assumes the pkgid's path only has one element
+    let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str());
+    let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX);
+
+    debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
+
+    let mut result_filename = None;
+    for dir_contents.each |&p| {
+        let mut which = 0;
+        let mut hash = None;
+        // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
+        // and remember what the hash was
+        for p.each_split_char('-') |piece| {
+            debug!("a piece = %s", piece);
+            if which == 0 && piece != lib_prefix {
+                break;
+            }
+            else if which == 0 {
+                which += 1;
+            }
+            else if which == 1 {
+                hash = Some(piece.to_owned());
+                which += 1;
+            }
+            else if which == 2 && piece != lib_filetype {
+                hash = None;
+                break;
+            }
+            else if which == 2 {
+                break;
+            }
+            else {
+                // something went wrong
+                hash = None;
+                break;
+            }
+        }
+        if hash.is_some() {
+            result_filename = Some(p);
+            break;
+        }
+    }
+
+    // Return the filename that matches, which we now know exists
+    // (if result_filename != None)
+    debug!("result_filename = %?", result_filename);
+    match result_filename {
+        None => None,
+        Some(result_filename) => {
+            let result_filename = result.with_filename(result_filename);
+            debug!("result_filename = %s", result_filename.to_str());
+            Some(result_filename)
+        }
+    }
+}
+
 /// Returns the executable that would be installed for <pkgid>
 /// in <workspace>
+/// As a side effect, creates the bin-dir if it doesn't exist
 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)
+    target_file_in_workspace(pkgid, workspace, Main)
 }
 
 
 /// Returns the executable that would be installed for <pkgid>
 /// in <workspace>
+/// As a side effect, creates the bin-dir if it doesn't exist
 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)
+    target_file_in_workspace(pkgid, workspace, Lib)
 }
 
 /// 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)
+    target_file_in_workspace(pkgid, workspace, Test)
 }
 
 /// 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)
+    target_file_in_workspace(pkgid, workspace, Bench)
+}
+
+fn target_file_in_workspace(pkgid: PkgId, workspace: &Path,
+                            what: OutputType) -> Path {
+    use conditions::bad_path::cond;
+
+    let (subdir, create_dir) = match what {
+        Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false)
+    };
+    let result = workspace.push(subdir);
+    if create_dir {
+        if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
+            cond.raise((result, fmt!("I couldn't create the %s dir", subdir)));
+        }
+    }
+    mk_output_path(what, pkgid.path.to_str(), result)
+
 }
 
 /// Return the directory for <pkgid>'s build artifacts in <workspace>.
@@ -123,7 +227,11 @@ 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 { ~"" },
+                           match what {
+                               Test => "test",
+                               Bench => "bench",
+                               _     => ""
+                           }
                            os::EXE_SUFFIX))
     }
 }
diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc
index a296f0ca32a..cc74f464e0e 100644
--- a/src/librustpkg/rustpkg.rc
+++ b/src/librustpkg/rustpkg.rc
@@ -34,6 +34,8 @@ use syntax::{ast, diagnostic};
 use util::*;
 use path_util::normalize;
 use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace};
+use path_util::{built_executable_in_workspace, built_library_in_workspace};
+use path_util::{target_executable_in_workspace, target_library_in_workspace};
 use workspace::pkg_parent_workspaces;
 use rustc::driver::session::{lib_crate, bin_crate, crate_type};
 use context::Ctx;
@@ -188,49 +190,7 @@ impl Ctx {
                 // argument
                 let pkgid = PkgId::new(args[0]);
                 for pkg_parent_workspaces(pkgid) |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
-                        }
-                        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);
-                    }
+                    self.build(workspace, pkgid);
                 }
             }
             ~"clean" => {
@@ -304,6 +264,53 @@ impl Ctx {
         fail!(~"`do` not yet implemented");
     }
 
+    fn build(&self, workspace: &Path, pkgid: PkgId) {
+        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
+            }
+            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);
+        }
+
+    }
+
     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.
@@ -325,9 +332,31 @@ impl Ctx {
         fail!(~"info not yet implemented");
     }
 
-    fn install(&self, _workspace: &Path, _id: PkgId)  {
-        // stub
-        fail!(~"install not yet implemented");
+    fn install(&self, workspace: &Path, id: PkgId)  {
+        use conditions::copy_failed::cond;
+
+        // Should use RUST_PATH in the future.
+        // Also should use workcache to not build if not necessary.
+        self.build(workspace, id);
+
+        // Now copy stuff into the install dirs
+        let maybe_executable = built_executable_in_workspace(id, workspace);
+        let maybe_library = built_library_in_workspace(id, workspace);
+        let target_exec = target_executable_in_workspace(id, workspace);
+        let target_lib = target_library_in_workspace(id, workspace);
+
+        for maybe_executable.each |exec| {
+            debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
+            if !os::copy_file(exec, &target_exec) {
+                cond.raise((*exec, target_exec));
+            }
+        }
+        for maybe_library.each |lib| {
+            debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
+            if !os::copy_file(lib, &target_lib) {
+                cond.raise((*lib, target_lib));
+            }
+        }
     }
 
     fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>)  {
@@ -610,7 +639,7 @@ impl PkgSrc {
 
 
     fn check_dir(&self) -> Path {
-        use conditions::bad_path::cond;
+        use conditions::nonexistent_package::cond;
 
         debug!("Pushing onto root: %s | %s", self.id.path.to_str(),
                self.root.to_str());
@@ -620,12 +649,12 @@ impl PkgSrc {
         debug!("Checking dir: %s", dir.to_str());
 
         if !os::path_exists(&dir) {
-            return cond.raise((dir, ~"missing package dir"));
+            cond.raise((self.id, ~"missing package dir"));
         }
 
         if !os::path_is_dir(&dir) {
-            return cond.raise((dir, ~"supplied path for package dir is a \
-                                      non-directory"));
+            cond.raise((self.id, ~"supplied path for package dir is a \
+                                   non-directory"));
         }
 
         dir
@@ -680,6 +709,7 @@ impl PkgSrc {
     /// is no custom build logic
     fn find_crates(&mut self) {
         use PkgSrc::push_crate;
+        use conditions::missing_pkg_files::cond;
 
         let dir = self.check_dir();
         let prefix = dir.components.len();
@@ -704,7 +734,7 @@ impl PkgSrc {
             util::note(~"Couldn't infer any crates to build.\n\
                          Try naming a crate `main.rs`, `lib.rs`, \
                          `test.rs`, or `bench.rs`.");
-            fail!(~"Failed to infer crates to build");
+            cond.raise(self.id);
         }
 
         debug!("found %u libs, %u mains, %u tests, %u benchs",
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index bcee2992e5a..f38fc88f727 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -17,7 +17,8 @@ use std::tempfile::mkdtemp;
 use util::{PkgId, default_version};
 use path_util::{target_executable_in_workspace, target_library_in_workspace,
                target_test_in_workspace, target_bench_in_workspace,
-               make_dir_rwx};
+               make_dir_rwx, u_rwx};
+use core::os::mkdir_recursive;
 
 fn fake_ctxt() -> Ctx {
     Ctx {
@@ -33,8 +34,27 @@ fn fake_pkg() -> PkgId {
     }
 }
 
-fn mk_temp_workspace() -> Path {
-    mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir")
+fn writeFile(file_path: &Path, contents: ~str) {
+    let out: @io::Writer =
+        result::get(&io::file_writer(file_path,
+                                     ~[io::Create, io::Truncate]));
+    out.write_line(contents);
+}
+
+fn mk_temp_workspace(short_name: &Path) -> Path {
+    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
+    let package_dir = workspace.push(~"src").push_rel(short_name);
+    assert!(mkdir_recursive(&package_dir, u_rwx));
+    // Create main, lib, test, and bench files
+    writeFile(&package_dir.push(~"main.rs"),
+              ~"fn main() { let _x = (); }");
+    writeFile(&package_dir.push(~"lib.rs"),
+              ~"pub fn f() { let _x = (); }");
+    writeFile(&package_dir.push(~"test.rs"),
+              ~"#[test] pub fn f() { (); }");
+    writeFile(&package_dir.push(~"bench.rs"),
+              ~"#[bench] pub fn f() { (); }");
+    workspace
 }
 
 fn is_rwx(p: &Path) -> bool {
@@ -42,11 +62,10 @@ fn is_rwx(p: &Path) -> bool {
 
     match p.get_mode() {
         None => return false,
-        Some(m) => {
+        Some(m) =>
             ((m & S_IRUSR as uint) == S_IRUSR as uint
             && (m & S_IWUSR as uint) == S_IWUSR as uint
             && (m & S_IXUSR as uint) == S_IXUSR as uint)
-        }
     }
 }
 
@@ -54,48 +73,60 @@ fn is_rwx(p: &Path) -> bool {
 fn test_make_dir_rwx() {
     let temp = &os::tmpdir();
     let dir = temp.push(~"quux");
-    let _ = os::remove_dir(&dir);
+    assert!(!os::path_exists(&dir) ||
+            os::remove_dir_recursive(&dir));
+    debug!("Trying to make %s", dir.to_str());
     assert!(make_dir_rwx(&dir));
     assert!(os::path_is_dir(&dir));
     assert!(is_rwx(&dir));
-    assert!(os::remove_dir(&dir));
+    assert!(os::remove_dir_recursive(&dir));
 }
 
 #[test]
-#[ignore(reason = "install not yet implemented")]
 fn test_install_valid() {
+    use rustc::metadata::filesearch;
+
+    let sysroot = filesearch::get_rustpkg_sysroot();
+    debug!("sysroot = %s", sysroot.get().to_str());
     let ctxt = fake_ctxt();
     let temp_pkg_id = fake_pkg();
-    let temp_workspace = mk_temp_workspace();
+    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
     // should have test, bench, lib, and main
     ctxt.install(&temp_workspace, temp_pkg_id);
     // Check that all files exist
     let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace);
+    debug!("exec = %s", exec.to_str());
     assert!(os::path_exists(&exec));
     assert!(is_rwx(&exec));
     let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace);
+    debug!("lib = %s", lib.to_str());
     assert!(os::path_exists(&lib));
     assert!(is_rwx(&lib));
     // And that the test and bench executables aren't installed
     assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace)));
-    assert!(!os::path_exists(&target_bench_in_workspace(temp_pkg_id, &temp_workspace)));
+    let bench = target_bench_in_workspace(temp_pkg_id, &temp_workspace);
+    debug!("bench = %s", bench.to_str());
+    assert!(!os::path_exists(&bench));
 }
 
 #[test]
-#[ignore(reason = "install not yet implemented")]
 fn test_install_invalid() {
     use conditions::nonexistent_package::cond;
+    use cond1 = conditions::missing_pkg_files::cond;
 
     let ctxt = fake_ctxt();
     let pkgid = fake_pkg();
-    let temp_workspace = mk_temp_workspace();
-    let expected_path = Path(~"quux");
-    let substituted: Path = do cond.trap(|_| {
-        expected_path
+    let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
+    let mut error_occurred = false;
+    let mut error1_occurred = false;
+    do cond1.trap(|_| {
+        error1_occurred = true;
     }).in {
-        ctxt.install(&temp_workspace, pkgid);
-        // ok
-        fail!(~"test_install_invalid failed, should have raised a condition");
-    };
-    assert!(substituted == expected_path);
+        do cond.trap(|_| {
+            error_occurred = true;
+        }).in {
+            ctxt.install(&temp_workspace, pkgid);
+        }
+    }
+    assert!(error_occurred && error1_occurred);
 }
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 28198e59f86..1b3d72bf6aa 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -477,6 +477,8 @@ pub fn compile_input(sysroot: Option<Path>,
 
     let matches = getopts(~[~"-Z", ~"time-passes"]
                           + if building_library { ~[~"--lib"] }
+                            else if test { ~[~"--test"] }
+                            // bench?
                             else { ~[] }
                           + flags
                           + cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
@@ -540,9 +542,13 @@ pub fn compile_crate_from_input(input: driver::input,
             let (crate, _) = driver::compile_upto(sess, cfg, &input,
                                                   driver::cu_parse, Some(outputs));
 
+            debug!("About to inject link_meta info...");
             // Inject the inferred link_meta info if it's not already there
             // (assumes that name and vers are the only linkage metas)
             let mut crate_to_use = crate;
+
+            debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len());
+
             if attr::find_linkage_metas(crate.node.attrs).is_empty() {
                 crate_to_use = add_attrs(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link",
                                                   // change PkgId to have a <shortname> field?
@@ -552,7 +558,6 @@ pub fn compile_crate_from_input(input: driver::input,
                                                     mk_string_lit(@pkg_id.version.to_str())))])))]);
             }
 
-
             driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use));
             crate_to_use
         }