diff options
Diffstat (limited to 'src/librustpkg/rustpkg.rs')
| -rw-r--r-- | src/librustpkg/rustpkg.rs | 299 | 
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); } + } /** | 
