PandA-2024.02
ToolManager.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
44 #include "ToolManager.hpp"
45 
46 #include "Parameter.hpp"
47 #include "constant_strings.hpp"
48 #include "dbgPrintHelper.hpp"
49 #include "fileIO.hpp"
50 #include "string_manipulation.hpp"
51 
52 #include <filesystem>
53 
54 #define OUTPUT_FILE GetPath("__stdouterr")
55 
56 // constructor
58  : Param(_Param), local(true), debug_level(_Param->get_class_debug_level(GET_CLASS(*this)))
59 {
60 }
61 
62 // destructor
64 {
65  if(std::filesystem::exists(OUTPUT_FILE))
66  {
67  std::filesystem::remove(OUTPUT_FILE);
68  }
69 }
70 
71 int ToolManager::execute_command(const std::string& _command_, const std::string& error_message,
72  const std::string& log_file, bool permissive, bool throw_message)
73 {
75  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Executing command: " + _command_);
76  THROW_ASSERT(!log_file.empty(), "Log file not set");
77  int ret = PandaSystem(Param, _command_, true, log_file);
78  if(IsError(ret))
79  {
80  if(permissive)
81  {
82  if(throw_message)
83  {
84  THROW_WARNING(error_message);
85  }
86  }
87  else
88  {
90  if(!log_file.empty())
91  {
92  CopyStdout(log_file);
93  }
94  THROW_ERROR(error_message);
95  }
96  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Executed command: " + _command_);
97  }
98  else
99  {
100  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Executed command: " + _command_);
101  }
102  return ret;
103 }
104 
105 int ToolManager::check_command(const std::string& _tool_, const std::string& setupscr, const std::string& _host_,
106  bool permissive)
107 {
108  std::string command;
109  if(!_host_.empty())
110  {
112  command += "ssh " + _host_ + " '";
113  }
115  if(!setupscr.empty())
116  {
117  if(starts_with(setupscr, "export"))
118  {
119  command += setupscr + " >& /dev/null; ";
120  }
121  else
122  {
123  command += ". " + setupscr + " >& /dev/null; ";
124  }
125  }
126 
127  command += "if test -f " + _tool_ + " ; then ";
128  command += " true; ";
129  command += "else ";
130  command += " if test `which " + _tool_ + "`; then ";
131  command += " true; ";
132  command += " else ";
133  command += " false; ";
134  command += " fi ";
135  command += "fi";
136 
137  if(!_host_.empty())
138  {
139  command += "'";
140  }
141 
142  command += ">& " + std::string(OUTPUT_FILE);
143  const auto ret = execute_command(
144  command,
145  "Problems in checking \"" + _tool_ + "\" executable" +
146  (!_host_.empty() ? " on host \"" + _host_ + "\"" +
147  (!setupscr.empty() ? " with this setup script \"" + setupscr + "\"!" : "") :
148  ""),
149  Param->getOption<std::string>(OPT_output_temporary_directory) + "/check_command_output", permissive, false);
150  return ret;
151 }
152 
153 void ToolManager::configure(const std::string& _tool_, const std::string& setupscr, const std::string& _host_,
154  const std::string& _remote_path_, bool force_remote)
155 {
156  setup_script = setupscr;
158  executable = "";
159  if(!force_remote and check_command(_tool_, setupscr, "", true) != -1)
160  {
161  if(!setupscr.empty())
162  {
163  if(starts_with(setupscr, "export"))
164  {
165  executable += setupscr + " >& /dev/null; ";
166  }
167  else
168  {
169  executable += ". " + setupscr + " >& /dev/null; ";
170  }
171  }
172  executable += _tool_;
174  }
176  else if(!_host_.empty())
177  {
179  if(check_command(_tool_, setupscr, _host_) == -1)
180  {
181  THROW_ERROR("Login problems on host \"" + _host_ + "\" or executable not available!");
182  }
183 
184  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Correctly connected to Host \"" + _host_ + "\"");
185  std::string command;
186  local = false;
187  if(!setupscr.empty())
188  {
189  if(starts_with(setupscr, "export"))
190  {
191  executable += setupscr + "; ";
192  }
193  else
194  {
195  executable += ". " + setupscr + "; ";
196  }
197  }
198  executable += _tool_;
199  host = _host_;
200  if(!_remote_path_.empty())
201  {
202  command = "ssh " + _host_ + " ";
203  command += "'mkdir -p " + _remote_path_ + "' >& " + std::string(OUTPUT_FILE);
204  execute_command(command, "Remote path cannot be created on the host machine \"" + host + "\"!",
205  Param->getOption<std::string>(OPT_output_temporary_directory) + "/configure_output");
206  }
207  remote_path = _remote_path_;
208  }
209  else
210  {
211  std::ifstream output_file(OUTPUT_FILE);
212  if(!force_remote && output_file.is_open() && !output_file.eof())
213  {
214  local = true;
215  executable = _tool_;
216  }
217  else
218  {
219  THROW_ERROR("Command \"" + _tool_ + "\" not found!");
220  }
221  }
222 }
223 
224 std::string ToolManager::create_command_line(const std::vector<std::string>& parameters) const
225 {
226  THROW_ASSERT(!parameters.empty(), "Executable has not been specified");
227  std::string command = parameters[0];
228  for(unsigned int i = 1; i < parameters.size(); i++)
229  {
230  command += (" " + parameters[i]);
231  }
232  return command;
233 }
234 
235 std::string ToolManager::create_remote_command_line(const std::vector<std::string>& parameters) const
236 {
237  std::string command = create_command_line(parameters);
238  return "ssh " + host + " 'cd " + remote_path + "; " + command + "'";
239 }
240 
241 std::vector<std::string> ToolManager::determine_paths(std::vector<std::string>& files, bool overwrite)
242 {
243  std::vector<std::string> effective_files;
244  effective_files.reserve(files.size());
245  for(auto& file : files)
246  {
247  effective_files.push_back(determine_paths(file, overwrite));
248  }
249  return effective_files;
250 }
251 
252 std::string ToolManager::determine_paths(std::string& file_name, bool overwrite)
253 {
254  std::string effective_file, file_to_be_copied;
255  bool copy = false;
256 
257  std::filesystem::path file(file_name);
258  std::string FileName = file.filename().string();
259  if(local)
260  {
261  effective_file = file_name;
262  }
263  else
264  {
265  effective_file = FileName;
266  }
267  if(!local and !overwrite)
268  {
269  std::string command = "ssh " + host + " ";
270  command += "'if test -f " + remote_path + "/" + FileName + " ; then ";
271  command += " true; ";
272  command += "else ";
273  command += " false; ";
274  command += "fi'";
275  int ret = execute_command(
276  command, "Login problems on host \"" + host + "\"!",
277  Param->getOption<std::string>(OPT_output_temporary_directory) + "/determine_paths_output", true);
278  if(ret == -1)
279  {
280  copy = true;
281  }
282  }
283  else
284  {
285  copy = true;
286  }
287  if(copy)
288  {
289  if(!std::filesystem::exists(file))
290  {
291  THROW_ERROR("File \"" + file.string() + "\" does not exists");
292  }
293  file_to_be_copied = file_name;
294  }
295 
296  file_name = file_to_be_copied;
297  return effective_file;
298 }
299 
300 void ToolManager::prepare_input_files(const std::vector<std::string>& files)
301 {
302  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Preparing input files");
303  std::vector<std::string> move_to_host(1, "scp");
304  for(const auto& i : files)
305  {
306  std::filesystem::path file(i);
307  if(!std::filesystem::exists(file))
308  {
309  THROW_ERROR("File \"" + file.string() + "\" does not exists");
310  }
311  if(!local)
312  {
313  move_to_host.push_back(i);
314  }
315  }
316  if(!local and !files.empty())
317  {
318  move_to_host.push_back(host + ":" + remote_path);
319  move_to_host.push_back(">& " + std::string(OUTPUT_FILE));
320  std::string command = create_command_line(move_to_host);
321  execute_command(command, "Input files cannot be moved on the host machine",
322  Param->getOption<std::string>(OPT_output_temporary_directory) + "/prepare_input_files_output");
323  }
324  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Prepared input files");
325 }
326 
327 int ToolManager::execute(const std::vector<std::string>& parameters, const std::vector<std::string>& input_files,
328  const std::vector<std::string>& output_files, const std::string& log_file, bool permissive)
329 {
330  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Invoking tool execution");
331  THROW_ASSERT(!log_file.empty(), "Log file is empty");
333  prepare_input_files(input_files);
334 
336  remove_files(input_files, output_files);
337 
339  std::vector<std::string> command_line(1, executable);
340  for(const auto& parameter : parameters)
341  {
342  command_line.push_back(parameter);
343  }
344  std::string command = local ? create_command_line(command_line) : create_remote_command_line(command_line);
345 
346  THROW_ASSERT(!log_file.empty(), "Log file not set during executable " + executable);
347  const auto ret = execute_command(command, "Returned error code!", log_file, permissive);
348 
350  check_output_files(output_files);
351  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Invoked tool execution");
352 
353  return ret;
354 }
355 
356 void ToolManager::remove_files(const std::vector<std::string>& input_files, const std::vector<std::string>& files)
357 {
358  std::vector<std::string> removing(1, "rm -rf");
359  for(const auto& file : files)
360  {
361  if(std::filesystem::exists(file) and std::find(input_files.begin(), input_files.end(), file) == input_files.end())
362  {
363  removing.push_back(file);
364  std::filesystem::remove(file);
365  }
366  }
367  if(removing.size() == 1)
368  {
369  return;
370  }
371  std::string command = local ? create_command_line(removing) : create_remote_command_line(removing);
372  execute_command(command, "Files cannot correctly removed",
373  Param->getOption<std::string>(OPT_output_temporary_directory) + "/remove_files_output");
374 }
375 
376 void ToolManager::check_output_files(const std::vector<std::string>& files)
377 {
378  std::vector<std::string> move_from_host(1, "scp ");
379  for(const auto& i : files)
380  {
381  if(local)
382  {
383  std::filesystem::path file(i);
384  if(!std::filesystem::exists(file))
385  {
386  THROW_ERROR("File \"" + file.string() + "\" has not been correctly created");
387  }
388  }
389  else
390  {
391  move_from_host.push_back(host + ":" + remote_path + "/" + i);
392  }
393  }
394  if(!local)
395  {
396  move_from_host.emplace_back(".");
397  move_from_host.push_back(">& " + std::string(OUTPUT_FILE));
398  std::string command = create_command_line(move_from_host);
399  auto output_level = Param->getOption<unsigned int>(OPT_output_level);
400  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, " Moving output files from the host machine...");
401  execute_command(command, "Generated files cannot be moved from the host machine",
402  Param->getOption<std::string>(OPT_output_temporary_directory) + "/check_output_files_output");
403  }
404 }
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
std::string create_remote_command_line(const std::vector< std::string > &parameters) const
Generate the command to the executed on the remote host.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
File containing functions and utilities to support the printing of debug messagges.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void check_output_files(const std::vector< std::string > &files)
Check that the output files have been correctly generated.
std::string host
this string represent the host machine if remote
Definition: ToolManager.hpp:69
#define OUTPUT_FILE
Definition: ToolManager.cpp:54
bool local
flag to specify if the executable is local (true) or remote (false)
Definition: ToolManager.hpp:66
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
Auxiliary methods for manipulating string.
void prepare_input_files(const std::vector< std::string > &files)
Check that the input files exist.
bool IsError(const int error_value)
Utility include.
Definition: exceptions.cpp:58
std::string remote_path
it represents the paths on the host where the files have to be copied
Definition: ToolManager.hpp:71
void configure(const std::string &_tool_, const std::string &setupscr, const std::string &_host_="", const std::string &_remote_path_="", bool force_remote=false)
Configuration of the tool.
bool starts_with(const std::string &str, const std::string &pattern)
const ParameterConstRef Param
The set of parameters passed to the tool.
Definition: ToolManager.hpp:57
std::vector< std::string > determine_paths(std::vector< std::string > &files, bool overwrite=true)
Determine the relative paths of the inputs files.
utility function used to read files.
ToolManager(const ParameterConstRef &Param)
Constructor.
Definition: ToolManager.cpp:57
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
virtual ~ToolManager()
Destructor.
Definition: ToolManager.cpp:63
list command
Definition: test_panda.py:921
void remove_files(const std::vector< std::string > &input_files, const std::vector< std::string > &files)
Removed the specified files.
int execute_command(const std::string &_command_, const std::string &error_message, const std::string &log_file, bool permissive=false, bool throw_message=true)
Execute the command and check the return code.
Definition: ToolManager.cpp:71
int PandaSystem(const ParameterConstRef Param, const std::string &system_command, bool host_exec, const std::string &output, const unsigned int type, const bool background, const size_t timeout)
System call forcing execution with bash.
Definition: fileIO.cpp:78
int check_command(const std::string &_tool_, const std::string &setupscr, const std::string &_host_, bool permissive=false)
Check if a command exist on a given host provided a configuration script.
Class to manage a wrapped tool.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
std::string create_command_line(const std::vector< std::string > &parameters) const
Simply creates the command line starting from the list of parameters.
this class is used to manage the command-line or XML options.
constant strings
std::string executable
this string represent the path of the executable
Definition: ToolManager.hpp:60
#define PRINT_OUT_MEX(profLevel, curprofLevel, mex)
void CopyStdout(const std::string &filename)
Copy a file to the standard output.
Definition: fileIO.hpp:106
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
int debug_level
debug level of the class
Definition: ToolManager.hpp:74
int execute(const std::vector< std::string > &parameters, const std::vector< std::string > &input_files, const std::vector< std::string > &output_files=std::vector< std::string >(), const std::string &log_file=std::string(), bool permissive=false)
Execute the tool.
std::string setup_script
this string has the script used to setup the environment for the executable
Definition: ToolManager.hpp:63
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:56 for PandA-2024.02 by doxygen 1.8.13