From 4b075b4a7ed921be62740c302edeebcd8b06ca29 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 9 Oct 2014 20:42:57 +0300 Subject: [PATCH] Support redirecting ExternalTask's stdin/stdout from/to a file --- source/externaltask.cpp | 67 +++++++++++++++++++++++++++++++++-------- source/externaltask.h | 19 +++++++++--- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/source/externaltask.cpp b/source/externaltask.cpp index 3cc8eca..257d131 100644 --- a/source/externaltask.cpp +++ b/source/externaltask.cpp @@ -16,8 +16,8 @@ ExternalTask::ExternalTask(const Arguments &a, const FS::Path &wd): work_dir(wd), process(0), exit_code(-1), - stdout_dest(PASSTHROUGH), - stderr_dest(PASSTHROUGH), + stdout_action(PASSTHROUGH), + stderr_action(PASSTHROUGH), capture_pipe(0) { if(argv.empty()) @@ -45,35 +45,61 @@ string ExternalTask::get_command() const } } + if(!stdin_file.empty()) + { + cmd += " <"; + cmd += stdin_file.str(); + } + + if(stdout_action==REDIRECT) + { + cmd += " >"; + cmd += stdout_file.str(); + } + return cmd; } void ExternalTask::start() { IO::File *devnull = 0; + IO::File *infile = 0; + IO::File *outfile = 0; prepare(); process = new Process; - if(stdout_dest==IGNORE || stderr_dest==IGNORE) + if(stdout_action==IGNORE || stderr_action==IGNORE) { devnull = new IO::File("/dev/null", IO::M_WRITE); - if(stdout_dest==IGNORE) + if(stdout_action==IGNORE) process->redirect_cout(*devnull); - if(stderr_dest==IGNORE) + if(stderr_action==IGNORE) process->redirect_cerr(*devnull); } - if(stdout_dest==CAPTURE || stderr_dest==CAPTURE) + if(stdout_action==REDIRECT) + { + outfile = new IO::File((work_dir/stdout_file).str(), IO::M_WRITE); + process->redirect_cout(*outfile); + } + + if(stdout_action==CAPTURE || stderr_action==CAPTURE) { capture_pipe = new IO::Pipe; - if(stdout_dest==CAPTURE) + if(stdout_action==CAPTURE) process->redirect_cout(*capture_pipe); - if(stderr_dest==CAPTURE) + if(stderr_action==CAPTURE) process->redirect_cerr(*capture_pipe); } + if(!stdin_file.empty()) + { + infile = new IO::File((work_dir/stdin_file).str()); + process->redirect_cin(*infile); + } + if(!work_dir.empty()) process->set_working_directory(work_dir); @@ -83,6 +109,8 @@ void ExternalTask::start() capture_pipe->set_mode(IO::M_READ); delete devnull; + delete infile; + delete outfile; } Task::Status ExternalTask::check() @@ -126,14 +154,29 @@ 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_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) diff --git a/source/externaltask.h b/source/externaltask.h index 992df5c..00465f3 100644 --- a/source/externaltask.h +++ b/source/externaltask.h @@ -16,10 +16,11 @@ be captured. class ExternalTask: public Task { public: - enum Destination + enum StreamAction { PASSTHROUGH, //< Do not touch the stream CAPTURE, //< Capture the stream + REDIRECT, //< Redirect the stream to/from a file IGNORE //< Redirect the stream to oblivion }; @@ -30,8 +31,10 @@ private: Msp::FS::Path work_dir; Msp::Process *process; int exit_code; - Destination stdout_dest; - Destination stderr_dest; + Msp::FS::Path stdin_file; + StreamAction stdout_action; + Msp::FS::Path stdout_file; + StreamAction stderr_action; Msp::IO::Pipe *capture_pipe; std::string output; @@ -51,11 +54,17 @@ private: Status do_wait(bool); public: + /// Redirect stdin from a file. Has no effect after the task is started. + void set_stdin(const Msp::FS::Path &); + /// Sets destination for stdout. Has no effect after the task is started. - void set_stdout(Destination); + void set_stdout(StreamAction); + + /// Redirect stdout to a file. Has no effect after the task is started. + void set_stdout(const Msp::FS::Path &); /// Sets destination for stderr. Has no effect after the task is started. - void set_stderr(Destination); + void set_stderr(StreamAction); /** Returns captured output, if any. This may be called while the task is still running, but it will always return all output. */ -- 2.43.0