def run(self, i): try: s = "cmd=%s" % self.command if self.execute_cmd( self.command, self.target_directory, string_info=s) != 0: # use uncolored string for cmake self.failed = True except: # this fails, if the supplied command line is corrupted print(tools.red("Failed")) self.failed = True # if self fails, add error to number of errors if self.failed: self.nErrors += 1 # move the std.out file old_std = os.path.join(self.target_directory, 'std.out') new_std = os.path.join(self.target_directory, 'std-%04d.out' % i) if os.path.exists(os.path.abspath(old_std)): # check if file exists os.rename(old_std, new_std) # move the err.out file old_err = os.path.join(self.target_directory, 'std.err') new_err = os.path.join(self.target_directory, 'std-%04d.err' % i) if os.path.exists(os.path.abspath(old_err)): # check if file exists os.rename(old_err, new_err)
def names(self): # read combinations in 'parameter.ini' for renaming the results combis, digits = getCombinations(self.parameter_file, CheckForMultipleKeys=True) # set "suffix" logging.getLogger('logger').debug("") logging.getLogger('logger').debug("") logging.getLogger('logger').debug(tools.yellow('=' * 132)) logging.getLogger('logger').debug("Creating output name:") if not os.path.exists(self.names_file): print( tools.red("parameter_rename.ini file not found under: '%s'" % self.names_file)) exit(1) options_names, exclusions, noCrossCombinations = readKeyValueFile( self.names_file) suffix = '' for option in options_names: logging.getLogger('logger').debug("option.name=%s" % str(option.name)) found, number = isKeyOf(combis[0], option.name) if found: logging.getLogger('logger').debug( str(option.name) + " = " + tools.blue(str(found)) + " (%s)" % combis[0][option.name]) suffix += "_" + str( option.values[0]) + "%s" % (combis[0][option.name]) else: print( str(option.name) + " = " + tools.red(str(found)) + " (NOT FOUND!)") print("Name=[%s]" % tools.red(suffix)) logging.getLogger('logger').debug(tools.yellow('=' * 132)) logging.getLogger('logger').debug("") logging.getLogger('logger').debug("") self.suffix = suffix self.prefix = suffix[1:] + "_"
def __init__(self, cwd, command, names_file, names2_file, parameter_file): ExternalCommand.__init__(self) self.target_directory = cwd self.nErrors = 0 self.command = command self.failed = False self.names_file = os.path.join(cwd, names_file) # check if file exists if not os.path.exists(self.names_file): print( tools.red("parameter_rename.ini file not found under: '%s'" % self.names_file)) exit(1) self.names2_file = os.path.join(cwd, names2_file) # check if file exists if not os.path.exists(self.names2_file): print( tools.red("parameter_change.ini file not found under: '%s'" % self.names2_file)) exit(1) self.parameter_file = os.path.join(cwd, parameter_file) # check if file exists if not os.path.exists(self.parameter_file): print( tools.red("parameter.ini file not found under: '%s'" % self.parameter_file)) exit(1) # display used files print("Using the following input files") print("parameter_rename.ini".ljust(25), " = [", self.names_file, "]") print("parameter_change.ini".ljust(25), " = [", self.names2_file, "]") print("parameter.ini ".ljust(25), " = [", self.parameter_file, "]") print('=' * 132)
def readValueFromFile(filename, key): # Read the value of a single key from a file. Workflow: # 1. Read file line by line: # 1.1 ignore exclusion (if line starts with 'exclude:') # 1.2 ignore noCrossCombination (if line starts with 'nocrosscombination:') # 1.3 get option and its values from line, if the key is the same as the key passed to the routine, break and return the matching value found = os.path.exists(filename) # check if directory exists if not found: #raise getCombinationException(filename) # file not found raise Exception( tools.red("getCombination failed. file '%s' not found." % filename)) # 1. read options and exclusions from the file with open(filename) as f: for line in f.readlines(): # iterate over all lines of the file line = re.sub( r"\s+", "", line) # remove all whitespaces ("\s" is the whitespac symbol) line = re.sub( r"\\s", " ", line ) # add new whitespaces for all occurrances of "\s" in the string ("\s" is NOT the whitespace symbol here) if line.startswith('!'): continue # skip lines starting with a comment line = line.split('!')[0] # remove comments # 1.1 read an exclusion if line.lower().startswith('exclude:'): continue # ignore exclusion # 1.2 read a noCrossCombination if line.lower().startswith('nocrosscombination:'): continue # ignore noCrossCombination # 1.3 read a option and its possible values if '=' in line: (currentKey, currentValue) = line.split('=', 1) # split line at '=' if key.lower() == currentKey.lower( ): # check if the key matches the one passed to the routine break # if so, break from the for loop else: continue # better luck in the next line return currentValue
def SummaryOfErrors(builds, args) : """ General workflow: 1. loop over all builds, examples, command_lines, runs and for every run set the output strings and get the maximal lengths of those strings 2. print header 3. loop over all builds 3.1 print some information of the build 3.2 within each build loop over all examples, command_lines, runs and for every run print some information: 3.2.1 print an empty separation line if number of MPI threads changes 3.2.2 print (only if changes) a line with all run parameters except the inner most, which is printed in 3.2.3 3.2.3 print a line with following information: run.globalnumber, run.parameters[0] (the one not printed in 3.2.2), run.target_directory, MPI, run.walltime, run.result 3.2.4 print the analyze results line by line """ param_str_old = "" str_MPI_old = "-" restart_file_old = "-" # 1. loop over all runs and set output strings max_lens = collections.OrderedDict([ ("#run",4) , ("options",7) , ("path",4) , ("MPI",3), ("time",4) , ("Info",4) ]) for build in builds : for example in build.examples : for command_line in example.command_lines : for run in command_line.runs : run.output_strings = {} run.output_strings['#run'] = str(run.globalnumber) run.output_strings['options'] = "" # Check number of variations in parameter list(run.digits.items())[0][1] restart_file = command_line.parameters.get('restart_file', None) run.restart_file_used = False if list(run.digits.items())[0][1] > 0 : run.output_strings['options'] += "%s=%s"%(list(run.parameters.items())[0]) # print parameter and value as [parameter]=[value] elif restart_file : # if no parameter is varied, check if the restart file is used run.restart_file_used = True if restart_file != restart_file_old: # only display once run.output_strings['options'] += "%s=%s"%('restart_file',restart_file) # print parameter and value as [parameter]=[value] restart_file_old = restart_file run.output_strings['path'] = os.path.relpath(run.target_directory,OutputDirectory.output_dir) run.output_strings['MPI'] = command_line.parameters.get('MPI', '-') run.output_strings['time'] = "%2.1f" % run.walltime run.output_strings['Info'] = run.result for key in run.output_strings.keys() : max_lens[key] = max(max_lens[key], len(run.output_strings[key])) # set max column widths for summary table # 2. print header print(132*"=") print(" Summary of Errors"+"\n") spacing = 1 for key, value in list(max_lens.items()) : print(key.ljust(value),spacing*' ', end=' ') # skip linebreak print("") # 3. loop over alls builds for build in builds : # 3.1 print cmake flags if no external binary was used for execution print('-'*132) if isinstance(build, check.Standalone) : print("Binary supplied externally under ",build.binary_path) elif isinstance(build, check.Build) : print("Build %d of %d (%s) compiled with in [%.2f sec]:" % (build.number, len(builds), build.result, build.walltime)) print(" ".join(build.cmake_cmd_color)) if build.return_code != 0 : break # stop output as soon as a failed build in encountered # 3.2 loop over all examples, command_lines and runs for example in build.examples : for command_line in example.command_lines : for run in command_line.runs : # 3.2.1 print separation line only if MPI threads change if run.output_strings["MPI"] != str_MPI_old : print("") str_MPI_old = run.output_strings["MPI"] # 3.2.2 print the run parameters, except the inner most (this one is displayed in # 3.2.3) paramsWithMultipleValues = [item for item in list(run.parameters.items())[1:] if run.digits[item[0]]>0 ] param_str =", ".join(["%s=%s"%item for item in paramsWithMultipleValues]) # skip first index restart_file = command_line.parameters.get('restart_file', None) if not param_str_old.startswith(param_str) or len(param_str_old) == 0: # Only print when the parameter set changes if restart_file and not run.restart_file_used and restart_file != restart_file_old: # Add restart file once if len(param_str) > 0: param_str += ", " param_str += "%s=%s" % ('restart_file',restart_file) restart_file_old = restart_file if len(param_str) > 0: print("".ljust(max_lens["#run"]), spacing*' ', tools.yellow(param_str)) param_str_old = param_str # 3.2.3 print all output_strings for key,value in list(max_lens.items()) : # Print options with .ljust if key == "options" : print(tools.yellow(run.output_strings[key].ljust(value)), end=' ') # skip linebreak elif key == "MPI" and any([args.noMPI, args.noMPIautomatic]) : print(tools.yellow("1"), end=' ') # skip linebreak else : print(run.output_strings[key].ljust(value), end=' ') # skip linebreak print(spacing*' ', end=' ') # skip linebreak print("") # 3.2.4 print the analyze results line by line for result in run.analyze_results : print(tools.red(result).rjust(150)) # 3.2.5 print the external results line by line for error in run.externals_errors : print(tools.red(error).rjust(150)) # print an empty line after all errors were displayed if len(run.analyze_results) > 0 or len(run.externals_errors): print("")
def execute_cmd(self, cmd, target_directory, name="std", string_info=None, environment=None, displayOnFailure=True): """Execute an external program specified by 'cmd'. The working directory of this program is set to target_directory. Returns the return_code of the external program. cmd : command given as list of strings (the command is split at every white space occurrence) target_directory : path to directory where the cmd command is to be executed name (optional, default="std") : [name].std and [name].err files are created for storing the std and err output of the job string_info (optional, default=None) : Print info regarding the command that is executed before execution environment (optional, default=None) : run cmd command with environment variables as given by environment=os.environ (and possibly modified) displayOnFailure (optional, default=True) : Display error information if the code has failed to run: the last 15 lines of std.out and the last 15 lines of std.err """ # Display string_info if string_info is not None: print(string_info) # check that only cmd arguments of type 'list' are supplied to this function if type(cmd) != type([]): print( tools.red("cmd must be of type 'list'\ncmd=") + str(cmd) + tools.red(" and type(cmd)="), type(cmd)) exit(1) sys.stdout.flush( ) # flush output here, because the subprocess will force buffering until it is finished log = logging.getLogger('logger') workingDir = os.path.abspath(target_directory) log.debug(workingDir) log.debug(cmd) start = timer() (pipeOut_r, pipeOut_w) = os.pipe() (pipeErr_r, pipeErr_w) = os.pipe() self.stdout = [] self.stderr = [] bufOut = "" bufErr = "" if environment is None: self.process = subprocess.Popen(cmd, \ stdout = pipeOut_w, \ stderr = pipeErr_w, \ universal_newlines = True, \ cwd = workingDir) else: self.process = subprocess.Popen(cmd, \ stdout = pipeOut_w, \ stderr = pipeErr_w, \ universal_newlines = True, \ cwd = workingDir, \ env = environment) # .poll() is None means that the child is still running while self.process.poll() is None: # Loop as long as the select mechanism indicates there is data to be read from the buffer # 1. std.out while len(select.select([pipeOut_r], [], [], 0)[0]) == 1: # Read up to a 1 KB chunk of data out_s = os.read(pipeOut_r, 1024) if not isinstance(out_s, str): out_s = out_s.decode("utf-8", 'ignore') bufOut = bufOut + out_s tmp = bufOut.split('\n') for line in tmp[:-1]: self.stdout.append(line + '\n') log.debug(line) bufOut = tmp[-1] # 1. err.out while len(select.select([pipeErr_r], [], [], 0)[0]) == 1: # Read up to a 1 KB chunk of data out_s = os.read(pipeErr_r, 1024) if not isinstance(out_s, str): out_s = out_s.decode("utf-8", 'ignore') bufErr = bufErr + out_s tmp = bufErr.split('\n') for line in tmp[:-1]: self.stderr.append(line + '\n') log.info(line) bufErr = tmp[-1] os.close(pipeOut_w) os.close(pipeOut_r) os.close(pipeErr_w) os.close(pipeErr_r) self.return_code = self.process.returncode end = timer() self.walltime = end - start # write std.out and err.out to disk self.stdout_filename = os.path.join(target_directory, name + ".out") with open(self.stdout_filename, 'w') as f: for line in self.stdout: f.write(line) if self.return_code != 0: self.result = tools.red("Failed") self.stderr_filename = os.path.join(target_directory, name + ".err") with open(self.stderr_filename, 'w') as f: for line in self.stderr: f.write(line) else: self.result = tools.blue("Successful") # Display result (Successful or Failed) if string_info is not None: # display result and wall time in previous line and shift the text by ncols columns to the right # Note that f-strings in print statements, e.g. print(f"...."), only work in python 3 # print(f"\033[F\033[{ncols}G "+str(self.result)+" [%.2f sec]" % self.walltime) ncols = len(string_info) + 1 print("\033[F\033[%sG " % ncols + str(self.result) + " [%.2f sec]" % self.walltime) else: print(self.result + " [%.2f sec]" % self.walltime) # Display error information if the code has failed to run: the last 15 lines of std.out and the last 15 lines of std.err if log.getEffectiveLevel() != logging.DEBUG and displayOnFailure: if self.return_code != 0: for line in self.stdout[-15:]: print(tools.red("%s" % line.strip())) for line in self.stderr[-15:]: print(tools.red("%s" % line.strip())) return self.return_code
import args_parser import summary """ General workflow: 1. get the command line arguments 'args' and all valid build combinations in the check directory from 'builds.ini' 2. set the logger 'log' with the debug level from 'args' to determine the level of logging which displays output to the user 3. perform the regression check by a) building executables b) running the code c) performing the defined analyzes 4. display the summary table with information for each build, run and analysis step 5. display if regression check was successful or not and return the corresponding error code """ print('') print( tools.red(' oooooooo ====================') + tools.yellow('=====================================') + tools.green('==================== oooooooo ')) print( tools.red(' ooo oo ooo _____ ______ ') + tools.yellow(' _____ _____ _____ ______ ') + tools.green(' ___ ___ ooo oo ooo ')) print( tools.red(' oo oo oo | __ \ | ____| ') + tools.yellow(' / ____| / ____| |_ _| | ____| ') + tools.green('|__ \ / _ \ oo oo oo ')) print( tools.red(' oo oo oo | |__) | | |__ ') + tools.yellow('| | __ | | __ | | | |__ ') + tools.green(' ) | | | | | oo oo oo ')) print(
import args_parser """ General workflow: 1. FIX THIS: ------------------ get the command line arguments 'args' with path to ".gitlab-ci.yml" file 2. FIX THIS: ------------------ set the logger 'log' with the debug level from 'args' to determine the level of logging which displays output to the user 3. FIX THIS: ------------------ perform the regression check by a) building executables ------------------ b) running the code ------------------ c) performing the defined analyzes 4. FIX THIS: ------------------ display the summary table with information for each build, run and analysis step 5. FIX THIS: ------------------ display if regression check was successful or not and return the corresponding error code """ print('') print( tools.red( '==============================================================================================================================' )) print( tools.red( ' _____ _____ _____ _____ _____ ' )) print( tools.red( ' /\ \ /\ \ /\ \ /\ \ /\ \ ' )) print( tools.red( ' /::\ \ /::\ \ /::\ \ /::\ \ /::\ \ ' )) print( tools.red(
args = parser.parse_args() # set the logger 'log' with the debug level from 'args' to determine the level of logging which displays output to the user tools.setup_logger(args.debug) log = logging.getLogger('logger') # check if file exists if os.path.isdir(args.gitlab_ci): print( tools.yellow( "Supplied path is [%s]. Searching for '.gitlab-ci.yml' there." % args.gitlab_ci)) args.gitlab_ci = os.path.join(args.gitlab_ci, '.gitlab-ci.yml') if not os.path.exists(args.gitlab_ci): print( tools.red("gitlab-ci.yml file not found under: '%s'" % args.gitlab_ci)) exit(1) # display all command line arguments print("Running with the following command line options") for arg in args.__dict__: print("%s = [ %s ]" % (arg.ljust(15), getattr(args, arg))) print('=' * 132) # set the basedir (where the code is) and the reggiedir (where the reggie.py is) basedir = os.path.abspath(os.path.dirname(args.gitlab_ci)) reggiedir = os.path.abspath(os.path.dirname(reggie_exe_path)) print(tools.blue("Using code under [basedir]: " + str(basedir))) print(tools.blue("Using reggie under [reggiedir]: " + str(reggiedir))) print(tools.blue("Running checks for [args.stage]: " + str(args.stage)))
def getCombinations(filename, CheckForMultipleKeys=False, OverrideOptionKey=None, OverrideOptionValue=None): # 1. get the key-value list from file # 1.1 get exclusion from line (if line starts with 'exclude:') # 1.2 get noCrossCombination from line (if line starts with 'nocrosscombination:') # 1.3 get option and it values from line ( option=value1 [,value2 [,value3 ...]] ) options, exclusions, noCrossCombinations = readKeyValueFile(filename) # 1.4 Check if a options[].values (key in the dict) is to be overridden (removes all other occurrences too!) if OverrideOptionKey and OverrideOptionValue: print( tools.yellow("Setting all options for: %s=[%s]" % (OverrideOptionKey, OverrideOptionValue))) # find the key/value pair in the options and replace the key/value + re-sort the list option_not_found = True for i in range(len(options)): if options[i].name == OverrideOptionKey: options[i].values = [OverrideOptionValue] option_not_found = False if option_not_found: raise Exception( tools.red( "Trying to set %s = [%s], but %s was not found in the list." % (OverrideOptionKey, OverrideOptionValue, OverrideOptionKey))) options.sort( key=lambda option: len(option.values), reverse=True ) # sort list in order to have the most varying option at the beginning # 2. Compute combinations: # 2.1 count total number of all combinations # 2.2 build only the valid combinations (that do NOT match any exclusion) # 2. compute combinations # 2.1 count total number of possible combinations without the exclusions combinations = [] # list of all VALID combinations NumOfCombinationsTotal = 1 for option in options: option.base = NumOfCombinationsTotal # save total number of combinations of all options before this option NumOfCombinationsTotal = NumOfCombinationsTotal * len(option.values) logging.getLogger('logger').debug( " Total number of combinations for '%s' = %d" % (filename, NumOfCombinationsTotal)) if NumOfCombinationsTotal > 10000: raise Exception( tools.red( "more than 10000 combinations in parameter.ini are not allowed!" )) # 2.2 build all valid combinations (all that do not match any exclusion) for i in range(NumOfCombinationsTotal ): # iterate index 'i' over NumOfCombinationsTotal combination = collections.OrderedDict() digits = collections.OrderedDict() # build i-th combination by adding all options with their name and a certain value for option in options: # compute index in the list of values of the option # Explanation with Example: # Assume you are reading the following file: # opt1 = black,white # opt2 = a,b,c # opt3 = cat,dog,bird,snake # opt4 = car,train # Then you get 2*3*4*2 = 48 combinations in total. Let us imagine the options (opt1, opt2, ...) # as digits in a crazy number system, where opt1 is the digit with the lowest value and # opt4 with the highest value. Since we have different number of values for every digit, the base # of each digit is not as in a standard number system like the decimal a series of powers 10^0, 10^1, 10^2, ... # In our example we get the following bases for the options: # base of opt1 = 1 (first digit has base 1 in every number system) # base of opt2 = 2 (since opt1 has two values, we get a 2 here) # base of opt3 = 6 (since opt2 has three values and base=2, we get 2*3=6. This is the number of combinations of opt1 and opt2) # base of opt4 = 24 (since opt3 has foure values and base=6, we get 6*4=24. This is the number of combinations of opt1, opt2 and opt3) # Luckily we already stored the base while counting the number of all combinations before. # We now can compute the index in the list of values of an option (which is the value of the respective digit in our crazy number system) # by dividing the index i (which is a number in our crazy number system) by the base and modulo the number of values of the option. j = (i / option.base) % len(option.values) digits[option.name] = int(j) for option in options: if CheckForMultipleKeys: # check if the same parameter name (e.g. 'BoundaryName') occurs more than once in the list and # move multiple occurances to a separate key/value where the value is a list of all occurances # this must be done, because dicts cannot have the same key name more than once (it is a dictionary) found, number = isKeyOf(combination, option.name) if found: new_key = "MULTIPLE_KEY:" + option.name logging.getLogger('logger').info( tools.yellow(str(option.name)) + " is already in list (found " + str(number) + " times). Adding new key/value as " + tools.yellow(new_key) + " with value=" + option.values[digits[option.name]]) # create list for value in key/value pair for the new re-named option "MULTIPLE_KEY+X" combination.setdefault(new_key, []).append( option.values[digits[option.name]]) digits[new_key] = -100 # default value for special key else: combination[option.name] = option.values[digits[ option.name]] else: combination[option.name] = option.values[digits[option.name]] # check if the combination is valid (does not match any exclusion) if anyIsSubset(exclusions, combination): continue # if any exclusion matches the combination, the combination is invalid => cycle and do not add to list of valid combinations # check if option is marked with "noCrossCombinations", these are not to be permutated skip = False for noCrossCombination in noCrossCombinations: # Check if the parameter exists in the list if digits.get(noCrossCombination[0], None) is None: print( tools.red( "nocrosscombination [%s] not found in list of parameters given in [%s].\nOnly parameters that are read can be considered for nocrosscombination." % (noCrossCombination[0], filename))) exit(1) # Check all noCrossCombinations and skip them is they already were added to the list if not all([ digits[key] == digits[noCrossCombination[0]] for key in noCrossCombination ]): skip = True break # Don't add combination if it was marked skip=True if skip: continue # add valid combination combinations.append(combination) logging.getLogger('logger').debug(" Number of valid combinations = %d" % len(combinations)) return combinations, digits
def readKeyValueFile(filename): # General worflow: # 1. Read file line by line: # 1.1 get exclusion from line (if line starts with 'exclude:') # 1.2 get noCrossCombination from line (if line starts with 'nocrosscombination:') # 1.3 get option and its values from line ( option=value1 [,value2 [,value3 ...]] ) found = os.path.exists(filename) # check if directory exists if not found: #raise getCombinationException(filename) # file not found raise Exception( tools.red("getCombination failed. file '%s' not found." % filename)) options = [] # list of all options exclusions = [] # list of all exclusions noCrossCombinations = [] # list of all noCrossCombinations # 1. read options and exclusions from the file with open(filename) as f: for line in f.readlines(): # iterate over all lines of the file line = re.sub( r"\s+", "", line) # remove all whitespaces ("\s" is the whitespac symbol) line = re.sub( r"\\s", " ", line ) # add new whitespaces for all occurrances of "\s" in the string ("\s" is NOT the whitespace symbol here) if line.startswith('!'): continue # skip lines starting with a comment line = line.split('!')[0] # remove comments # 1.1 read an exclusion if line.lower().startswith('exclude:'): line = line.split(':', 1)[1] # remove everything before ':'' ex = {} # new dictionary for the exclusion for key_value in splitValues( line ): # split at ',' (but not inside brackets) and iterate over key-value-pairs (key, value) = key_value.split('=') ex[key] = value # save key and its value in the exclusion-dictionary exclusions.append( ex) # append exclusion to the list of all exclusions continue # reading of exclusion finished -> go on with next line # 1.2 read a noCrossCombination if line.lower().startswith('nocrosscombination:'): line = line.split(':', 1)[1] # remove everything before ':'' noCrossCombination = line.split( ',') # list of keys, that should not be cross combined noCrossCombinations.append( noCrossCombination ) # append noCrossCombination to the list of all noCrossCombinations continue # reading of noCrossCombination finished -> go on with next line # 1.3 read a option and its possible values if '=' in line: (key, values) = line.split('=', 1) # split line at '=' option = Option( key, splitValues(values) ) # generate new Option with a list of values (splitted at ',' but not inside brackets) options.append(option) # append option to options list, where continue # reading of option finished -> go on with next line options.sort( key=lambda option: len(option.values), reverse=True ) # sort list in order to have the most varying option at the beginning return options, exclusions, noCrossCombinations
def getArgsAndBuilds(): """get command line arguments and builds in check directory from 'builds.ini'""" parser = argparse.ArgumentParser( description= 'DESCRIPTION:\nRegression checker for NRG codes.\nSupply the path to a /regressioncheck/checks/ directory within a repository containing a CMakeLists.txt file which can automatically be build using cmake. ', formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('-c', '--carryon', action='store_true', help='''Continue build/run process. --carryon : build non-existing binary-combinations and run all examples for thoses builds --carryon --run : run all failed examples''') parser.add_argument( '-e', '--exe', help='Path to executable of code that should be tested.') parser.add_argument( '-m', '--MPIexe', help= 'Path to mpirun executable. The correct MPI lib must be used, i.e. the one which which the executable (e.g. flexi) was compiled, e.g., /opt/openmpi/2.0.2/bin/mpirun.', default='mpirun') parser.add_argument('-d', '--debug', help='Debug level.', type=int, default=0) parser.add_argument( '-j', '--buildprocs', help='Number of processors used for compiling (make -j XXX).', type=int, default=0) parser.add_argument( '-b', '--basedir', help= 'Path to basedir of code that should be tested (contains CMakeLists.txt).' ) parser.add_argument( '-y', '--dummy', help= 'Use dummy_basedir and dummy_checks for fast testing on dummy code.', action='store_true') parser.add_argument( '-r', '--run', help= 'Run all binaries for all examples with all run-combinations for all existing binaries.', action='store_true') parser.add_argument( '-s', '--save', help= 'Do not remove output directories buildsXXXX in output_dir after successful run.', action='store_true') parser.add_argument( '-t', '--compiletype', help= 'Override all CMAKE_BUILD_TYPE settings by ignoring the value set in builds.ini (e.g. DEBUG or RELEASE).' ) parser.add_argument('-a', '--hlrs', help='Run on with aprun (24-core hlrs system).', action='store_true') parser.add_argument( '-z', '--rc', help= 'Create/Replace reference files that are required for analysis. After running the program, the output files are stored in the check-/example-directory.', action='store_true', dest='referencescopy') parser.add_argument( '-f', '--fc', help= 'Create/Replace required restart files (if defined in command_line.ini). After running the program, the output files are stored in the check-/example-directory.', action='store_true', dest='restartcopy') parser.add_argument( '-i', '--noMPI', help='Run program without "mpirun" (single thread execution).', action='store_true') parser.add_argument('check', help='Path to check-/example-directory.') #parser.set_defaults(carryon=False) #parser.set_defaults(dummy=False) #parser.set_defaults(run=False) #parser.set_defaults(save=False) #parser.set_defaults(hlrs=False) #parser.set_defaults(referencescopy=False) #parser.set_defaults(restartcopy=False) #parser.set_defaults(noMPI=False) # get reggie command line arguments args = parser.parse_args() # Set default values args.noMPIautomatic = False # Check OS if re.search('^linux', platform): hostname = socket.gethostname() print("platform: %s, hostname: %s" % (platform, hostname)) if re.search('^mom[0-9]+$', hostname): print( tools.yellow( 'Automatic detection of hlrs system: Assuming aprun is used and setting args.hlrs = True' )) args.hlrs = True elif re.search('^eslogin[0-9]+$', hostname): if args.hlrs: raise Exception( 'Running with -a or --hlrs. Cannot run this program on a login node. Get interactive job and run on mom node!' ) # setup basedir if args.dummy: # For testing reggie during reggie-developement: # Overwrite basedir and check directory with dummy directories. reggieDir = os.path.dirname(os.path.realpath(__file__)) args.basedir = os.path.join(reggieDir, 'dummy_basedir') args.check = os.path.join(reggieDir, 'dummy_checks/test') print("Basedir directory switched to '%s'" % args.basedir) print("Check directory switched to '%s'" % args.check) else: # For real reggie-execution: # Setup basedir (containing CMakeLists.txt) by searching upward from current working directory if args.basedir is None: args.basedir = os.getcwd() # start with current working directory try: if args.exe is None: # only get basedir if no executable is supplied args.basedir = tools.find_basedir(args.basedir) except Exception: print( tools.red( "Basedir (containing 'CMakeLists.txt') not found!\nEither specify the basedir on the command line or execute reggie within a project with a 'CMakeLists.txt'." )) exit(1) if not os.path.exists(args.check): # check if directory exists print(tools.red("Check directory not found: '%s'" % args.check)) exit(1) # delete the building directory when [carryon = False] and [run = False] before getBuilds is called if not args.carryon and not args.run: tools.remove_folder(OutputDirectory.output_dir) # get builds from checks directory if no executable is supplied if args.exe is None: # if not exe is supplied, get builds # read build combinations from checks/XX/builds.ini builds = check.getBuilds(args.basedir, args.check, args.compiletype) else: if not os.path.exists(args.exe): # check if executable exists print(tools.red("No executable found under '%s'" % args.exe)) exit(1) else: builds = [ check.Standalone(args.exe, args.check) ] # set builds list to contain only the supplied executable args.noMPIautomatic = check.StandaloneAutomaticMPIDetection( args.exe ) # Check possibly existing userblock.txt to find out if the executable was compiled with MPI=ON or MPI=OFF args.run = True # set 'run-mode' do not compile the code args.basedir = None # since code will not be compiled, the basedir is not required if args.run: print("args.run -> skip building") # in 'run-mode' remove all build from list of builds if their binaries do not exist (build.binary_exists() == False) builds = [build for build in builds if build.binary_exists()] if len(builds) == 0: print( tools.red("List of 'builds' is empty! Maybe switch off '--run'.")) exit(1) # display all command line arguments print("Running with the following command line options") for arg in list(args.__dict__): print(arg.ljust(15) + " = [ " + str(getattr(args, arg)) + " ]") print('=' * 132) return args, builds