diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 4f05247ada4b8..f919274f2ed18 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -46,10 +46,10 @@ pub fn run(lib_path: &str, prog: &str, args: &[~str], env: ~[(~str, ~str)], - input: Option<~str>) -> Result { + input: Option<~str>) -> Option { let env = env + target_env(lib_path, prog); - let mut process = run::Process::new(prog, args, run::ProcessOptions { + let mut opt_process = run::Process::new(prog, args, run::ProcessOptions { env: Some(env), dir: None, in_fd: None, @@ -57,15 +57,20 @@ pub fn run(lib_path: &str, err_fd: None }); - for input in input.iter() { - process.input().write(input.as_bytes()); - } - let run::ProcessOutput { status, output, error } = process.finish_with_output(); + match opt_process { + Some(ref mut process) => { + for input in input.iter() { + process.input().write(input.as_bytes()); + } + let run::ProcessOutput { status, output, error } = process.finish_with_output(); - Result { - status: status, - out: str::from_utf8_owned(output), - err: str::from_utf8_owned(error) + Some(Result { + status: status, + out: str::from_utf8_owned(output), + err: str::from_utf8_owned(error) + }) + }, + None => None } } @@ -73,10 +78,10 @@ pub fn run_background(lib_path: &str, prog: &str, args: &[~str], env: ~[(~str, ~str)], - input: Option<~str>) -> run::Process { + input: Option<~str>) -> Option { let env = env + target_env(lib_path, prog); - let mut process = run::Process::new(prog, args, run::ProcessOptions { + let opt_process = run::Process::new(prog, args, run::ProcessOptions { env: Some(env), dir: None, in_fd: None, @@ -84,9 +89,14 @@ pub fn run_background(lib_path: &str, err_fd: None }); - for input in input.iter() { - process.input().write(input.as_bytes()); - } + match opt_process { + Some(mut process) => { + for input in input.iter() { + process.input().write(input.as_bytes()); + } - return process; + Some(process) + }, + None => None + } } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index dae5a1d342b43..136f29765eac7 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -289,20 +289,23 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) { dump_output_file(config, testfile, script_str, "debugger.script"); - procsrv::run("", config.adb_path.clone(), + procsrv::run("", config.adb_path, [~"push", exe_file.as_str().unwrap().to_owned(), config.adb_test_dir.clone()], - ~[(~"",~"")], Some(~"")); + ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); procsrv::run("", config.adb_path, [~"forward", ~"tcp:5039", ~"tcp:5039"], - ~[(~"",~"")], Some(~"")); + ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); let adb_arg = format!("export LD_LIBRARY_PATH={}; gdbserver :5039 {}/{}", config.adb_test_dir.clone(), config.adb_test_dir.clone(), str::from_utf8(exe_file.filename().unwrap())); - let mut process = procsrv::run_background("", config.adb_path.clone(), - [~"shell",adb_arg.clone()],~[(~"",~"")], Some(~"")); + let mut process = procsrv::run_background("", config.adb_path, + [~"shell",adb_arg.clone()],~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); loop { //waiting 1 second for gdbserver start timer::sleep(1000); @@ -334,10 +337,12 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) { let debugger_opts = ~[~"-quiet", ~"-batch", ~"-nx", "-command=" + debugger_script.as_str().unwrap().to_owned()]; + let gdb_path = tool_path.append("/bin/arm-linux-androideabi-gdb"); let procsrv::Result{ out, err, status }= procsrv::run("", - tool_path.append("/bin/arm-linux-androideabi-gdb"), - debugger_opts, ~[(~"",~"")], None); + gdb_path, + debugger_opts, ~[(~"",~"")], None) + .expect(format!("failed to exec `{}`", gdb_path)); let cmdline = { let cmdline = make_cmdline("", "arm-linux-androideabi-gdb", debugger_opts); logv(config, format!("executing {}", cmdline)); @@ -800,7 +805,8 @@ fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str, cmdline }; let procsrv::Result{ out, err, status } = - procsrv::run(lib_path, prog, args, env, input); + procsrv::run(lib_path, prog, args, env, input) + .expect(format!("failed to exec `{}`", prog)); dump_output(config, testfile, out, err); return ProcRes {status: status, stdout: out, @@ -908,7 +914,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, // copy to target let copy_result = procsrv::run("", config.adb_path, [~"push", args.prog.clone(), config.adb_test_dir.clone()], - ~[(~"",~"")], Some(~"")); + ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); if config.verbose { println!("push ({}) {} {} {}", @@ -932,7 +939,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, for tv in args.args.iter() { runargs.push(tv.to_owned()); } - procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")); + procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); // get exitcode of result runargs = ~[]; @@ -942,7 +950,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, let procsrv::Result{ out: exitcode_out, err: _, status: _ } = procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], - Some(~"")); + Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); let mut exitcode : int = 0; for c in exitcode_out.chars() { @@ -960,7 +969,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short)); let procsrv::Result{ out: stdout_out, err: _, status: _ } = - procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")); + procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); // get stderr of result runargs = ~[]; @@ -969,7 +979,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short)); let procsrv::Result{ out: stderr_out, err: _, status: _ } = - procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")); + procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); dump_output(config, testfile, stdout_out, stderr_out); @@ -1004,7 +1015,8 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { // FIXME (#9639): This needs to handle non-utf8 paths let copy_result = procsrv::run("", config.adb_path, [~"push", file.as_str().unwrap().to_owned(), config.adb_test_dir.clone()], - ~[(~"",~"")], Some(~"")); + ~[(~"",~"")], Some(~"")) + .expect(format!("failed to exec `{}`", config.adb_path)); if config.verbose { println!("push ({}) {} {} {}", diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs index c1916714bf283..9cb73ecb07bbb 100644 --- a/src/librustc/back/archive.rs +++ b/src/librustc/back/archive.rs @@ -40,15 +40,25 @@ fn run_ar(sess: Session, args: &str, cwd: Option<&Path>, Some(p) => { debug!("inside {}", p.display()); } None => {} } - let o = Process::new(ar, args.as_slice(), opts).finish_with_output(); - if !o.status.success() { - sess.err(format!("{} {} failed with: {}", ar, args.connect(" "), - o.status)); - sess.note(format!("stdout ---\n{}", str::from_utf8(o.output))); - sess.note(format!("stderr ---\n{}", str::from_utf8(o.error))); - sess.abort_if_errors(); + let mut opt_prog = Process::new(ar, args.as_slice(), opts); + match opt_prog { + Some(ref mut prog) => { + let o = prog.finish_with_output(); + if !o.status.success() { + sess.err(format!("{} {} failed with: {}", ar, args.connect(" "), + o.status)); + sess.note(format!("stdout ---\n{}", str::from_utf8(o.output))); + sess.note(format!("stderr ---\n{}", str::from_utf8(o.error))); + sess.abort_if_errors(); + } + o + }, + None => { + sess.err(format!("could not exec `{}`", ar)); + sess.abort_if_errors(); + fail!("rustc::back::archive::run_ar() should not reach this point"); + } } - o } impl Archive { diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 91680f5c2e568..d67277289d431 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -310,13 +310,19 @@ pub mod write { assembly.as_str().unwrap().to_owned()]; debug!("{} '{}'", cc, args.connect("' '")); - let prog = run::process_output(cc, args); - - if !prog.status.success() { - sess.err(format!("linking with `{}` failed: {}", cc, prog.status)); - sess.note(format!("{} arguments: '{}'", cc, args.connect("' '"))); - sess.note(str::from_utf8_owned(prog.error + prog.output)); - sess.abort_if_errors(); + match run::process_output(cc, args) { + Some(prog) => { + if !prog.status.success() { + sess.err(format!("linking with `{}` failed: {}", cc, prog.status)); + sess.note(format!("{} arguments: '{}'", cc, args.connect("' '"))); + sess.note(str::from_utf8_owned(prog.error + prog.output)); + sess.abort_if_errors(); + } + }, + None => { + sess.err(format!("could not exec `{}`", cc)); + sess.abort_if_errors(); + } } } @@ -949,14 +955,22 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path, // Invoke the system linker debug!("{} {}", cc_prog, cc_args.connect(" ")); - let prog = time(sess.time_passes(), "running linker", (), |()| - run::process_output(cc_prog, cc_args)); - - if !prog.status.success() { - sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status)); - sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '"))); - sess.note(str::from_utf8_owned(prog.error + prog.output)); - sess.abort_if_errors(); + let opt_prog = time(sess.time_passes(), "running linker", (), |()| + run::process_output(cc_prog, cc_args)); + + match opt_prog { + Some(prog) => { + if !prog.status.success() { + sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status)); + sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '"))); + sess.note(str::from_utf8_owned(prog.error + prog.output)); + sess.abort_if_errors(); + } + }, + None => { + sess.err(format!("could not exec `{}`", cc_prog)); + sess.abort_if_errors(); + } } diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index 0d0d0b7c4c79d..8e4216562c0a5 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -142,14 +142,14 @@ pub fn install_pkg(cx: &BuildContext, /// Builds an arbitrary library whose short name is `output`, /// by invoking `tool` with arguments `args` plus "-o %s", where %s /// is the platform-specific library name for `output`. -/// Returns that platform-specific name. +/// Returns that platform-specific name, or None if `tool` could not be started. pub fn build_library_in_workspace(exec: &mut workcache::Exec, context: &mut Context, package_name: &str, tool: &str, flags: &[~str], paths: &[~str], - output: &str) -> ~str { + output: &str) -> Option<~str> { use command_failed = conditions::command_failed::cond; let workspace = my_workspace(context, package_name); @@ -169,16 +169,20 @@ pub fn build_library_in_workspace(exec: &mut workcache::Exec, let all_args = flags + absolute_paths + cc_args + ~[~"-o", out_name.as_str().unwrap().to_owned()]; - let exit_process = run::process_status(tool, all_args); - if exit_process.success() { - let out_name_str = out_name.as_str().unwrap().to_owned(); - exec.discover_output("binary", - out_name_str, - digest_only_date(&out_name)); - context.add_library_path(out_name.dir_path()); - out_name_str - } else { - command_failed.raise((tool.to_owned(), all_args, exit_process)) + match run::process_status(tool, all_args) { + Some(exit_process) => { + if exit_process.success() { + let out_name_str = out_name.as_str().unwrap().to_owned(); + exec.discover_output("binary", + out_name_str, + digest_only_date(&out_name)); + context.add_library_path(out_name.dir_path()); + Some(out_name_str) + } else { + Some(command_failed.raise((tool.to_owned(), all_args, exit_process))) + } + }, + None => None } } diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index cedb21eeb2adf..76d2db0a587e6 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -166,29 +166,47 @@ impl<'a> PkgScript<'a> { /// Run the contents of this package script, where /// is the command to pass to it (e.g., "build", "clean", "install") /// Returns a pair of an exit code and list of configs (obtained by - /// calling the package script's configs() function if it exists - fn run_custom(exe: &Path, sysroot: &Path) -> (~[~str], process::ProcessExit) { + /// calling the package script's configs() function if it exists, or + /// None if `exe` could not be started. + fn run_custom(exe: &Path, sysroot: &Path) -> Option<(~[~str], process::ProcessExit)> { debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(), sysroot.display(), "install"); // FIXME #7401 should support commands besides `install` // FIXME (#9639): This needs to handle non-utf8 paths - let status = run::process_status(exe.as_str().unwrap(), - [sysroot.as_str().unwrap().to_owned(), ~"install"]); - if !status.success() { - debug!("run_custom: first pkg command failed with {:?}", status); - (~[], status) - } - else { - debug!("Running program (configs): {} {} {}", - exe.display(), sysroot.display(), "configs"); - // FIXME (#9639): This needs to handle non-utf8 paths - let output = run::process_output(exe.as_str().unwrap(), - [sysroot.as_str().unwrap().to_owned(), ~"configs"]); - debug!("run_custom: second pkg command did {:?}", output.status); - // Run the configs() function to get the configs - let cfgs = str::from_utf8(output.output).words() - .map(|w| w.to_owned()).collect(); - (cfgs, output.status) + let opt_status = run::process_status(exe.as_str().unwrap(), + [sysroot.as_str().unwrap().to_owned(), ~"install"]); + match opt_status { + Some(status) => { + if !status.success() { + debug!("run_custom: first pkg command failed with {:?}", status); + Some((~[], status)) + } + else { + debug!("Running program (configs): {} {} {}", + exe.display(), sysroot.display(), "configs"); + // FIXME (#9639): This needs to handle non-utf8 paths + let opt_output = run::process_output(exe.as_str().unwrap(), + [sysroot.as_str().unwrap().to_owned(), + ~"configs"]); + match opt_output { + Some(output) => { + debug!("run_custom: second pkg command did {:?}", output.status); + // Run the configs() function to get the configs + let cfgs = str::from_utf8(output.output).words() + .map(|w| w.to_owned()).collect(); + Some((cfgs, output.status)) + }, + None => { + debug!("run_custom: second pkg command failed to start"); + Some((~[], status)) + } + } + } + }, + None => { + debug!("run_custom: first pkg command failed to start"); + None + } } } } @@ -481,14 +499,20 @@ impl CtxMethods for BuildContext { }) }); // We always *run* the package script - let (cfgs, hook_result) = PkgScript::run_custom(&Path::new(pkg_exe), &sysroot); - debug!("Command return code = {:?}", hook_result); - if !hook_result.success() { - fail!("Error running custom build command") + match PkgScript::run_custom(&Path::new(pkg_exe), &sysroot) { + Some((cfgs, hook_result)) => { + debug!("Command return code = {:?}", hook_result); + if !hook_result.success() { + fail!("Error running custom build command") + } + custom = true; + // otherwise, the package script succeeded + cfgs + }, + None => { + fail!("Error starting custom build command") + } } - custom = true; - // otherwise, the package script succeeded - cfgs } (Some(_), Inferred) => { debug!("There is a package script, but we're ignoring it"); @@ -693,9 +717,14 @@ impl CtxMethods for BuildContext { Some(test_exec) => { debug!("test: test_exec = {}", test_exec.display()); // FIXME (#9639): This needs to handle non-utf8 paths - let status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]); - if !status.success() { - fail!("Some tests failed"); + let opt_status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]); + match opt_status { + Some(status) => { + if !status.success() { + fail!("Some tests failed"); + } + }, + None => fail!("Could not exec `{}`", test_exec.display()) } } None => { diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index 702a849e4addd..cbb5503023175 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -33,15 +33,16 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult if !target.exists() { debug!("Running: git clone {} {}", source.display(), target.display()); // FIXME (#9639): This needs to handle non-utf8 paths - let outp = run::process_output("git", [~"clone", - source.as_str().unwrap().to_owned(), - target.as_str().unwrap().to_owned()]); + let opt_outp = run::process_output("git", [~"clone", + source.as_str().unwrap().to_owned(), + target.as_str().unwrap().to_owned()]); + let outp = opt_outp.expect("Failed to exec `git`"); if !outp.status.success() { println(str::from_utf8_owned(outp.output.clone())); println(str::from_utf8_owned(outp.error)); return DirToUse(target.clone()); } - else { + else { match v { &ExactRevision(ref s) => { let git_dir = target.join(".git"); @@ -51,7 +52,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult let outp = run::process_output("git", [format!("--work-tree={}", target.as_str().unwrap().to_owned()), format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()), - ~"checkout", format!("{}", *s)]); + ~"checkout", format!("{}", *s)]).expect("Failed to exec `git`"); if !outp.status.success() { println(str::from_utf8_owned(outp.output.clone())); println(str::from_utf8_owned(outp.error)); @@ -72,7 +73,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult let args = [format!("--work-tree={}", target.as_str().unwrap().to_owned()), format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()), ~"pull", ~"--no-edit", source.as_str().unwrap().to_owned()]; - let outp = run::process_output("git", args); + let opt_outp = run::process_output("git", args); + let outp = opt_outp.expect("Failed to exec `git`"); assert!(outp.status.success()); } CheckedOutSources @@ -108,8 +110,9 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) { use conditions::git_checkout_failed::cond; // FIXME (#9639): This needs to handle non-utf8 paths - let outp = run::process_output("git", [~"clone", source.to_owned(), - target.as_str().unwrap().to_owned()]); + let opt_outp = run::process_output("git", [~"clone", source.to_owned(), + target.as_str().unwrap().to_owned()]); + let outp = opt_outp.expect("Failed to exec `git`"); if !outp.status.success() { debug!("{}", str::from_utf8_owned(outp.output.clone())); debug!("{}", str::from_utf8_owned(outp.error)); @@ -118,8 +121,9 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) { else { match v { &ExactRevision(ref s) | &Tagged(ref s) => { - let outp = process_output_in_cwd("git", [~"checkout", s.to_owned()], + let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()], target); + let outp = opt_outp.expect("Failed to exec `git`"); if !outp.status.success() { debug!("{}", str::from_utf8_owned(outp.output.clone())); debug!("{}", str::from_utf8_owned(outp.error)); @@ -131,10 +135,13 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) { } } -fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput { - let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd) - ,..ProcessOptions::new()}); - prog.finish_with_output() +fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> Option { + let mut opt_prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd) + ,..ProcessOptions::new()}); + match opt_prog { + Some(ref mut prog) => Some(prog.finish_with_output()), + None => None + } } pub fn is_git_dir(p: &Path) -> bool { diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 59fdf20941ec2..28bf8deb5a7d9 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -148,7 +148,7 @@ fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &st in_fd: None, out_fd: None, err_fd: None - }); + }).expect("failed to exec `git`"); let rslt = prog.finish_with_output(); if !rslt.status.success() { fail!("{} [git returned {:?}, output = {}, error = {}]", err_msg, @@ -285,7 +285,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s in_fd: None, out_fd: None, err_fd: None - }); + }).expect(format!("failed to exec `{}`", cmd)); let output = prog.finish_with_output(); debug!("Output from command {} with args {:?} was {} \\{{}\\}[{:?}]", cmd, args, str::from_utf8(output.output), @@ -503,7 +503,8 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) { // n.b. Bumps time up by 2 seconds to get around granularity issues if !run::process_output("touch", [~"--date", ~"+2 seconds", - p.as_str().unwrap().to_owned()]).status.success() { + p.as_str().unwrap().to_owned()]) + .expect("failed to exec `touch`").status.success() { let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path")); } } @@ -521,7 +522,8 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) { // FIXME (#9639): This needs to handle non-utf8 paths // n.b. Bumps time up by 2 seconds to get around granularity issues if !run::process_output("touch", [~"-A02", - p.as_str().unwrap().to_owned()]).status.success() { + p.as_str().unwrap().to_owned()]) + .expect("failed to exec `touch`").status.success() { let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path")); } } @@ -1276,7 +1278,7 @@ fn test_extern_mod() { in_fd: None, out_fd: None, err_fd: None - }); + }).expect(format!("failed to exec `{}`", rustc.as_str().unwrap())); let outp = prog.finish_with_output(); if !outp.status.success() { fail!("output was {}, error was {}", @@ -1331,7 +1333,7 @@ fn test_extern_mod_simpler() { in_fd: None, out_fd: None, err_fd: None - }); + }).expect(format!("failed to exec `{}`", rustc.as_str().unwrap())); let outp = prog.finish_with_output(); if !outp.status.success() { fail!("output was {}, error was {}", diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index ba6cf5f513b77..e9ccfccb126a1 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -104,8 +104,9 @@ pub fn try_getting_local_version(local_path: &Path) -> Option { continue; } // FIXME (#9639): This needs to handle non-utf8 paths - let outp = run::process_output("git", + let opt_outp = run::process_output("git", ["--git-dir=" + git_dir.as_str().unwrap(), ~"tag", ~"-l"]); + let outp = opt_outp.expect("Failed to exec `git`"); debug!("git --git-dir={} tag -l ~~~> {:?}", git_dir.display(), outp.status); @@ -140,9 +141,10 @@ pub fn try_getting_version(remote_path: &Path) -> Option { remote_path.display(), tmp_dir.display()); // FIXME (#9639): This needs to handle non-utf8 paths - let outp = run::process_output("git", [~"clone", format!("https://{}", - remote_path.as_str().unwrap()), - tmp_dir.as_str().unwrap().to_owned()]); + let opt_outp = run::process_output("git", [~"clone", format!("https://{}", + remote_path.as_str().unwrap()), + tmp_dir.as_str().unwrap().to_owned()]); + let outp = opt_outp.expect("Failed to exec `git`"); if outp.status.success() { debug!("Cloned it... ( {}, {} )", str::from_utf8(outp.output), @@ -152,9 +154,10 @@ pub fn try_getting_version(remote_path: &Path) -> Option { debug!("(getting version, now getting tags) executing \\{git --git-dir={} tag -l\\}", git_dir.display()); // FIXME (#9639): This needs to handle non-utf8 paths - let outp = run::process_output("git", - ["--git-dir=" + git_dir.as_str().unwrap(), - ~"tag", ~"-l"]); + let opt_outp = run::process_output("git", + ["--git-dir=" + git_dir.as_str().unwrap(), + ~"tag", ~"-l"]); + let outp = opt_outp.expect("Failed to exec `git`"); let output_text = str::from_utf8(outp.output); debug!("Full output: ( {} ) [{:?}]", output_text, outp.status); for l in output_text.lines() { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 754c02e308f1b..14d49df59a4c6 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -119,7 +119,7 @@ impl Process { * * options - Options to configure the environment of the process, * the working directory and the standard IO streams. */ - pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Process { + pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Option { let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options; let env = env.as_ref().map(|a| a.as_slice()); let cwd = dir.as_ref().map(|a| a.as_str().unwrap()); @@ -138,8 +138,10 @@ impl Process { cwd: cwd, io: rtio, }; - let inner = process::Process::new(rtconfig).unwrap(); - Process { inner: inner } + match process::Process::new(rtconfig) { + Some(inner) => Some(Process { inner: inner }), + None => None + } } /// Returns the unique id of the process @@ -290,17 +292,20 @@ impl Process { * * # Return value * - * The process's exit code + * The process's exit code, or None if the child process could not be started */ -pub fn process_status(prog: &str, args: &[~str]) -> ProcessExit { - let mut prog = Process::new(prog, args, ProcessOptions { +pub fn process_status(prog: &str, args: &[~str]) -> Option { + let mut opt_prog = Process::new(prog, args, ProcessOptions { env: None, dir: None, in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }), out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }), err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) }) }); - prog.finish() + match opt_prog { + Some(ref mut prog) => Some(prog.finish()), + None => None + } } /** @@ -313,11 +318,15 @@ pub fn process_status(prog: &str, args: &[~str]) -> ProcessExit { * * # Return value * - * The process's stdout/stderr output and exit code. + * The process's stdout/stderr output and exit code, or None if the child process could not be + * started. */ -pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput { - let mut prog = Process::new(prog, args, ProcessOptions::new()); - prog.finish_with_output() +pub fn process_output(prog: &str, args: &[~str]) -> Option { + let mut opt_prog = Process::new(prog, args, ProcessOptions::new()); + match opt_prog { + Some(ref mut prog) => Some(prog.finish_with_output()), + None => None + } } #[cfg(test)] @@ -331,24 +340,36 @@ mod tests { use task::spawn; use unstable::running_on_valgrind; use io::native::file; - use io::{Writer, Reader}; + use io::{Writer, Reader, io_error}; #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_process_status() { - let mut status = run::process_status("false", []); + let mut status = run::process_status("false", []).expect("failed to exec `false`"); assert!(status.matches_exit_status(1)); - status = run::process_status("true", []); + status = run::process_status("true", []).expect("failed to exec `true`"); assert!(status.success()); } + #[test] + fn test_process_output_fail_to_start() { + let mut trapped_io_error = false; + let opt_outp = io_error::cond.trap(|_| { + trapped_io_error = true; + }).inside(|| -> Option { + run::process_output("no-binary-by-this-name-should-exist", []) + }); + assert!(trapped_io_error); + assert!(opt_outp.is_none()); + } + #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_process_output_output() { let run::ProcessOutput {status, output, error} - = run::process_output("echo", [~"hello"]); + = run::process_output("echo", [~"hello"]).expect("failed to exec `echo`"); let output_str = str::from_utf8_owned(output); assert!(status.success()); @@ -364,7 +385,7 @@ mod tests { fn test_process_output_error() { let run::ProcessOutput {status, output, error} - = run::process_output("mkdir", [~"."]); + = run::process_output("mkdir", [~"."]).expect("failed to exec `mkdir`"); assert!(status.matches_exit_status(1)); assert_eq!(output, ~[]); @@ -385,7 +406,7 @@ mod tests { in_fd: Some(pipe_in.input), out_fd: Some(pipe_out.out), err_fd: Some(pipe_err.out) - }); + }).expect("failed to exec `cat`"); os::close(pipe_in.input); os::close(pipe_out.out); @@ -422,14 +443,16 @@ mod tests { #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_once() { - let mut prog = run::Process::new("false", [], run::ProcessOptions::new()); + let mut prog = run::Process::new("false", [], run::ProcessOptions::new()) + .expect("failed to exec `false`"); assert!(prog.finish().matches_exit_status(1)); } #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_twice() { - let mut prog = run::Process::new("false", [], run::ProcessOptions::new()); + let mut prog = run::Process::new("false", [], run::ProcessOptions::new()) + .expect("failed to exec `false`"); assert!(prog.finish().matches_exit_status(1)); assert!(prog.finish().matches_exit_status(1)); } @@ -438,7 +461,8 @@ mod tests { #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_with_output_once() { - let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()); + let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()) + .expect("failed to exec `echo`"); let run::ProcessOutput {status, output, error} = prog.finish_with_output(); let output_str = str::from_utf8_owned(output); @@ -455,7 +479,8 @@ mod tests { #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_with_output_twice() { - let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()); + let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()) + .expect("failed to exec `echo`"); let run::ProcessOutput {status, output, error} = prog.finish_with_output(); @@ -484,14 +509,14 @@ mod tests { run::Process::new("pwd", [], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }) + }).expect("failed to exec `pwd`") } #[cfg(unix,target_os="android")] fn run_pwd(dir: Option<&Path>) -> run::Process { run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }) + }).expect("failed to exec `/system/bin/sh`") } #[cfg(windows)] @@ -499,7 +524,7 @@ mod tests { run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }) + }).expect("failed to run `cmd`") } #[test] @@ -539,14 +564,14 @@ mod tests { run::Process::new("env", [], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }) + }).expect("failed to exec `env`") } #[cfg(unix,target_os="android")] fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process { run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }) + }).expect("failed to exec `/system/bin/sh`") } #[cfg(windows)] @@ -554,7 +579,7 @@ mod tests { run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }) + }).expect("failed to run `cmd`") } #[test] diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 05f74ca8373ee..4b7ab09e152b0 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -27,7 +27,8 @@ fn test_destroy_once() { #[cfg(target_os="android")] static PROG: &'static str = "ls"; // android don't have echo binary - let mut p = run::Process::new(PROG, [], run::ProcessOptions::new()); + let mut p = run::Process::new(PROG, [], run::ProcessOptions::new()) + .expect(format!("failed to exec `{}`", PROG)); p.destroy(); // this shouldn't crash (and nor should the destructor) } @@ -38,7 +39,8 @@ fn test_destroy_twice() { #[cfg(target_os="android")] static PROG: &'static str = "ls"; // android don't have echo binary - let mut p = run::Process::new(PROG, [], run::ProcessOptions::new()); + let mut p = run::Process::new(PROG, [], run::ProcessOptions::new()) + .expect(format!("failed to exec `{}`", PROG)); p.destroy(); // this shouldnt crash... io::io_error::cond.trap(|_| {}).inside(|| { p.destroy(); // ...and nor should this (and nor should the destructor) @@ -58,13 +60,15 @@ fn test_destroy_actually_kills(force: bool) { #[cfg(unix,not(target_os="android"))] fn process_exists(pid: libc::pid_t) -> bool { - let run::ProcessOutput {output, ..} = run::process_output("ps", [~"-p", pid.to_str()]); + let run::ProcessOutput {output, ..} = run::process_output("ps", [~"-p", pid.to_str()]) + .expect("failed to exec `ps`"); str::from_utf8_owned(output).contains(pid.to_str()) } #[cfg(unix,target_os="android")] fn process_exists(pid: libc::pid_t) -> bool { - let run::ProcessOutput {output, ..} = run::process_output("/system/bin/ps", [pid.to_str()]); + let run::ProcessOutput {output, ..} = run::process_output("/system/bin/ps", [pid.to_str()]) + .expect("failed to exec `/system/bin/ps`"); str::from_utf8_owned(output).contains(~"root") } @@ -88,7 +92,8 @@ fn test_destroy_actually_kills(force: bool) { } // this process will stay alive indefinitely trying to read from stdin - let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new()); + let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new()) + .expect(format!("failed to exec `{}`", BLOCK_COMMAND)); assert!(process_exists(p.get_id())); diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index 8fa8c8d0c146f..c26c79112fe59 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -19,7 +19,8 @@ fn main() { // Raise a segfault. unsafe { *(0 as *mut int) = 0; } } else { - let status = run::process_status(args[0], [~"signal"]); + let status = run::process_status(args[0], [~"signal"]) + .expect("failed to exec `signal`"); // Windows does not have signal, so we get exit status 0xC0000028 (STATUS_BAD_STACK). match status { process::ExitSignal(_) if cfg!(unix) => {},