3 #include <msp/fs/dir.h>
4 #include <msp/io/console.h>
5 #include <msp/io/file.h>
6 #include <msp/io/print.h>
7 #include <msp/time/timedelta.h>
8 #include "externaltask.h"
13 ExternalTask::ExternalTask(const Arguments &a, const FS::Path &wd):
18 stdin_action(PASSTHROUGH),
19 stdout_action(PASSTHROUGH),
20 stderr_action(PASSTHROUGH),
24 throw invalid_argument("ExternalTask::ExternalTask");
27 ExternalTask::~ExternalTask()
32 string ExternalTask::get_command() const
35 for(vector<string>::const_iterator i=argv.begin(); i!=argv.end(); ++i)
40 for(string::const_iterator j=i->begin(); j!=i->end(); ++j)
42 if(*j=='"' || *j=='\'' || *j==' ' || *j=='\\' || *j=='&')
48 if(stdin_action==REDIRECT)
51 cmd += stdin_file.str();
54 if(stdout_action==REDIRECT)
57 cmd += stdout_file.str();
63 void ExternalTask::start()
65 IO::File *devnull = 0;
67 IO::File *outfile = 0;
71 process = new Process;
73 if(stdin_action==IGNORE || stdout_action==IGNORE || stderr_action==IGNORE)
76 devnull = new IO::File("nul", IO::M_RDWR);
78 devnull = new IO::File("/dev/null", IO::M_RDWR);
80 if(stdin_action==IGNORE)
81 process->redirect_cin(*devnull);
82 if(stdout_action==IGNORE)
83 process->redirect_cout(*devnull);
84 if(stderr_action==IGNORE)
85 process->redirect_cerr(*devnull);
88 if(stdout_action==REDIRECT)
90 outfile = new IO::File((work_dir/stdout_file).str(), IO::M_WRITE);
91 process->redirect_cout(*outfile);
94 if(stdout_action==CAPTURE || stderr_action==CAPTURE)
96 capture_pipe = new IO::Pipe;
97 if(stdout_action==CAPTURE)
98 process->redirect_cout(*capture_pipe);
99 if(stderr_action==CAPTURE)
100 process->redirect_cerr(*capture_pipe);
103 if(stdin_action==REDIRECT)
105 infile = new IO::File((work_dir/stdin_file).str());
106 process->redirect_cin(*infile);
109 if(!work_dir.empty())
110 process->set_working_directory(work_dir);
112 Process::Arguments args(argv.begin()+1, argv.end());
113 process->execute(argv.front(), args);
115 capture_pipe->set_mode(IO::M_READ);
122 Task::Status ExternalTask::check()
124 return do_wait(false);
127 Task::Status ExternalTask::wait()
129 return do_wait(true);
132 Task::Status ExternalTask::do_wait(bool block)
136 if(process->wait(block && !capture_pipe))
138 exit_code = process->get_exit_code();
143 // Do this after waiting to avoid a race condition
144 while(capture_pipe && IO::poll(*capture_pipe, IO::P_INPUT, 10*Time::msec))
147 unsigned len = capture_pipe->read(buf, sizeof(buf));
149 output.append(buf, len);
160 signal_finished.emit(!exit_code);
163 return exit_code ? ERROR : SUCCESS;
166 void ExternalTask::set_stdin(const FS::Path &f)
168 stdin_action = REDIRECT;
172 void ExternalTask::set_stdout(StreamAction a)
175 throw invalid_argument("ExternalTask::set_stdout");
179 void ExternalTask::set_stdout(const FS::Path &f)
181 stdout_action = REDIRECT;
185 void ExternalTask::set_stderr(StreamAction a)
188 throw invalid_argument("ExternalTask::set_stdout");
192 string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd, bool capture_stderr)
194 ExternalTask task(argv, wd);
195 task.stdin_action = IGNORE;
196 task.set_stdout(CAPTURE);
197 task.set_stderr(capture_stderr ? CAPTURE : IGNORE);
199 if(task.wait()!=SUCCESS)
200 throw runtime_error(format("%s failed", argv.front()));
201 return task.get_output();