]> git.tdb.fi Git - builder.git/commitdiff
Add support for capturing output in ExternalTask
authorMikko Rasa <tdb@tdb.fi>
Wed, 30 May 2012 19:28:12 +0000 (19:28 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 8 Jul 2012 21:08:52 +0000 (00:08 +0300)
source/externaltask.cpp
source/externaltask.h

index 6ff6a3e90892bcecb8fcb47d448b9982cc05d2db..0da81e519cc05eba437855e02da99d81722302d1 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,9 @@ string ExternalTask::get_command() const
 
 void ExternalTask::start()
 {
+       if(stdout_dest==CAPTURE || stderr_dest==CAPTURE)
+               capture_pipe = new IO::Pipe;
+
        if((pid = fork()))
        {
                if(pid==-1)
@@ -50,6 +64,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()));
@@ -62,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)
                {
@@ -72,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(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;
+}
index 0bd108e9a3cac68e46ca80e6f43ac434b752a70c..b23bb66728805e280359705ff61a6b2b1436b55f 100644 (file)
@@ -4,22 +4,40 @@
 #include <string>
 #include <vector>
 #include <msp/fs/path.h>
+#include <msp/io/pipe.h>
 #include "task.h"
 
 class ExternalTask: public Task
 {
+public:
+       enum Destination
+       {
+               PASSTHROUGH,
+               CAPTURE,
+               IGNORE
+       };
+
 private:
        std::vector<std::string> argv;
        Msp::FS::Path work_dir;
        int pid;
        int exit_code;
+       Destination stdout_dest;
+       Destination stderr_dest;
+       Msp::IO::Pipe *capture_pipe;
+       std::string output;
 
 public:
        ExternalTask(const std::vector<std::string> &, const Msp::FS::Path &);
+       virtual ~ExternalTask();
 
        virtual std::string get_command() const;
        virtual void start();
        virtual Status check();
+
+       void set_stdout(Destination);
+       void set_stderr(Destination);
+       const std::string &get_output() const { return output; }
 };
 
 #endif