X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fexternaltask.cpp;h=643831e993b9b7e8a8d4c2b65f11245c612bba18;hb=c75c89d2425ab0c69e94d45a5d956286838bbc67;hp=f24774e83a5cc8009aae92d2d172a41c2893c039;hpb=64cd148dcd762ea368d9a552e982fdff83781ef2;p=builder.git diff --git a/source/externaltask.cpp b/source/externaltask.cpp index f24774e..643831e 100644 --- a/source/externaltask.cpp +++ b/source/externaltask.cpp @@ -2,7 +2,10 @@ #include #include #include +#include +#include #include +#include #include "externaltask.h" using namespace std; @@ -12,9 +15,17 @@ ExternalTask::ExternalTask(const vector &a, const FS::Path &wd): argv(a), work_dir(wd), pid(-1), - exit_code(-1) + exit_code(-1), + stdout_dest(PASSTHROUGH), + stderr_dest(PASSTHROUGH), + capture_pipe(0) { } +ExternalTask::~ExternalTask() +{ + delete capture_pipe; +} + string ExternalTask::get_command() const { string cmd; @@ -36,10 +47,15 @@ string ExternalTask::get_command() const void ExternalTask::start() { + if(stdout_dest==CAPTURE || stderr_dest==CAPTURE) + capture_pipe = new IO::Pipe; + + prepare(); + if((pid = fork())) { if(pid==-1) - exit_code = 1; + exit_code = 1026; else exit_code = 0; } @@ -50,6 +66,24 @@ void ExternalTask::start() cargv[i] = argv[i].c_str(); cargv.back() = 0; + if(stdout_dest==IGNORE || stderr_dest==IGNORE) + { + IO::File devnull("/dev/null", IO::M_WRITE); + if(stdout_dest==IGNORE) + IO::cout.redirect(devnull); + if(stderr_dest==IGNORE) + IO::cerr.redirect(devnull); + } + + if(capture_pipe) + { + if(stdout_dest==CAPTURE) + IO::cout.redirect(*capture_pipe); + if(stderr_dest==CAPTURE) + IO::cerr.redirect(*capture_pipe); + delete capture_pipe; + } + if(!work_dir.empty()) FS::chdir(work_dir); execvp(cargv.front(), const_cast(&cargv.front())); @@ -59,11 +93,21 @@ void ExternalTask::start() } Task::Status ExternalTask::check() +{ + return do_wait(false); +} + +Task::Status ExternalTask::wait() +{ + return do_wait(true); +} + +Task::Status ExternalTask::do_wait(bool block) { if(pid>0) { int status; - if(waitpid(pid, &status, WNOHANG)==pid) + if(waitpid(pid, &status, (block ? 0 : WNOHANG))==pid) { if(WIFEXITED(status)) exit_code = WEXITSTATUS(status); @@ -72,12 +116,47 @@ Task::Status ExternalTask::check() else exit_code = 1025; pid = 0; + } - signal_finished.emit(!exit_code); + // Do this after waiting to avoid a race condition + if(capture_pipe) + { + while(IO::poll(*capture_pipe, IO::P_INPUT, Time::zero)) + { + char buf[1024]; + unsigned len = capture_pipe->read(buf, sizeof(buf)); + output.append(buf, len); + if(len0) return RUNNING; + else + signal_finished.emit(!exit_code); } return exit_code ? ERROR : SUCCESS; } + +void ExternalTask::set_stdout(Destination d) +{ + stdout_dest = d; +} + +void ExternalTask::set_stderr(Destination d) +{ + stderr_dest = d; +} + +string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd) +{ + ExternalTask task(argv, wd); + task.set_stdout(CAPTURE); + task.set_stderr(IGNORE); + task.start(); + if(task.wait()!=SUCCESS) + throw runtime_error(format("%s failed", argv.front())); + return task.get_output(); +}