From: Christian Van Wambeke Date: Sat, 26 May 2018 06:51:25 +0000 (+0200) Subject: new option noboolean as implicit False X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=86682c1fc62767b01878d68f6ac63bc19c0756e0;p=tools%2Fsat.git new option noboolean as implicit False --- diff --git a/commands/patch.py b/commands/patch.py index a057bd0..3b3c2ab 100644 --- a/commands/patch.py +++ b/commands/patch.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import os -import subprocess as sP +import pprint as PP import src.debug as DBG import src.returnCode as RCO @@ -75,9 +75,9 @@ class Command(_BaseCommand): # Print some informations logger.info("Patching sources of the application %s" % \ - UTS.blue(config.VARS.application)) + UTS.label(config.VARS.application)) - logger.info(" workdir = %s" % UTS.blue(config.APPLICATION.workdir)) + logger.info(" workdir = %s" % UTS.info(config.APPLICATION.workdir)) # Get the products list with products informations regarding the options products_infos = self.get_products_list(options, config) @@ -90,112 +90,87 @@ class Command(_BaseCommand): # The loop on all the products on which to apply the patches good_result = 0 for tmp, product_info in products_infos: - # Apply the patch - rc = apply_patch(config, product_info, max_product_name_len, logger) - logger.info(str(rc)) - if rc.isOk(): - good_result += 1 + # Apply the patch + rc = apply_patch(config, product_info, max_product_name_len, logger) + if rc.isOk(): + good_result += 1 # Display the results (how much passed, how much failed, etc...) - if good_result == len(products_infos): - status = "OK" + status = "OK" else: - status = "KO" + status = "KO" # write results msg = ("Patching sources of the application: <%s> (%d/%d)") % \ - (status, good_result, len(products_infos)) - logger.info(msg) - + (status, good_result, len(products_infos)) + logger.info(msg) return RCO.ReturnCode(status, msg) def apply_patch(config, product_info, max_product_name_len, logger): - """The method called to apply patches on a product - - :param config: (Config) The global configuration - :param product_info: (Config) - The configuration specific to the product to be patched - :param logger: (Logger: - The logger instance to use for the display and logging - :return: (RCO.ReturnCode) - """ - - # if the product is native, do not apply patch - if PROD.product_is_native(product_info): - # display and log - logger.info('%s: ' % UTS.label(product_info.name)) - logger.info(' ' * (max_product_name_len - len(product_info.name))) - logger.info("\n") - msg = _("The %s product is native. Do not apply any patch") % product_info.name - logger.info(msg + "\n") - return RCO.ReturnCode("OK", msg) - - if not "patches" in product_info or len(product_info.patches) == 0: - # display and log - logger.info('%s: ' % UTS.label(product_info.name)) - logger.info(' ' * (max_product_name_len - len(product_info.name))) - logger.info("\n") - msg = _("No patch for the %s product") % product_info.name - logger.info(msg + "\n") - return RCO.ReturnCode("OK", msg) - else: - # display and log - logger.info('%s: ' % UTS.label(product_info.name)) - logger.info(' ' * (max_product_name_len - len(product_info.name))) - logger.info("\n") - - if not os.path.exists(product_info.source_dir): - msg = _("No sources found for the %s product") % product_info.name - logger.error(UTS.red(msg)) - return RCO.ReturnCode("KO", msg) - - # At this point, there one or more patches and the source directory exists - retcode = [] - res = [] - # Loop on all the patches of the product - for patch in product_info.patches: - details = [] - - # Check the existence and apply the patch - if os.path.isfile(patch): - patch_cmd = "patch -p1 < %s" % patch - - # Write the command in the terminal if verbose level is at 5 - logger.info(" >%s\n" % patch_cmd) - - # Write the command in the log file (can be seen using 'sat log') - logger.logTxtFile.write("\n >%s\n" % patch_cmd) - logger.logTxtFile.flush() - - # Call the command - res_cmd = SP.call(patch_cmd, shell=True, cwd=product_info.source_dir, - stdout=logger.logTxtFile, stderr=SP.STDOUT ) - - res_cmd = (res_cmd == 0) - else: - res_cmd = False - details.append(" " + UTS.red(_("Not a valid patch: %s\n")) % patch) - - res.append(res_cmd) - - if res_cmd: - message = _("Apply patch %s") % UTS.blue(patch) - else: - message = _("Failed to apply patch %s") % UTS.red(patch) - - if config.USER.output_verbose_level >= 3: - retcode.append(" %s" % message) - else: - retcode.append("%s: %s" % (product_info.name, message)) - - if len(details) > 0: - retcode.extend(details) - - if False in res: + """The method called to apply patches on a product + + :param config: (Config) The global configuration + :param product_info: (Config) + The configuration specific to the product to be patched + :param logger: (Logger: + The logger instance to use for the display and logging + :return: (RCO.ReturnCode) + """ + + # if the product is native, do not apply patch + msg = '%s: ' % UTS.label(product_info.name) + if PROD.product_is_native(product_info): + # display and log + msg += _("The product is native. Do not apply any patch") + logger.info(msg) + return RCO.ReturnCode("OK", msg) + + if not "patches" in product_info or len(product_info.patches) == 0: + # display and log + msg += _("No patch for the product") + logger.info(msg) + return RCO.ReturnCode("OK", msg) + else: + # display and log after action + pass + + if not os.path.exists(product_info.source_dir): + msg += _("No sources found for the product") + logger.error(UTS.red(msg)) + return RCO.ReturnCode("KO", msg) + + # At this point, there one or more patches and the source directory exists + retcodes = [] + rc = "OK" + # Loop on all the patches of the product + for patch in product_info.patches: + details = [] + # Check the existence and apply the patch + if not os.path.isfile(patch): + msg += _("Patch file %s not found") % UTS.info(patch) + logger.error(msg) + continue + + cmd = """ +set -x +patch -p1 < %s +""" % patch + # Call the command + res = UTS.Popen(cmd, cwd=product_info.source_dir, logger=logger) + if not res.isOk(): rc = "KO" + resPatch = RCO.ReturnCode("KO", _("Failed to apply patch %s") % UTS.red(patch)) else: - rc = "OK" - - return RCO.ReturnCode(rc, "\n".join(retcode)) + resPatch = RCO.ReturnCode("OK", _("Apply patch %s") % UTS.info(patch)) + retcodes.append(resPatch) + + res = RCO.ReturnCodeFromList(retcodes) + if res.isOk(): + logger.info(msg + "...") + logger.trace(msg + "... %s" % res.getWhy()) + else: + logger.info(msg + "... %s" % res.getWhy()) + return res + diff --git a/commands/source.py b/commands/source.py index 94c7681..7756f58 100644 --- a/commands/source.py +++ b/commands/source.py @@ -167,7 +167,7 @@ def get_source_from_git(product_info, repo_git = product_info.git_info.repo # Display informations - msg = " %s:%s tag:%s ..." % (coflag, repo_git, product_info.git_info.tag) + msg = " %s:%s tag:%s ..." % (coflag, UTS.info(repo_git), product_info.git_info.tag) logger.info(msg) # Call the system function that do the extraction in git mode @@ -188,24 +188,21 @@ def get_source_from_archive(product_info, source_dir, logger): :return: (bool) True if it succeed, else False """ # check archive exists - if not os.path.exists(product_info.archive_info.archive_name): - raise Exception(_("Archive not found: '%s'") % \ - product_info.archive_info.archive_name) + archName = product_info.archive_info.archive_name + if not os.path.exists(archName): + raise Exception(_("Archive not found: '%s'") % archName) - logger.info('arc:%s ... ' % UTS.info(product_info.archive_info.archive_name)) + logger.info(' arc:%s ...' % UTS.info(archName)) # Call the system function that do the extraction in archive mode - retcode, NameExtractedDirectory = SYSS.archive_extract( - product_info.archive_info.archive_name, - source_dir.dir(), logger) + retcode = SYSS.archive_extract(archName, source_dir.dir(), logger) + nameDirectory = retcode.getValue() # where extracted # Rename the source directory if # it does not match with product_info.source_dir - if (NameExtractedDirectory.replace('/', '') != - os.path.basename(product_info.source_dir)): - shutil.move(os.path.join(os.path.dirname(product_info.source_dir), - NameExtractedDirectory), - product_info.source_dir) - + baseDir = os.path.basename(product_info.source_dir) + if (nameDirectory.replace('/', '') != baseDir): + iniDir = os.path.join(os.path.dirname(product_info.source_dir), nameDirectory) + shutil.move(iniDir, product_info.source_dir) return retcode def get_source_from_dir(product_info, source_dir, logger): @@ -229,7 +226,7 @@ def get_source_from_dir(product_info, source_dir, logger): logger.error(msg) return False - logger.info('DIR: %s ... ' % UTS.info(product_info.dir_info.dir)) + logger.info(' DIR: %s ...' % UTS.info(product_info.dir_info.dir)) retcode = UTS.Path(product_info.dir_info.dir).copy(source_dir) return retcode @@ -275,17 +272,13 @@ def get_source_from_cvs(user, coflag = 'cvs' if checkout: coflag = coflag.upper() - msg = '%s:%s' % (coflag, cvs_line) - msg += " " * (pad + 50 - len(cvs_line)) + msg = " %s:%s" % (coflag, cvs_line) msg += " src:%s" % product_info.cvs_info.source - msg += " " * (pad + 1 - len(product_info.cvs_info.source)) msg += " tag:%s" % product_info.cvs_info.tag # at least one '.' is visible - msg += " %s. " % ("." * (10 - len(product_info.cvs_info.tag))) - + msg += " %s ..." % msg logger.info(msg) - # Call the system function that do the extraction in cvs mode retcode = SYSS.cvs_extract(protocol, user, product_info.cvs_info.server, @@ -320,8 +313,7 @@ def get_source_from_svn(user, coflag = 'svn' if checkout: coflag = coflag.upper() - logger.info('%s:%s ... ' % (coflag, product_info.svn_info.repo)) - + logger.info(' %s:%s ...' % (coflag, product_info.svn_info.repo)) # Call the system function that do the extraction in svn mode retcode = SYSS.svn_extract(user, product_info.svn_info.repo, diff --git a/src/loggingSat.py b/src/loggingSat.py index 5a6048d..70670d8 100755 --- a/src/loggingSat.py +++ b/src/loggingSat.py @@ -66,6 +66,7 @@ _TRACE = LOGI.INFO - 2 # trace level is just below STEP LOGI.STEP = _STEP # only for coherency, LOGI.TRACE = _TRACE # only for coherency, +_knownLevels = "CRITICAL ERROR WARNING INFO STEP TRACE DEBUG".upper().split() ################################################################# # utilities methods @@ -206,6 +207,7 @@ class LoggerSat(LOGI.Logger): LOGI.addLevelName(_STEP, "STEP") LOGI.addLevelName(_TRACE, "TRACE") self.dateLogger = "NoDateLogger" + self.dateHour = None # datehour of main command self.isClosed = False self.idCommandHandlers = 0 # incremented, 0 for main command 1, 2, etc. for micro command self.STEP = _STEP @@ -292,7 +294,12 @@ class LoggerSat(LOGI.Logger): log_dir_out = os.path.join(log_dir, "OUT") # files txt UTS.ensure_path_exists(log_dir) UTS.ensure_path_exists(log_dir_out) - datehour = config.VARS.datehour + if self.idCommandHandlers == 0: + datehour = config.VARS.datehour + self.dateHour = datehour # save dateHour for micro commands + else: + datehour = self.dateHour # micro commands have same datehour for naming files + cmd = config.VARS.command fullNameCmd = cmdInstance.getFullNameStr() hostname = config.VARS.hostname diff --git a/src/options.py b/src/options.py index 4e1a8ab..8bb831e 100644 --- a/src/options.py +++ b/src/options.py @@ -85,7 +85,8 @@ class Options(object): # in a list that contains dicts self.options = [] # The list of available option type - self.availableOptions = "boolean string int float long list list2 level".split() + self.availableOptions = "noboolean boolean string int float long list list2 level".split() + self.noArgOptions = "noboolean boolean".split() self.default = None self.results = {} @@ -192,11 +193,11 @@ class Options(object): longNameOption = [] for option in self.options: shortNameOption = shortNameOption + option['shortName'] - if option['shortName'] != "" and option['optionType'] != "boolean": + if option['shortName'] != "" and option['optionType'] not in self.noArgOptions: shortNameOption = shortNameOption + ":" if option['longName'] != "": - if option['optionType'] != "boolean": + if option['optionType'] not in self.noArgOptions: longNameOption.append(option['longName'] + "=") else: longNameOption.append(option['longName']) @@ -206,7 +207,7 @@ class Options(object): try: optlist, args = getopt.getopt(argList, shortNameOption, longNameOption) except Exception as e: - msg = str(e) + " on %s\n\n" % argList + self.get_help() + msg = str(e) + " on '%s'\n\n" % " ".join(argList) + self.get_help() raise Exception(msg) # instantiate and completing the optResult that will be returned @@ -221,6 +222,8 @@ class Options(object): option['result'] = opt[1] elif optionType == "boolean": option['result'] = True + elif optionType == "noboolean": + option['result'] = False elif optionType == "int": option['result'] = int(opt[1]) elif optionType == "float": @@ -232,16 +235,11 @@ class Options(object): option['result'] = list() option['result'].append(opt[1]) elif optionType == "level": #logger logging levels - option['result'] = opt[1] - # TODO test in (lowercase) debug info warning error critical + option['result'] = self.filterLevel(opt[1]) elif optionType == "list2": if option['result'] is None: option['result'] = list() - if opt[1].find(",") == -1: - option['result'].append(opt[1]) - else: - elts = filter(lambda l: len(l) > 0, opt[1].split(",")) - option['result'].extend(elts) + option['result'] = self.filterList2(opt[1]) optResult.__setattr__(option['destName'], option['result']) # free the option in order to be able to make @@ -251,6 +249,26 @@ class Options(object): self.results = {"optlist": optlist, "optResult": optResult, "args": args, "argList": argList} DBG.write("results", self.results) return optResult, args + + def filterLevel(self, aLevel): + """filter level logging values""" + import src.loggingSat as LOG + aLev = aLevel.upper() + knownLevels = LOG._knownLevels + maxLen = max([len(i) for i in knownLevels]) + for i in range(maxLen): + for lev in knownLevels: + if aLev == lev[:i]: + DBG.write("filterLevel", "%s -> %s" % (aLevel, lev), True) + return lev + msg = "Unknown level '%s', accepted are:\n%s" % (aLev, ",".join(knownLevels)) + raise Exception(msg) + + def filterList2(self, aStr): + """filter a list as 'KERNEL,YACS,etc.'""" + aList = aStr.strip().split(",") + return aList + def __repr__(self): """ diff --git a/src/returnCode.py b/src/returnCode.py index de6fe23..c2441b3 100644 --- a/src/returnCode.py +++ b/src/returnCode.py @@ -212,3 +212,20 @@ class ReturnCode(object): return self else: raise Exception(self.getWhy()) + +def ReturnCodeFromList(aListOfReturnCodes): + """ + Create ReturnCode from list of ReturnCode + + convenience over "+" operand + """ + res = "OK" + whyes = [] + for rc in aListOfReturnCodes: + if not rc.isOk(): + res = "KO" + whyes.append(str(rc)) + reswhy = "\n ".join(whyes) + return ReturnCode(res, "\n " + reswhy) + + \ No newline at end of file diff --git a/src/salomeTools.py b/src/salomeTools.py index 3365d44..bed28dc 100755 --- a/src/salomeTools.py +++ b/src/salomeTools.py @@ -486,18 +486,27 @@ class Sat(object): (internal use only) """ parser = Options() + parser.add_option('h', 'help', 'boolean', 'help', _("shows global help or help on a specific command.")) + parser.add_option('o', 'overwrite', 'list', "overwrite", _("overwrites a configuration parameters.")) - parser.add_option('g', 'debug', 'boolean', 'debug_mode', - _("run salomeTools in debug mode.")) - parser.add_option('v', 'verbose', 'int', "output_verbose_level", - _("change output verbose level (default is 3).")) + + parser.add_option('v', 'verbose', 'level', "output_verbose_level", + _("change console output verbose level (default is INFO).")) + + parser.add_option('d', 'devel', 'noboolean', "development mode", + _("""\ +development mode (more verbose error/exception messages) +(default is production mode).""")) + parser.add_option('b', 'batch', 'boolean', "batch", _("batch mode (no question).")) - parser.add_option('t', 'all_in_terminal', 'boolean', "all_in_terminal", - _("all traces in the terminal (for example compilation logs).")) + + parser.add_option('t', 'terminal_all_log', "noboolean", 'terminal_all_log', + _("all log traces in the terminal (for example compilation logs).")) + parser.add_option('l', 'logs_paths_in_file', 'string', "logs_paths_in_file", _("put the command result and paths to log files.")) return parser @@ -506,8 +515,8 @@ class Sat(object): def parseArguments(self, arguments): args = self.assumeAsList(arguments) genericOptions, remaindersArgs = self.parser.parse_args(args) - DBG.write("Sat generic options", genericOptions) - DBG.write("Sat remainders arguments", remaindersArgs) + DBG.write("Sat generic options", genericOptions, True) + DBG.write("Sat remainders arguments", remaindersArgs, True) return genericOptions, remaindersArgs