2 #include <msp/fs/dir.h>
3 #include <msp/io/console.h>
4 #include <msp/io/file.h>
5 #include <msp/io/print.h>
6 #include <msp/time/timedelta.h>
7 #include "externaltask.h"
12 ExternalTask::ExternalTask(const Arguments &a, const FS::Path &wd):
17 throw invalid_argument("ExternalTask::ExternalTask");
20 ExternalTask::~ExternalTask()
25 string ExternalTask::get_command() const
28 for(const string &a: argv)
35 if(c=='"' || c=='\'' || c==' ' || c=='\\' || c=='&')
41 if(stdin_action==REDIRECT)
44 cmd += stdin_file.str();
47 if(stdout_action==REDIRECT)
50 cmd += stdout_file.str();
56 void ExternalTask::start()
58 IO::File *devnull = 0;
60 IO::File *outfile = 0;
64 process = new Process;
66 if(stdin_action==IGNORE || stdout_action==IGNORE || stderr_action==IGNORE)
69 devnull = new IO::File("nul", IO::M_RDWR);
71 devnull = new IO::File("/dev/null", IO::M_RDWR);
73 if(stdin_action==IGNORE)
74 process->redirect_cin(*devnull);
75 if(stdout_action==IGNORE)
76 process->redirect_cout(*devnull);
77 if(stderr_action==IGNORE)
78 process->redirect_cerr(*devnull);
81 if(stdout_action==REDIRECT)
83 outfile = new IO::File((work_dir/stdout_file).str(), IO::M_WRITE);
84 process->redirect_cout(*outfile);
87 if(stdout_action==CAPTURE || stderr_action==CAPTURE)
89 capture_pipe = new IO::Pipe;
90 if(stdout_action==CAPTURE)
91 process->redirect_cout(*capture_pipe);
92 if(stderr_action==CAPTURE)
93 process->redirect_cerr(*capture_pipe);
96 if(stdin_action==REDIRECT)
98 infile = new IO::File((work_dir/stdin_file).str());
99 process->redirect_cin(*infile);
102 if(!work_dir.empty())
103 process->set_working_directory(work_dir);
105 Process::Arguments args(argv.begin()+1, argv.end());
106 process->execute(argv.front(), args);
108 capture_pipe->set_mode(IO::M_READ);
115 Task::Status ExternalTask::check()
117 return do_wait(false);
120 Task::Status ExternalTask::wait()
122 return do_wait(true);
125 Task::Status ExternalTask::do_wait(bool block)
129 if(process->wait(block && !capture_pipe))
131 exit_code = process->get_exit_code();
136 // Do this after waiting to avoid a race condition
137 while(capture_pipe && IO::poll(*capture_pipe, IO::P_INPUT, 10*Time::msec))
140 unsigned len = capture_pipe->read(buf, sizeof(buf));
142 output.append(buf, len);
153 signal_finished.emit(!exit_code);
156 return exit_code ? ERROR : SUCCESS;
159 void ExternalTask::set_stdin(const FS::Path &f)
161 stdin_action = REDIRECT;
165 void ExternalTask::set_stdout(StreamAction a)
168 throw invalid_argument("ExternalTask::set_stdout");
172 void ExternalTask::set_stdout(const FS::Path &f)
174 stdout_action = REDIRECT;
178 void ExternalTask::set_stderr(StreamAction a)
181 throw invalid_argument("ExternalTask::set_stdout");
185 string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd, bool capture_stderr)
187 ExternalTask task(argv, wd);
188 task.stdin_action = IGNORE;
189 task.set_stdout(CAPTURE);
190 task.set_stderr(capture_stderr ? CAPTURE : IGNORE);
192 if(task.wait()!=SUCCESS)
193 throw runtime_error(format("%s failed", argv.front()));
194 return task.get_output();