X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fexternaltask.cpp;h=16d1df096dd4a23eee3f60b2e54a8cf289de9884;hb=8a98d59b2b4954f51eb3f649d3675af976154de6;hp=643831e993b9b7e8a8d4c2b65f11245c612bba18;hpb=33d74db3e99f35a8984d4ad9b703f709d07d44c5;p=builder.git diff --git a/source/externaltask.cpp b/source/externaltask.cpp index 643831e..16d1df0 100644 --- a/source/externaltask.cpp +++ b/source/externaltask.cpp @@ -1,25 +1,27 @@ #include -#include -#include #include #include #include #include -#include +#include #include "externaltask.h" using namespace std; using namespace Msp; -ExternalTask::ExternalTask(const vector &a, const FS::Path &wd): +ExternalTask::ExternalTask(const Arguments &a, const FS::Path &wd): argv(a), work_dir(wd), - pid(-1), + process(0), exit_code(-1), - stdout_dest(PASSTHROUGH), - stderr_dest(PASSTHROUGH), + stdin_action(PASSTHROUGH), + stdout_action(PASSTHROUGH), + stderr_action(PASSTHROUGH), capture_pipe(0) -{ } +{ + if(argv.empty()) + throw invalid_argument("ExternalTask::ExternalTask"); +} ExternalTask::~ExternalTask() { @@ -42,54 +44,78 @@ string ExternalTask::get_command() const } } + if(stdin_action==REDIRECT) + { + cmd += " <"; + cmd += stdin_file.str(); + } + + if(stdout_action==REDIRECT) + { + cmd += " >"; + cmd += stdout_file.str(); + } + return cmd; } void ExternalTask::start() { - if(stdout_dest==CAPTURE || stderr_dest==CAPTURE) - capture_pipe = new IO::Pipe; + IO::File *devnull = 0; + IO::File *infile = 0; + IO::File *outfile = 0; prepare(); - if((pid = fork())) + process = new Process; + + if(stdin_action==IGNORE || stdout_action==IGNORE || stderr_action==IGNORE) { - if(pid==-1) - exit_code = 1026; - else - exit_code = 0; +#ifdef _WIN32 + devnull = new IO::File("nul", IO::M_RDWR); +#else + devnull = new IO::File("/dev/null", IO::M_RDWR); +#endif + if(stdin_action==IGNORE) + process->redirect_cin(*devnull); + if(stdout_action==IGNORE) + process->redirect_cout(*devnull); + if(stderr_action==IGNORE) + process->redirect_cerr(*devnull); } - else - { - vector cargv(argv.size()+1); - for(unsigned i=0; iredirect_cout(*outfile); + } - 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(stdout_action==CAPTURE || stderr_action==CAPTURE) + { + capture_pipe = new IO::Pipe; + if(stdout_action==CAPTURE) + process->redirect_cout(*capture_pipe); + if(stderr_action==CAPTURE) + process->redirect_cerr(*capture_pipe); + } - if(!work_dir.empty()) - FS::chdir(work_dir); - execvp(cargv.front(), const_cast(&cargv.front())); - IO::print("Couldn't execute %s\n", argv.front()); - exit(1); + if(stdin_action==REDIRECT) + { + infile = new IO::File((work_dir/stdin_file).str()); + process->redirect_cin(*infile); } + + if(!work_dir.empty()) + process->set_working_directory(work_dir); + + Process::Arguments args(argv.begin()+1, argv.end()); + process->execute(argv.front(), args); + if(capture_pipe) + capture_pipe->set_mode(IO::M_READ); + + delete devnull; + delete infile; + delete outfile; } Task::Status ExternalTask::check() @@ -104,35 +130,31 @@ Task::Status ExternalTask::wait() Task::Status ExternalTask::do_wait(bool block) { - if(pid>0) + while(process) { - int status; - if(waitpid(pid, &status, (block ? 0 : WNOHANG))==pid) + if(process->wait(block && !capture_pipe)) { - if(WIFEXITED(status)) - exit_code = WEXITSTATUS(status); - else if(WIFSIGNALED(status)) - exit_code = 256+WTERMSIG(status); - else - exit_code = 1025; - pid = 0; + exit_code = process->get_exit_code(); + delete process; + process = 0; } // Do this after waiting to avoid a race condition - if(capture_pipe) + while(capture_pipe && IO::poll(*capture_pipe, IO::P_INPUT, 10*Time::msec)) { - while(IO::poll(*capture_pipe, IO::P_INPUT, Time::zero)) - { - char buf[1024]; - unsigned len = capture_pipe->read(buf, sizeof(buf)); + char buf[1024]; + unsigned len = capture_pipe->read(buf, sizeof(buf)); + if(len) output.append(buf, len); - if(len0) - return RUNNING; + if(process) + { + if(!block) + return RUNNING; + } else signal_finished.emit(!exit_code); } @@ -140,21 +162,38 @@ Task::Status ExternalTask::do_wait(bool block) return exit_code ? ERROR : SUCCESS; } -void ExternalTask::set_stdout(Destination d) +void ExternalTask::set_stdin(const FS::Path &f) +{ + stdin_action = REDIRECT; + stdin_file = f; +} + +void ExternalTask::set_stdout(StreamAction a) +{ + if(a==REDIRECT) + throw invalid_argument("ExternalTask::set_stdout"); + stdout_action = a; +} + +void ExternalTask::set_stdout(const FS::Path &f) { - stdout_dest = d; + stdout_action = REDIRECT; + stdout_file = f; } -void ExternalTask::set_stderr(Destination d) +void ExternalTask::set_stderr(StreamAction a) { - stderr_dest = d; + if(a==REDIRECT) + throw invalid_argument("ExternalTask::set_stdout"); + stderr_action = a; } -string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd) +string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd, bool capture_stderr) { ExternalTask task(argv, wd); + task.stdin_action = IGNORE; task.set_stdout(CAPTURE); - task.set_stderr(IGNORE); + task.set_stderr(capture_stderr ? CAPTURE : IGNORE); task.start(); if(task.wait()!=SUCCESS) throw runtime_error(format("%s failed", argv.front()));