]> git.tdb.fi Git - builder.git/blobdiff - source/externaltask.cpp
Move the bpk files into a subdirectory and install them
[builder.git] / source / externaltask.cpp
index 6ff6a3e90892bcecb8fcb47d448b9982cc05d2db..643831e993b9b7e8a8d4c2b65f11245c612bba18 100644 (file)
@@ -2,7 +2,10 @@
 #include <unistd.h>
 #include <sys/wait.h>
 #include <msp/fs/dir.h>
+#include <msp/io/console.h>
+#include <msp/io/file.h>
 #include <msp/io/print.h>
+#include <msp/time/units.h>
 #include "externaltask.h"
 
 using namespace std;
@@ -12,9 +15,17 @@ ExternalTask::ExternalTask(const vector<string> &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,6 +47,11 @@ 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)
@@ -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<char *const *>(&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(len<sizeof(buf))
+                                       break;
+                       }
                }
-               else
+
+               if(pid>0)
                        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();
+}