Salome HOME
Fix bug for test command
[tools/sat.git] / salomeTools.py
index 38badf80b11990208f425f519a69825ce3d7c18d..84429e4d3f5bf98be045c6a3763f879848cfa984 100755 (executable)
 #  You should have received a copy of the GNU Lesser General Public
 #  License along with this library; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
 '''This file is the main entry file to salomeTools
 '''
 
 # python imports
 import os
 import sys
+import re
+import tempfile
 import imp
 import types
 import gettext
+import traceback
 
 # salomeTools imports
 import src
@@ -97,7 +99,7 @@ class Sat(object):
         # Read the salomeTools options (the list of possible options is 
         # at the beginning of this file)
         try:
-            (options, argus) = parser.parse_args(opt.split(' '))
+            (options, argus) = parser.parse_args(opt)
         except Exception as exc:
             write_exception(exc)
             sys.exit(-1)
@@ -143,25 +145,39 @@ class Sat(object):
             # Exception for the jobs command that requires the paramiko module
             if nameCmd == "jobs":
                 try:
+                    saveout = sys.stderr
+                    ff = tempfile.TemporaryFile()
+                    sys.stderr = ff
                     import paramiko
+                    sys.stderr = saveout
                 except:
+                    sys.stderr = saveout
                     continue
 
             # load the module that has name nameCmd in dirPath
             (file_, pathname, description) = imp.find_module(nameCmd, [dirPath])
             module = imp.load_module(nameCmd, file_, pathname, description)
             
-            def run_command(args='', batch = False, verbose = -1, logger_add_link = None):
+            def run_command(args='',
+                            options=None,
+                            batch = False,
+                            verbose = -1,
+                            logger_add_link = None):
                 '''The function that will load the configuration (all pyconf)
                 and return the function run of the command corresponding to module
                 
-                :param args str: The directory path containing the commands 
+                :param args str: The arguments of the command 
                 '''
                 # Make sure the internationalization is available
                 gettext.install('salomeTools', os.path.join(satdir, 'src', 'i18n'))
                 
                 # Get the arguments in a list and remove the empty elements
-                argv_0 = args.split(" ")
+                if type(args) == type(''):
+                    # split by spaces without considering spaces in quotes
+                    argv_0 = re.findall(r'(?:"[^"]*"|[^\s"])+', args)
+                else:
+                    argv_0 = args
+                
                 if argv_0 != ['']:
                     while "" in argv_0: argv_0.remove("")
                 
@@ -178,17 +194,22 @@ class Sat(object):
                            
                 # if it is provided by the command line, get the application
                 appliToLoad = None
-                if argv != [''] and argv[0][0] != "-":
+                if argv not in [[''], []] and argv[0][0] != "-":
                     appliToLoad = argv[0].rstrip('*')
                     argv = argv[1:]
-   
+                
+                # Check if the global options of salomeTools have to be changed
+                if options:
+                    options_save = self.options
+                    self.options = options  
+
                 # read the configuration from all the pyconf files    
                 cfgManager = config.ConfigManager()
                 self.cfg = cfgManager.get_config(datadir=self.datadir, 
                                                  application=appliToLoad, 
                                                  options=self.options, 
                                                  command=__nameCmd__)
-                
+                               
                 # Set the verbose mode if called
                 if verbose > -1:
                     verbose_save = self.options.output_verbose_level
@@ -207,14 +228,20 @@ class Sat(object):
                 silent = (self.cfg.USER.output_verbose_level == 0)
 
                 # create log file
+                micro_command = False
+                if logger_add_link:
+                    micro_command = True
                 logger_command = src.logger.Logger(self.cfg, 
-                                                   silent_sysstd=silent,
-                                                   all_in_terminal=self.options.all_in_terminal)
+                                   silent_sysstd=silent,
+                                   all_in_terminal=self.options.all_in_terminal,
+                                   micro_command=micro_command)
                 
                 # Check that the path given by the logs_paths_in_file option
                 # is a file path that can be written
-                if self.options.logs_paths_in_file:
+                if self.options.logs_paths_in_file and not micro_command:
                     try:
+                        self.options.logs_paths_in_file = os.path.abspath(
+                                                self.options.logs_paths_in_file)
                         dir_file = os.path.dirname(self.options.logs_paths_in_file)
                         if not os.path.exists(dir_file):
                             os.makedirs(dir_file)
@@ -225,20 +252,48 @@ class Sat(object):
                     except Exception as e:
                         msg = _("WARNING: the logs_paths_in_file option will "
                                 "not be taken into account.\nHere is the error:")
-                        logger_command.write("%s\n%s\n\n" % (src.printcolors.printcWarning(msg), str(e)))
+                        logger_command.write("%s\n%s\n\n" % (
+                                             src.printcolors.printcWarning(msg),
+                                             str(e)))
                         self.options.logs_paths_in_file = None
                 
+                options_launched = ""
+                res = None
                 try:
-                    res = None
                     # Execute the hooks (if there is any) 
                     # and run method of the command
                     self.run_hook(__nameCmd__, C_PRE_HOOK, logger_command)
                     res = __module__.run(argv, self, logger_command)
                     self.run_hook(__nameCmd__, C_POST_HOOK, logger_command)
-                    
-                    # set res if it is not set in the command
                     if res is None:
                         res = 0
+                        
+                except Exception as e:
+                    # Get error
+                    logger_command.write("\n***** ", 1)
+                    logger_command.write(src.printcolors.printcError(
+                                                       "salomeTools ERROR:"), 1)
+                    logger_command.write("\n" + str(e) + "\n\n", 1)
+                    # get stack
+                    __, __, exc_traceback = sys.exc_info()
+                    fp = tempfile.TemporaryFile()
+                    traceback.print_tb(exc_traceback, file=fp)
+                    fp.seek(0)
+                    stack = fp.read()
+                    verbosity = 5
+                    if self.options.debug_mode:
+                        verbosity = 1
+                    logger_command.write("TRACEBACK: %s" % stack.replace('"',"'"),
+                                         verbosity)
+                finally:
+                    # set res if it is not set in the command
+                    if res is None:
+                        res = 1
+                                            
+                    # come back to the original global options
+                    if options:
+                        options_launched = get_text_from_options(self.options)
+                        self.options = options_save
                     
                     # come back in the original batch mode if 
                     # batch argument was called
@@ -255,46 +310,45 @@ class Sat(object):
                     launchedCommand = ' '.join([self.cfg.VARS.salometoolsway +
                                                 os.path.sep +
                                                 'sat',
+                                                options_launched,
                                                 __nameCmd__, 
-                                                args])
+                                                ' '.join(argv_0)])
                     launchedCommand = launchedCommand.replace('"', "'")
                     
                     # Add a link to the parent command      
                     if logger_add_link is not None:
-                        xmlLinks = logger_add_link.xmlFile.xmlroot.find(
-                                                                    "Links")
-                        src.xmlManager.add_simple_node(xmlLinks, 
-                                                       "link", 
-                                            text = logger_command.logFileName,
-                                            attrib = {"command" : __nameCmd__,
-                                                      "passed" : res,
-                                        "launchedCommand" : launchedCommand})
+                        logger_add_link.add_link(logger_command.logFileName,
+                                                 __nameCmd__,
+                                                 res,
+                                                 launchedCommand)
                         logger_add_link.l_logFiles += logger_command.l_logFiles
-
-                finally:
-                    launchedCommand = ' '.join([self.cfg.VARS.salometoolsway +
-                                                os.path.sep +
-                                                'sat',
-                                                __nameCmd__, 
-                                                args])
-                    launchedCommand = launchedCommand.replace('"', "'")
-                    
+                                            
                     # Put the final attributes corresponding to end time and
                     # Write the file to the hard drive
                     logger_command.end_write(
                                         {"launchedCommand" : launchedCommand})
                     
-                    if res is None:
+                    if res != 0:
                         res = 1
+                        
+                    # print the log file path if 
+                    # the maximum verbose mode is invoked
+                    if not micro_command:
+                        logger_command.write("\nPath to the xml log file :\n",
+                                             5)
+                        logger_command.write("%s\n\n" % src.printcolors.printcInfo(
+                                                logger_command.logFilePath), 5)
+
                     # If the logs_paths_in_file was called, write the result
                     # and log files in the given file path
-                    if self.options.logs_paths_in_file:
+                    if self.options.logs_paths_in_file and not micro_command:
                         file_res = open(self.options.logs_paths_in_file, "w")
                         file_res.write(str(res) + "\n")
                         for i, filepath in enumerate(logger_command.l_logFiles):
                             file_res.write(filepath)
                             if i < len(logger_command.l_logFiles):
                                 file_res.write("\n")
+                                file_res.flush()
                 
                 return res
 
@@ -408,7 +462,22 @@ class Sat(object):
         (file_, pathname, description) = imp.find_module(module, [cmdsdir])
         module = imp.load_module(module, file_, pathname, description)
         return module
+
+def get_text_from_options(options):
+    text_options = ""
+    for attr in dir(options):
+        if attr.startswith("__"):
+            continue
+        if options.__getattr__(attr) != None:
+            option_contain = options.__getattr__(attr)
+            if type(option_contain)==type([]):
+                option_contain = ",".join(option_contain)
+            if type(option_contain)==type(True):
+                option_contain = ""
+            text_options+= "--%s %s " % (attr, option_contain)
+    return text_options
+                
+
 def print_version():
     '''prints salomeTools version (in src/internal_config/salomeTools.pyconf)
     '''
@@ -464,23 +533,13 @@ if __name__ == "__main__":
         sys.exit(0)
     
     # instantiate the salomeTools class with correct options
-    sat = Sat(' '.join(sys.argv[1:]))
+    sat = Sat(sys.argv[1:])
     # the command called
     command = args[0]
     # get dynamically the command function to call
     fun_command = sat.__getattr__(command)
-    # call the command with two cases : mode debug or not
-    if options.debug_mode:
-        # call classically the command and if it fails, 
-        # show exception and stack (usual python mode)
-        code = fun_command(' '.join(args[1:]))
-    else:
-        # catch exception in order to show less verbose but elegant message
-        try:
-            code = fun_command(' '.join(args[1:]))
-        except Exception as exc:
-            code = 1
-            write_exception(exc)
+    # Run the command using the arguments
+    code = fun_command(args[1:])
     
     # exit salomeTools with the right code (0 if no errors, else 1)
     if code is None: code = 0