about summary refs log tree commit diff
path: root/src/librustpkg/rustpkg.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustpkg/rustpkg.rs')
-rw-r--r--src/librustpkg/rustpkg.rs299
1 files changed, 187 insertions, 112 deletions
diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs
index eef1dcabfd0..7cd30c7af9e 100644
--- a/src/librustpkg/rustpkg.rs
+++ b/src/librustpkg/rustpkg.rs
@@ -22,11 +22,10 @@ extern mod extra;
 extern mod rustc;
 extern mod syntax;
 
-use std::{io, os, result, run, str};
+use std::{io, os, result, run, str, task};
 pub use std::path::Path;
 
 use extra::workcache;
-use extra::arc::RWArc;
 use rustc::driver::{driver, session};
 use rustc::metadata::filesearch;
 use rustc::metadata::filesearch::rust_path;
@@ -45,12 +44,16 @@ use context::{Context, BuildContext,
                        LLVMAssemble, LLVMCompileBitcode};
 use package_id::PkgId;
 use package_source::PkgSrc;
-use workcache_support::{discover_outputs, digest_only_date};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+// use workcache_support::{discover_outputs, digest_only_date};
+use workcache_support::digest_only_date;
+use exit_codes::copy_failed_code;
 
 pub mod api;
 mod conditions;
 mod context;
 mod crate;
+mod exit_codes;
 mod installed_packages;
 mod messages;
 mod package_id;
@@ -172,40 +175,26 @@ impl<'self> PkgScript<'self> {
 pub trait CtxMethods {
     fn run(&self, cmd: &str, args: ~[~str]);
     fn do_cmd(&self, _cmd: &str, _pkgname: &str);
-    fn build_from_src(&self, pkg_src: PkgSrc);
     /// Returns the destination workspace
-    fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
+    fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
     fn clean(&self, workspace: &Path, id: &PkgId);
     fn info(&self);
     /// Returns a pair. First component is a list of installed paths,
     /// second is a list of declared and discovered inputs
-    fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
+    fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
     /// Returns a list of installed files
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path];
+                        id: &PkgId) -> ~[~str];
     fn prefer(&self, _id: &str, _vers: Option<~str>);
     fn test(&self);
     fn uninstall(&self, _id: &str, _vers: Option<~str>);
     fn unprefer(&self, _id: &str, _vers: Option<~str>);
+    fn init(&self);
 }
 
 impl CtxMethods for BuildContext {
-    fn build_from_src(&self, pkg_src: PkgSrc) {
-        let tag = pkg_src.id.to_str();
-        debug!("package source = %s", pkg_src.to_str());
-        do self.workcache_context.with_prep(tag) |prep| {
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            declare_package_script_dependency(prep, &subsrc);
-            pkg_src.declare_inputs(prep);
-            do prep.exec |exec| {
-                subself.build(exec, subsrc.clone());
-            }
-        }
-    }
-
     fn run(&self, cmd: &str, args: ~[~str]) {
         match cmd {
             "build" => {
@@ -214,11 +203,13 @@ impl CtxMethods for BuildContext {
                         None if self.context.use_rust_path_hack => {
                             let cwd = os::getcwd();
                             let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.build_from_src(PkgSrc::new(cwd, true, pkgid));
+                            let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                         None => { usage::build(); return; }
                         Some((ws, pkgid)) => {
-                            self.build_from_src(PkgSrc::new(ws, false, pkgid));
+                            let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                     }
                 }
@@ -229,8 +220,8 @@ impl CtxMethods for BuildContext {
                     do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
                         debug!("found pkg %s in workspace %s, trying to build",
                                pkgid.to_str(), workspace.to_str());
-                        let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
-                        self.build_from_src(pkg_src);
+                        let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+                        self.build(&mut pkg_src, &Everything);
                         true
                     };
                 }
@@ -270,12 +261,12 @@ impl CtxMethods for BuildContext {
                             let cwd = os::getcwd();
                             let inferred_pkgid =
                                 PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.install(PkgSrc::new(cwd, true, inferred_pkgid));
+                            self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
                         }
                         None  => { usage::install(); return; }
                         Some((ws, pkgid))                => {
                             let pkg_src = PkgSrc::new(ws, false, pkgid);
-                            self.install(pkg_src);
+                            self.install(pkg_src, &Everything);
                       }
                   }
                 }
@@ -290,14 +281,14 @@ impl CtxMethods for BuildContext {
                         let rp = rust_path();
                         assert!(!rp.is_empty());
                         let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
-                        self.install(src);
+                        self.install(src, &Everything);
                     }
                     else {
                         for workspace in workspaces.iter() {
                             let src = PkgSrc::new(workspace.clone(),
                                                   self.context.use_rust_path_hack,
                                                   pkgid.clone());
-                            self.install(src);
+                            self.install(src, &Everything);
                         };
                     }
                 }
@@ -319,6 +310,13 @@ impl CtxMethods for BuildContext {
             "test" => {
                 self.test();
             }
+            "init" => {
+                if args.len() != 0 {
+                    return usage::init();
+                } else {
+                    self.init();
+                }
+            }
             "uninstall" => {
                 if args.len() < 1 {
                     return usage::uninstall();
@@ -358,7 +356,9 @@ impl CtxMethods for BuildContext {
 
     /// Returns the destination workspace
     /// In the case of a custom build, we don't know, so we just return the source workspace
-    fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
+    /// what_to_build says: "Just build the lib.rs file in one subdirectory,
+    /// don't walk anything recursively." Or else, everything.
+    fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
         let workspace = pkg_src.workspace.clone();
         let pkgid = pkg_src.id.clone();
 
@@ -376,7 +376,7 @@ impl CtxMethods for BuildContext {
             let default_ws = default_workspace();
             debug!("Calling build recursively with %? and %?", default_ws.to_str(),
                    pkgid.to_str());
-            return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
+            return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
         }
 
         // Is there custom build logic? If so, use it
@@ -387,12 +387,21 @@ impl CtxMethods for BuildContext {
         let cfgs = match pkg_src.package_script_option() {
             Some(package_script_path) => {
                 let sysroot = self.sysroot_to_use();
-                let (cfgs, hook_result) = {
-                    let pscript = PkgScript::parse(@sysroot.clone(),
-                                                   package_script_path.clone(),
-                                                   &workspace.clone(),
-                                                   &pkgid);
-                    pscript.run_custom(exec, &sysroot)
+                let (cfgs, hook_result) =
+                    do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
+                    let sub_sysroot = sysroot.clone();
+                    let package_script_path_clone = package_script_path.clone();
+                    let sub_ws = workspace.clone();
+                    let sub_id = pkgid.clone();
+                    declare_package_script_dependency(prep, &*pkg_src);
+                    do prep.exec |exec| {
+                        let pscript = PkgScript::parse(@sub_sysroot.clone(),
+                                                       package_script_path_clone.clone(),
+                                                       &sub_ws,
+                                                       &sub_id);
+
+                        pscript.run_custom(exec, &sub_sysroot)
+                    }
                 };
                 debug!("Command return code = %?", hook_result);
                 if hook_result != 0 {
@@ -411,10 +420,31 @@ impl CtxMethods for BuildContext {
         // If there was a package script, it should have finished
         // the build already. Otherwise...
         if !custom {
-            // Find crates inside the workspace
-            pkg_src.find_crates();
+            match what_to_build {
+                // Find crates inside the workspace
+                &Everything => pkg_src.find_crates(),
+                // Don't infer any crates -- just build the one that was requested
+                &JustOne(ref p) => {
+                    // We expect that p is relative to the package source's start directory,
+                    // so check that assumption
+                    debug!("JustOne: p = %s", p.to_str());
+                    assert!(os::path_exists(&pkg_src.start_dir.push_rel(p)));
+                    if is_lib(p) {
+                        PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
+                    } else if is_main(p) {
+                        PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
+                    } else if is_test(p) {
+                        PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
+                    } else if is_bench(p) {
+                        PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
+                    } else {
+                        warn(fmt!("Not building any crates for dependency %s", p.to_str()));
+                        return workspace.clone();
+                    }
+                }
+            }
             // Build it!
-            let rs_path = pkg_src.build(exec, self, cfgs);
+            let rs_path = pkg_src.build(self, cfgs);
             Path(rs_path)
         }
         else {
@@ -444,56 +474,54 @@ impl CtxMethods for BuildContext {
         fail!("info not yet implemented");
     }
 
-    fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
-
-        let id = &pkg_src.id;
-
-        let installed_files = RWArc::new(~[]);
-        let inputs = RWArc::new(~[]);
-        // FIXME #7402: Use RUST_PATH to determine target dir
-        self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
-        do self.workcache_context.with_prep(id.to_str()) |prep| {
-            let sub_inputs = inputs.clone();
-            let sub_files  = installed_files.clone();
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            let id_str = id.to_str();
-            let sub_id = id.clone();
-            sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
-                                          { (~"file", (*v).clone()) }));
-            do prep.exec |exec| {
-                let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
-                // See #7402: This still isn't quite right yet; we want to
-                // install to the first workspace in the RUST_PATH if there's
-                // a non-default RUST_PATH. This code installs to the same
-                // workspace the package was built in.
-                let actual_workspace = if path_util::user_set_rust_path() {
-                    default_workspace()
-                }
-                else {
-                    Path(destination_workspace)
-                };
-                debug!("install: destination workspace = %s, id = %s, installing to %s",
-                       destination_workspace, id_str, actual_workspace.to_str());
-                let result = subself.install_no_build(&Path(destination_workspace),
-                                                      &actual_workspace,
-                                                      &sub_id);
-                debug!("install: id = %s, about to call discover_outputs, %?",
-                       id_str, result.to_str());
-
-                discover_outputs(exec, result.clone());
-                sub_files.write(|r| { *r = result.clone(); });
-                sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
-                note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
+    fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
+
+        let id = pkg_src.id.clone();
+
+        let mut installed_files = ~[];
+        let inputs = ~[];
+
+        // workcache only knows about *crates*. Building a package
+        // just means inferring all the crates in it, then building each one.
+        let destination_workspace = self.build(&mut pkg_src, what).to_str();
+
+        let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
+                      pkg_src.tests.clone(), pkg_src.benchs.clone()];
+        debug!("In declare inputs for %s", id.to_str());
+        for cs in to_do.iter() {
+            for c in cs.iter() {
+                let path = pkg_src.start_dir.push_rel(&c.file).normalize();
+                debug!("Recording input: %s", path.to_str());
+                installed_files.push(path);
             }
+        }
+        // See #7402: This still isn't quite right yet; we want to
+        // install to the first workspace in the RUST_PATH if there's
+        // a non-default RUST_PATH. This code installs to the same
+        // workspace the package was built in.
+        let actual_workspace = if path_util::user_set_rust_path() {
+            default_workspace()
+        }
+            else {
+            Path(destination_workspace)
         };
-        (installed_files.unwrap(), inputs.unwrap())
+        debug!("install: destination workspace = %s, id = %s, installing to %s",
+               destination_workspace, id.to_str(), actual_workspace.to_str());
+        let result = self.install_no_build(&Path(destination_workspace),
+                                           &actual_workspace,
+                                           &id).map(|s| Path(*s));
+        debug!("install: id = %s, about to call discover_outputs, %?",
+               id.to_str(), result.to_str());
+        installed_files = installed_files + result;
+        note(fmt!("Installed package %s to %s", id.to_str(), actual_workspace.to_str()));
+        (installed_files, inputs)
     }
 
+    // again, working around lack of Encodable for Path
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path] {
+                        id: &PkgId) -> ~[~str] {
         use conditions::copy_failed::cond;
 
         // Now copy stuff into the install dirs
@@ -503,32 +531,59 @@ impl CtxMethods for BuildContext {
         let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
 
         debug!("target_exec = %s target_lib = %? \
-                maybe_executable = %? maybe_library = %?",
+               maybe_executable = %? maybe_library = %?",
                target_exec.to_str(), target_lib,
                maybe_executable, maybe_library);
 
-        let mut outputs = ~[];
-
-        for exec in maybe_executable.iter() {
-            debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
-            if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
-                 os::copy_file(exec, &target_exec)) {
-                cond.raise(((*exec).clone(), target_exec.clone()));
+        do self.workcache_context.with_prep(id.install_tag()) |prep| {
+            for ee in maybe_executable.iter() {
+                prep.declare_input("binary",
+                                   ee.to_str(),
+                                   workcache_support::digest_only_date(ee));
             }
-            outputs.push(target_exec.clone());
-        }
-        for lib in maybe_library.iter() {
-            let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
-                                                didn't install it!", lib.to_str()));
-            let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib"));
-            debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
-            if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
-                 os::copy_file(lib, &target_lib)) {
-                cond.raise(((*lib).clone(), target_lib.clone()));
+            for ll in maybe_library.iter() {
+                prep.declare_input("binary",
+                                   ll.to_str(),
+                                   workcache_support::digest_only_date(ll));
+            }
+            let subex = maybe_executable.clone();
+            let sublib = maybe_library.clone();
+            let sub_target_ex = target_exec.clone();
+            let sub_target_lib = target_lib.clone();
+
+            do prep.exec |exe_thing| {
+                let mut outputs = ~[];
+
+                for exec in subex.iter() {
+                    debug!("Copying: %s -> %s", exec.to_str(), sub_target_ex.to_str());
+                    if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) &&
+                         os::copy_file(exec, &sub_target_ex)) {
+                        cond.raise(((*exec).clone(), sub_target_ex.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                        sub_target_ex.to_str(),
+                        workcache_support::digest_only_date(&sub_target_ex));
+                    outputs.push(sub_target_ex.to_str());
+                }
+                for lib in sublib.iter() {
+                    let target_lib = sub_target_lib
+                        .clone().expect(fmt!("I built %s but apparently \
+                                             didn't install it!", lib.to_str()));
+                    let target_lib = target_lib
+                        .pop().push(lib.filename().expect("weird target lib"));
+                    debug!("Copying: %s -> %s", lib.to_str(), sub_target_lib.to_str());
+                    if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
+                         os::copy_file(lib, &target_lib)) {
+                        cond.raise(((*lib).clone(), target_lib.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                                              target_lib.to_str(),
+                                              workcache_support::digest_only_date(&target_lib));
+                    outputs.push(target_lib.to_str());
+                }
+                outputs
             }
-            outputs.push(target_lib.clone());
         }
-        outputs
     }
 
     fn prefer(&self, _id: &str, _vers: Option<~str>)  {
@@ -540,6 +595,13 @@ impl CtxMethods for BuildContext {
         fail!("test not yet implemented");
     }
 
+    fn init(&self) {
+        os::mkdir_recursive(&Path("src"),   U_RWX);
+        os::mkdir_recursive(&Path("lib"),   U_RWX);
+        os::mkdir_recursive(&Path("bin"),   U_RWX);
+        os::mkdir_recursive(&Path("build"), U_RWX);
+    }
+
     fn uninstall(&self, _id: &str, _vers: Option<~str>)  {
         fail!("uninstall not yet implemented");
     }
@@ -688,6 +750,7 @@ pub fn main_args(args: &[~str]) {
                     ~"list"    => usage::list(),
                     ~"prefer" => usage::prefer(),
                     ~"test" => usage::test(),
+                    ~"init" => usage::init(),
                     ~"uninstall" => usage::uninstall(),
                     ~"unprefer" => usage::unprefer(),
                     _ => usage::general()
@@ -710,15 +773,27 @@ pub fn main_args(args: &[~str]) {
 
     debug!("Using sysroot: %s", sroot.to_str());
     debug!("Will store workcache in %s", default_workspace().to_str());
-    BuildContext {
-        context: Context {
-        cfgs: cfgs,
-        rustc_flags: rustc_flags,
-        use_rust_path_hack: use_rust_path_hack,
-        sysroot: sroot, // Currently, only tests override this
-    },
-        workcache_context: api::default_context(default_workspace()).workcache_context
-    }.run(*cmd, remaining_args)
+
+    let rm_args = remaining_args.clone();
+    let sub_cmd = cmd.clone();
+    // Wrap the rest in task::try in case of a condition failure in a task
+    let result = do task::try {
+        BuildContext {
+            context: Context {
+                cfgs: cfgs.clone(),
+                rustc_flags: rustc_flags.clone(),
+                use_rust_path_hack: use_rust_path_hack,
+                sysroot: sroot.clone(), // Currently, only tests override this
+            },
+            workcache_context: api::default_context(default_workspace()).workcache_context
+        }.run(sub_cmd, rm_args.clone())
+    };
+    // FIXME #9262: This is using the same error code for all errors,
+    // and at least one test case succeeds if rustpkg returns copy_failed_code,
+    // when actually, it might set the exit code for that even if a different
+    // unhandled condition got raised.
+    if result.is_err() { os::set_exit_status(copy_failed_code); }
+
 }
 
 /**