Gazebo Utils

API Reference

2.2.0
Subprocess.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #ifndef GZ_UTILS__SUBPROCESS_HH_
19 #define GZ_UTILS__SUBPROCESS_HH_
20 
21 #include "detail/subprocess.h"
22 #include "gz/utils/Environment.hh"
23 
24 #include <iostream>
25 #include <string>
26 #include <vector>
27 #include <utility>
28 
29 #include <gz/utils/detail/subprocess.h>
30 
31 // This header contains a wrapper to the cross-platform subprocess library.
32 // It can be used to spawn processes to interact with, primarily for testing.
33 
34 namespace gz
35 {
36 namespace utils
37 {
38 
41 {
49  public: explicit Subprocess(const std::vector<std::string> &_commandLine):
50  commandLine(_commandLine),
51  environment({}),
52  inheritEnvironment(true)
53  {
54  this->Create();
55  }
56 
66  public: Subprocess(const std::vector<std::string> &_commandLine,
67  gz::utils::EnvironmentMap _environment):
68  commandLine(_commandLine),
69  environment(std::move(_environment)),
70  inheritEnvironment(false)
71  {
72  this->Create();
73  }
74 
84  public: Subprocess(const std::vector<std::string> &_commandLine,
85  const gz::utils::EnvironmentStrings &_environment):
86  Subprocess(_commandLine, gz::utils::envStringsToMap(_environment))
87  {
88  }
89 
90 
91  private: void Create()
92  {
93  if (this->process != nullptr)
94  return;
95 
96  this->process = new subprocess_s;
97 
98  auto environmentStr = gz::utils::envMapToStrings(this->environment);
99  std::vector<const char*> environmentCstr;
100  std::vector<const char*> commandLineCstr;
101 
102  for (const auto &val : this->commandLine)
103  {
104  commandLineCstr.push_back(val.c_str());
105  }
106  commandLineCstr.push_back(nullptr);
107 
108  if (!this->inheritEnvironment)
109  {
110  for (const auto &val : environmentStr)
111  {
112  environmentCstr.push_back(val.c_str());
113  }
114  environmentCstr.push_back(nullptr);
115  }
116 
117  int ret = -1;
118  if (!this->inheritEnvironment)
119  {
120  ret = subprocess_create_ex(commandLineCstr.data(),
121  0, environmentCstr.data(), this->process);
122  }
123  else
124  {
125  ret = subprocess_create(commandLineCstr.data(),
126  subprocess_option_inherit_environment,
127  this->process);
128  }
129 
130  if (0 != ret)
131  {
132  std::cerr << "failed to create subprocess" << std::endl;
133  delete this->process;
134  this->process = nullptr;
135  }
136  }
137 
138  public: ~Subprocess()
139  {
140  if (this->process != nullptr)
141  subprocess_destroy(this->process);
142  delete this->process;
143  }
144 
145  public: std::string Stdout()
146  {
147  std::string result;
148  if (this->process != nullptr)
149  {
150  auto *p_stdout = subprocess_stdout(this->process);
151  char buffer[128];
152  while (!feof(p_stdout))
153  {
154  if (fgets(buffer, 128, p_stdout) != nullptr)
155  result += buffer;
156  }
157  }
158  return result;
159  }
160 
161  public: std::string Stderr()
162  {
163  std::string result;
164  if (this->process != nullptr)
165  {
166  auto *p_stdout = subprocess_stderr(this->process);
167  char buffer[128];
168  while (!feof(p_stdout))
169  {
170  if (fgets(buffer, 128, p_stdout) != nullptr)
171  result += buffer;
172  }
173  }
174  return result;
175 
176  }
177 
178  public: bool Alive()
179  {
180  if (this->process != nullptr)
181  return subprocess_alive(this->process);
182  else
183  return false;
184  }
185 
186  public: bool Terminate()
187  {
188  if (this->process != nullptr)
189  return subprocess_terminate(this->process) != 0;
190  else
191  return false;
192  }
193 
194  public: int Join()
195  {
196  int return_code = -1;
197  if (this->process != nullptr)
198  {
199  auto ret = subprocess_join(this->process, &return_code);
200  if (ret != 0)
201  {
202  std::cerr << "Failed to join subprocess" << std::endl;
203  }
204  }
205 
206  return return_code;
207  }
208 
210 
212 
213  protected: bool inheritEnvironment;
214 
215  protected: subprocess_s * process {nullptr};
216 };
217 } // namespace utils
218 } // namespace gz
219 
220 #endif // GZ_UTILS__SUBPROCESS_HH_