SAGA Adaptor CPI v.1.0
process.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines