X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fexternaltask.cpp;h=0da81e519cc05eba437855e02da99d81722302d1;hb=4facd021514ab372c23b1b132d6b4b62baa4efbf;hp=c205cbcf1a5c704f92aeed61cda08537c580224d;hpb=f58a6a7389e0c2609c56a184f98731e01ab450a4;p=builder.git diff --git a/source/externaltask.cpp b/source/externaltask.cpp index c205cbc..0da81e5 100644 --- a/source/externaltask.cpp +++ b/source/externaltask.cpp @@ -2,20 +2,58 @@ #include #include #include +#include +#include #include +#include #include "externaltask.h" using namespace std; using namespace Msp; -ExternalTask::ExternalTask(const vector &argv, const FS::Path &work_dir): +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; + for(vector::const_iterator i=argv.begin(); i!=argv.end(); ++i) + { + if(i!=argv.begin()) + cmd += ' '; + + for(string::const_iterator j=i->begin(); j!=i->end(); ++j) + { + if(*j=='"' || *j=='\'' || *j==' ' || *j=='\\' || *j=='&') + cmd += '\\'; + cmd += *j; + } + } + + return cmd; +} + +void ExternalTask::start() +{ + if(stdout_dest==CAPTURE || stderr_dest==CAPTURE) + capture_pipe = new IO::Pipe; + if((pid = fork())) { if(pid==-1) - exit_code = 1; + exit_code = 1026; else exit_code = 0; } @@ -26,6 +64,24 @@ ExternalTask::ExternalTask(const vector &argv, const FS::Path &work_dir) 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())); @@ -38,6 +94,7 @@ Task::Status ExternalTask::check() { if(pid>0) { + // XXX This is sub-optimal, should have support for a blocking wait int status; if(waitpid(pid, &status, WNOHANG)==pid) { @@ -48,12 +105,36 @@ 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; +}