Salome HOME
7ee23c35a3f2f5d8410444309a8a827f31ea57e4
[tools/libbatch.git] / src / Core / CommandsOverloader.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 /*
23  * CommandsOverloader.cxx :
24  *
25  * Author : Margarita KARPUNINA - OCC
26  * Date   : October 2022
27  *
28  */
29
30 #include <fstream>
31 #include <set>
32 #include <sstream>
33
34 #include <libbatch_config.h>
35
36 #include "CommandsOverloader.hxx"
37
38 #include "RunTimeException.hxx"
39
40 using namespace std;
41
42
43 namespace Batch {
44
45   static set<string> supportedCmds({"RM", "SH", "CP", "MKDIR", "RSH", "RCP", "SSH", "SCP", "RSYNC"});
46
47   /*!
48    * Constructor.
49    */
50   CommandsOverloader::CommandsOverloader()
51   {    
52   }
53
54   /*!
55    * Destructor.
56    */
57   CommandsOverloader::~CommandsOverloader()
58   {
59   }
60
61   /*!
62    * Return the CommandsOverloader singleton.
63    */
64   CommandsOverloader& CommandsOverloader::getInstance () {
65     static CommandsOverloader instance;
66     return instance;
67   }
68
69   /*!
70    * Return an overridden definition of RM command.
71    */
72   string CommandsOverloader::RM_Command() {
73     string cmd = CMD_Command("RM");
74     return (cmd.empty() ? RM_COMMAND : cmd);
75   }
76
77   /*!
78    * Return an overridden definition of SH command.
79    */
80   string CommandsOverloader::SH_Command() {
81     string cmd = CMD_Command("SH");
82     return (cmd.empty() ? SH_COMMAND : cmd);
83   }
84
85   /*!
86    * Return an overridden definition of CP command.
87    */
88   string CommandsOverloader::CP_Command() {
89     string cmd = CMD_Command("CP");
90     return (cmd.empty() ? CP_COMMAND : cmd);
91   }
92
93   /*!
94    * Return an overridden definition of MKDIR command.
95    */
96   string CommandsOverloader::MKDIR_Command() {
97     string cmd = CMD_Command("MKDIR");
98     return (cmd.empty() ? MKDIR_COMMAND : cmd);
99   }
100
101   /*!
102    * Return an overridden definition of RSH command.
103    */
104   string CommandsOverloader::RSH_Command() {
105     string cmd = CMD_Command("RSH");
106     return (cmd.empty() ? RSH_COMMAND : cmd);
107   }
108
109   /*!
110    * Return an overridden definition of RCP command.
111    */
112   string CommandsOverloader::RCP_Command() {
113     string cmd = CMD_Command("RCP");
114     return (cmd.empty() ? RCP_COMMAND : cmd);
115   }
116
117   /*!
118    * Return an overridden definition of SSH command.
119    */
120   string CommandsOverloader::SSH_Command() {
121     string cmd = CMD_Command("SSH");
122     return (cmd.empty() ? SSH_COMMAND : cmd);
123   }
124
125   /*!
126    * Return an overridden definition of SCP command.
127    */
128   string CommandsOverloader::SCP_Command() {
129     string cmd = CMD_Command("SCP");
130     return (cmd.empty() ? SCP_COMMAND : cmd);
131   }
132
133   /*!
134    * Return an overridden definition of RSYNC command.
135    */
136   string CommandsOverloader::RSYNC_Command() {
137     string cmd = CMD_Command("RSYNC");
138      return (cmd.empty() ? RSYNC_COMMAND : cmd);
139   }
140
141   /*!
142    * Parse text file with the given file name and fill in the map of 
143    * <CMD> - <associated command desired by the user at runtime>.
144    * \param theFilename the name of text file to be parsed
145    */
146   void CommandsOverloader::parse(const std::string & theFilename) {
147     ifstream fileStream(theFilename.c_str());
148     if (!fileStream) {
149       stringstream errMsg;
150       errMsg << "Can't open file with overridden commands definitions " << theFilename;
151       throw RunTimeException(errMsg.str());
152     }
153     string line;
154     int lineNumber = 1;
155     while (getline(fileStream, line)) {
156       string str = line;
157       if (!str.empty()) {
158         // Find ' ' symbol and split the line
159         size_t pos = str.find_first_of(' ');
160         if (pos == string::npos) {
161           stringstream errMsg;
162           errMsg << "Wrong format of " << theFilename << " file on line " << lineNumber
163                  << ": Syntax error (missing ' ' character between key and value): " << line;
164           throw RunTimeException(errMsg.str());
165         } else {
166           string key = str.substr(0, pos);
167           string value = str.substr(pos+1);
168
169           // Check non-completeness of the file.
170           string trimmedKey = trim(key);
171           string trimmedValue = trim(value);
172           if (trimmedKey.empty() || trimmedValue.empty()) {
173             stringstream errMsg;
174             errMsg << "Wrong format of " << theFilename << " file on line " << lineNumber
175                    << ": The non-completeness of the file: " << line;
176             throw RunTimeException(errMsg.str());
177           }
178
179           // Check the presence of an unsupported command.
180           if (supportedCmds.find(trimmedKey) == supportedCmds.end()) {
181             stringstream errMsg;
182             errMsg << "Wrong format of " << theFilename << " file on line " << lineNumber
183                    << ": The presence of an unsupported command: " << trimmedKey;
184             throw RunTimeException(errMsg.str());
185           }
186
187           if (!hasKey(trimmedKey)) {
188             _cmdmap[trimmedKey] = trimmedValue;
189           }
190           else {
191             // Redifinition of already overloaded command is found.
192             stringstream errMsg;
193             errMsg << "Wrong format of " << theFilename << " file on line " << lineNumber
194                    <<": A repetition of the " << trimmedKey << " key in several lines.";
195             throw RunTimeException(errMsg.str());
196           }
197         }
198       }
199       ++lineNumber;
200     }
201     fileStream.close();
202   }
203
204   /*!
205    * Strip leading and trailing spaces in the given string.
206    * \param theStr string to be stripped
207    * \return stripped string
208    */
209   std::string CommandsOverloader::trim(const std::string & theStr) const noexcept
210   {
211     size_t beg = theStr.find_first_not_of(" \t");
212     if (beg == string::npos) beg = 0;
213     size_t end = theStr.find_last_not_of(" \t");
214     return theStr.substr(beg, end-beg+1);
215   }
216
217   /*!
218    * Return an overridden definition of the given command.
219    * \param theKey command name
220    * \return overridden definition of the given command
221    */
222   string CommandsOverloader::CMD_Command(const std::string & theKey) {
223     if (_cmdmap.empty()) {
224       const char * filename = getenv("LIBBATCH_OVERRIDE_CMDS");
225       if (filename != NULL) {
226         // Environment variable LIBBATCH_OVERRIDE_CMDS is defined.
227         // Parse text file pointed by LIBBATCH_OVERRIDE_CMDS environment variable.
228         parse(filename);
229         // Note: If environment variable LIBBATCH_OVERRIDE_CMDS is not defined,
230         // use command configuration established at compile time.
231       }
232     }
233
234     return (hasKey(theKey) ? _cmdmap[theKey] : string());
235   }
236
237   /*!
238    * Check, if commands map contains the given command key.
239    * \param theKey command name
240    * \return true, if command key exists in the map
241    */
242   bool CommandsOverloader::hasKey(const string & theKey) const
243   {
244     return (_cmdmap.find(theKey) != _cmdmap.end());
245   }
246
247 }