SAGA Adaptor CPI v.1.0
|
00001 // Copyright (c) 2005-2007 Andre Merzky (andre@merzky.net) 00002 // 00003 // Use, modification and distribution is subject to the Boost Software 00004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 00005 // http://www.boost.org/LICENSE_1_0.txt) 00006 // 00007 // TODO: add stdin handling 00008 00009 #include <boost/config.hpp> 00010 #include <saga/saga/adaptors/utils/process/process.hpp> 00011 00012 // for the throw macro... 00013 #include <saga/saga/object.hpp> 00014 #include <saga/impl/exception.hpp> 00015 00016 #if defined(BOOST_PROCESS_WIN32_API) 00017 00018 // this is a hack to make boost::process work (avoid multiple definitions) 00019 // (this will go away as soon as it is fixed in Boost.Process) 00020 const boost::process::detail::file_handle::handle_type 00021 boost::process::detail::file_handle::INVALID_VALUE = INVALID_HANDLE_VALUE; 00022 #endif 00023 00024 namespace saga 00025 { 00026 namespace adaptors 00027 { 00028 namespace utils 00029 { 00030 process::process (void) 00031 : cmd_ (""), 00032 exit_ (0), 00033 done_ (false), 00034 fail_ (false) 00035 { 00036 } 00037 00038 process::process (std::string cmd) 00039 : cmd_ (cmd), 00040 exit_ (0), 00041 done_ (false), 00042 fail_ (false) 00043 { 00044 } 00045 00046 process::process (std::vector <std::string> const& args) 00047 : args_ (args), 00048 exit_ (0), 00049 done_ (false), 00050 fail_ (false) 00051 { 00052 } 00053 00054 process::process (std::map <std::string, std::string> const& env) 00055 : env_ (env), 00056 exit_ (0), 00057 done_ (false), 00058 fail_ (false) 00059 { 00060 } 00061 00062 process::process (std::string cmd, 00063 std::vector <std::string> const& args) 00064 : cmd_ (cmd), 00065 args_ (args), 00066 exit_ (0), 00067 done_ (false), 00068 fail_ (false) 00069 { 00070 } 00071 00072 process::process (std::string cmd, 00073 std::map <std::string, std::string> const& env) 00074 : cmd_ (cmd), 00075 env_ (env), 00076 exit_ (0), 00077 done_ (false), 00078 fail_ (false) 00079 { 00080 } 00081 00082 process::process (std::string cmd, 00083 std::vector <std::string> const& args, 00084 std::map <std::string, std::string> const& env) 00085 : cmd_ (cmd), 00086 args_ (args), 00087 env_ (env), 00088 exit_ (0), 00089 done_ (false), 00090 fail_ (false) 00091 { 00092 } 00093 00094 void process::clear (void) 00095 { 00096 cmd_ = ""; 00097 00098 env_.clear (); 00099 args_.clear (); 00100 00101 msg_ = ""; 00102 exit_ = 0, 00103 fail_ = false; 00104 done_ = false; 00105 00106 out_v_.clear (); 00107 err_v_.clear (); 00108 } 00109 00110 void process::set_cmd (std::string cmd) 00111 { 00112 cmd_= cmd; 00113 } 00114 00115 void process::clear_args (void) 00116 { 00117 args_.clear (); 00118 } 00119 00120 void process::set_args (std::vector <std::string> const& args) 00121 { 00122 args_ = args; 00123 } 00124 00125 void process::add_args (std::string arg_1, 00126 std::string arg_2) 00127 { 00128 args_.push_back (arg_1); 00129 args_.push_back (arg_2); 00130 } 00131 00132 void process::add_arg (std::string arg) 00133 { 00134 args_.push_back (arg); 00135 } 00136 00137 void process::clear_env (void) 00138 { 00139 env_.clear (); 00140 } 00141 00142 void process::set_env (std::map <std::string, std::string> const& env) 00143 { 00144 env_ = env; 00145 } 00146 00147 void process::add_env (std::string key, std::string val) 00148 { 00149 env_[key] = val; 00150 } 00151 00153 // 00154 // run a process, and return stdout. In case of errors, throw a NoSuccess with 00155 // stderr as error message 00156 // 00157 std::vector <std::string> process::run_sync (bool io) 00158 { 00159 try 00160 { 00161 // reset state 00162 fail_ = false; 00163 done_ = false; 00164 00165 clear_out (); 00166 clear_err (); 00167 00168 if ( cmd_ == "") 00169 { 00170 std::cout << " === no cmd\n"; 00171 fail_ = true; 00172 msg_ = "no command to run"; 00173 00174 std::vector <std::string> out; 00175 return out; 00176 } 00177 00178 00179 boost::process::command_line cl (cmd_); 00180 std::string log (" >> "); 00181 log += cmd_ + " "; 00182 00183 for ( unsigned int i = 0; i < args_.size (); i++ ) 00184 { 00185 cl.argument (args_[i]); 00186 log += args_[i] + " "; 00187 } 00188 00189 SAGA_LOG_ALWAYS (log.c_str ()); 00190 00191 boost::process::launcher l; 00192 00193 if ( io ) 00194 { 00195 l.set_stdin_behavior (boost::process::redirect_stream); 00196 l.set_stdout_behavior (boost::process::redirect_stream); 00197 l.set_stderr_behavior (boost::process::redirect_stream); 00198 } 00199 00200 std::map <std::string, std::string> :: iterator it; 00201 00202 for ( it = env_.begin (); it != env_.end (); it++ ) 00203 { 00204 l.set_environment ( (*it).first, (*it).second ); 00205 } 00206 00207 c_ = l.start (cl); 00208 00209 if ( io ) 00210 { 00211 // boost::process::postream & in = c_.get_stdin (); 00212 boost::process::pistream & out = c_.get_stdout (); 00213 boost::process::pistream & err = c_.get_stderr (); 00214 00215 for ( std::string line; out.good () && getline (out, line); out_v_.push_back (line) ); 00216 for ( std::string line; err.good () && getline (err, line); err_v_.push_back (line) ); 00217 } 00218 00219 boost::process::status status = c_.wait (); 00220 00221 if ( ! status.exited () ) 00222 { 00223 fail_ = true; 00224 msg_ = "exit fail"; 00225 00226 SAGA_LOG_DEBUG (msg_.c_str ()); 00227 00228 for ( std::size_t i = 0; i < err_v_.size (); i++ ) 00229 { 00230 SAGA_LOG_DEBUG (err_v_[i].c_str ()); 00231 } 00232 } 00233 else 00234 { 00235 exit_ = status.exit_status (); 00236 00237 if ( ! status.exited () || exit_ ) 00238 { 00239 fail_ = true; 00240 msg_ = "exit status != 0"; 00241 00242 SAGA_LOG_DEBUG (msg_.c_str ()); 00243 00244 for ( std::size_t i = 0; i < err_v_.size (); i++ ) 00245 { 00246 SAGA_LOG_DEBUG (err_v_[i].c_str ()); 00247 } 00248 } 00249 else 00250 { 00251 done_ = true; 00252 } 00253 } 00254 00255 } 00256 catch ( const boost::process::not_found_error <std::string> & e ) 00257 { 00258 fail_ = true; 00259 std::string msg("Could not find executable in path: "); 00260 msg += e.what(); 00261 SAGA_THROW_NO_OBJECT (msg, saga::NoSuccess); 00262 } 00263 catch ( const boost::process::system_error & e ) 00264 { 00265 fail_ = true; 00266 std::string msg("Execution failed: "); 00267 msg += e.what(); 00268 SAGA_THROW_NO_OBJECT (msg, saga::NoSuccess); 00269 } 00270 00271 return out_v_; 00272 } 00273 00274 boost::process::pistream & process::get_out (void) 00275 { 00276 return c_.get_stdout (); 00277 } 00278 00279 boost::process::pistream & process::get_err (void) 00280 { 00281 return c_.get_stderr (); 00282 } 00283 00284 00285 std::string process::get_out_s (void) 00286 { 00287 std::string out; 00288 00289 for ( std::size_t i = 0; i < out_v_.size (); i++ ) 00290 { 00291 out += out_v_[i] + "\n"; 00292 } 00293 00294 return out; 00295 } 00296 00297 std::string process::get_err_s (void) 00298 { 00299 std::string err; 00300 00301 for ( std::size_t i = 0; i < err_v_.size (); i++ ) 00302 { 00303 err += err_v_[i] + "\n"; 00304 } 00305 00306 return err; 00307 } 00308 00309 00310 std::vector <std::string> process::get_out_v (void) 00311 { 00312 return out_v_; 00313 } 00314 00315 std::vector <std::string> process::get_err_v (void) 00316 { 00317 return err_v_; 00318 } 00319 00320 void process::clear_out (void) 00321 { 00322 out_v_.clear (); 00323 } 00324 00325 void process::clear_err (void) 00326 { 00327 err_v_.clear (); 00328 } 00330 00331 } // namespace utils 00332 00333 } // namespace adaptors 00334 00335 } // namespace saga 00336