|
42 | 42 | #include <sstream>
|
43 | 43 | #include <iterator>
|
44 | 44 |
|
| 45 | +#if (Boost_VERSION_MINOR > 85) && defined(OPENFLUID_OS_WINDOWS) |
| 46 | +#include <winsock2.h> // FIXME check if useful or necessary, theorically useful to respect include order |
| 47 | +#endif |
| 48 | +#if (Boost_VERSION_MINOR > 85) |
| 49 | +#include <unordered_map> |
| 50 | +#include <boost/asio/io_context.hpp> |
| 51 | +#include <boost/asio/readable_pipe.hpp> |
| 52 | +#include <boost/asio/read.hpp> |
| 53 | +#include <boost/process/v2/process.hpp> |
| 54 | +#include <boost/process/v2/environment.hpp> |
| 55 | +#include <boost/process/v2/stdio.hpp> |
| 56 | +#include <boost/process/v2/start_dir.hpp> |
| 57 | +#else |
45 | 58 | #include <boost/process.hpp>
|
| 59 | +#endif |
46 | 60 |
|
47 | 61 | #include <openfluid/tools/FilesystemPath.hpp>
|
48 | 62 | #include <openfluid/tools/StringHelpers.hpp>
|
@@ -136,6 +150,107 @@ bool Process::run()
|
136 | 150 |
|
137 | 151 | try
|
138 | 152 | {
|
| 153 | +#if (Boost_VERSION_MINOR > 85) |
| 154 | + std::ofstream StdOutFile; |
| 155 | + std::ofstream StdErrFile; |
| 156 | + std::string LineOut; |
| 157 | + std::string LineErr; |
| 158 | + std::unordered_map<std::string, std::string> ProcessEnv; |
| 159 | + boost::asio::io_context Ctx; |
| 160 | + boost::asio::readable_pipe PipeOut{Ctx}; |
| 161 | + boost::asio::readable_pipe PipeErr{Ctx}; |
| 162 | + |
| 163 | + bool SinkOutToFile = !m_Cmd.OutFile.empty(); |
| 164 | + bool SinkErrToFile = !m_Cmd.ErrFile.empty(); |
| 165 | + |
| 166 | + // prepare environment |
| 167 | + if (m_Env.Inherits) |
| 168 | + { |
| 169 | + for(const auto& InheritedVar : boost::process::v2::environment::current()) |
| 170 | + { |
| 171 | + ProcessEnv[InheritedVar.key().string()] = InheritedVar.value().string(); |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + for (const auto& Var : m_Env.Vars) |
| 176 | + { |
| 177 | + ProcessEnv[Var.first] = Var.second; |
| 178 | + } |
| 179 | + // Hotfix for windows bug when work dir is empty |
| 180 | + std::string WorkDir; |
| 181 | + if (m_Cmd.WorkDir.empty()) |
| 182 | + { |
| 183 | + WorkDir = "."; // warning boost : If your path is relative, it may fail on posix, |
| 184 | + //because the directory is changed before a call to execve. |
| 185 | + } |
| 186 | + else |
| 187 | + { |
| 188 | + WorkDir = m_Cmd.WorkDir; |
| 189 | + } |
| 190 | + |
| 191 | + // boost::process::shell, <- not relevant in new system? |
| 192 | + boost::process::v2::process Proc(Ctx, m_Cmd.Program, m_Cmd.Args, |
| 193 | + boost::process::v2::process_stdio{nullptr, PipeOut, PipeErr}, |
| 194 | + boost::process::v2::process_start_dir(WorkDir), |
| 195 | + boost::process::v2::process_environment(ProcessEnv)); |
| 196 | + |
| 197 | + // if out is redirected, create out file |
| 198 | + if (SinkOutToFile) |
| 199 | + { |
| 200 | + openfluid::tools::Path(openfluid::tools::Path(m_Cmd.OutFile).dirname()).makeDirectory(); |
| 201 | + StdOutFile.open(m_Cmd.OutFile,std::ios::out); |
| 202 | + } |
| 203 | + |
| 204 | + // if error is redirected, create error file |
| 205 | + if (SinkErrToFile) |
| 206 | + { |
| 207 | + openfluid::tools::Path(openfluid::tools::Path(m_Cmd.ErrFile).dirname()).makeDirectory(); |
| 208 | + StdErrFile.open(m_Cmd.ErrFile,std::ios::out); |
| 209 | + } |
| 210 | + |
| 211 | + boost::system::error_code Ec; |
| 212 | + boost::asio::read(PipeOut, boost::asio::dynamic_buffer(LineOut), Ec); |
| 213 | + if (!Ec || (Ec == boost::asio::error::eof)) |
| 214 | + { |
| 215 | + std::cout << "Boost process reading error in out stream: " << Ec.message() << std::endl; |
| 216 | + openfluid::utils::log::error("Process", "Boost process reading error in out stream"); |
| 217 | + } |
| 218 | + boost::asio::read(PipeErr, boost::asio::dynamic_buffer(LineErr), Ec); |
| 219 | + if (!Ec || (Ec == boost::asio::error::eof)) |
| 220 | + { |
| 221 | + std::cout << "Boost process reading error in err stream: " << Ec.message() << std::endl; |
| 222 | + openfluid::utils::log::error("Process", "Boost process reading error in err stream"); |
| 223 | + } |
| 224 | + |
| 225 | + Proc.wait(); |
| 226 | + for (const auto& L : openfluid::tools::split(LineOut, "\n")) |
| 227 | + { |
| 228 | + if (SinkOutToFile) |
| 229 | + { |
| 230 | + // if out is redirected, sink out lines in file |
| 231 | + StdOutFile << L << "\n"; |
| 232 | + } |
| 233 | + else |
| 234 | + { |
| 235 | + m_OutLines.push_back(L); |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + for (const auto& L : openfluid::tools::split(LineErr, "\n")) |
| 240 | + { |
| 241 | + if (SinkErrToFile) |
| 242 | + { |
| 243 | + // if out is redirected, sink out lines in file |
| 244 | + StdErrFile << L << "\n"; |
| 245 | + } |
| 246 | + else |
| 247 | + { |
| 248 | + m_ErrLines.push_back(L); |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + m_ExitCode = Proc.exit_code(); |
| 253 | +#else |
139 | 254 | boost::process::environment ProcessEnv;
|
140 | 255 | boost::process::ipstream StdOutStr;
|
141 | 256 | boost::process::ipstream StdErrStr;
|
@@ -229,17 +344,12 @@ bool Process::run()
|
229 | 344 |
|
230 | 345 | BPC.wait();
|
231 | 346 | m_ExitCode = BPC.exit_code();
|
| 347 | +#endif |
232 | 348 | }
|
233 |
| - catch(const boost::process::process_error& E) |
| 349 | + catch(const std::exception& E) |
234 | 350 | {
|
235 | 351 | m_ErrorMsg = std::string(E.what());
|
236 |
| - openfluid::utils::log::error("Process", std::string("Boost process error: ")+E.what()); |
237 |
| - return false; |
238 |
| - } |
239 |
| - catch(...) |
240 |
| - { |
241 |
| - // TODO for logging purposes |
242 |
| - openfluid::utils::log::error("Process", "Boost process error"); |
| 352 | + openfluid::utils::log::error("Process", std::string("Boost process error: ")+m_ErrorMsg); |
243 | 353 | return false;
|
244 | 354 | }
|
245 | 355 |
|
@@ -291,6 +401,38 @@ int Process::system(const std::string& Program, const std::vector<std::string>&
|
291 | 401 |
|
292 | 402 | int Process::system(const Command& Cmd, const Environment& Env)
|
293 | 403 | {
|
| 404 | +#if (Boost_VERSION_MINOR > 85) |
| 405 | + boost::asio::io_context Ctx; |
| 406 | + std::unordered_map<std::string, std::string> ProcessEnv; |
| 407 | + // prepare environment |
| 408 | + if (Env.Inherits) |
| 409 | + { |
| 410 | + for(const auto& InheritedVar : boost::process::v2::environment::current()) |
| 411 | + { |
| 412 | + ProcessEnv[InheritedVar.key().string()] = InheritedVar.value().string(); |
| 413 | + } |
| 414 | + } |
| 415 | + |
| 416 | + for (const auto& Var : Env.Vars) |
| 417 | + { |
| 418 | + ProcessEnv[Var.first] = Var.second; |
| 419 | + } |
| 420 | + // Hotfix for windows bug when work dir is empty |
| 421 | + std::string WorkDir; |
| 422 | + if (Cmd.WorkDir.empty()) |
| 423 | + { |
| 424 | + WorkDir = "."; // warning boost : If your path is relative, it may fail on posix, |
| 425 | + //because the directory is changed before a call to execve. |
| 426 | + } |
| 427 | + else |
| 428 | + { |
| 429 | + WorkDir = Cmd.WorkDir; |
| 430 | + } |
| 431 | + boost::process::v2::process Proc(Ctx, Cmd.Program, Cmd.Args, |
| 432 | + boost::process::v2::process_start_dir(WorkDir), |
| 433 | + boost::process::v2::process_environment(ProcessEnv)); |
| 434 | + return Proc.wait(); |
| 435 | +#else |
294 | 436 | boost::process::environment ProcessEnv;
|
295 | 437 |
|
296 | 438 | // prepare environment
|
@@ -321,6 +463,7 @@ int Process::system(const Command& Cmd, const Environment& Env)
|
321 | 463 | boost::process::args = Cmd.Args,
|
322 | 464 | boost::process::start_dir = WorkDir,
|
323 | 465 | ProcessEnv);
|
| 466 | +#endif |
324 | 467 | }
|
325 | 468 |
|
326 | 469 |
|
|
0 commit comments