#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Script "comp.py": # - compilation de Metafor # - lancement automatique de la batterie from parametricJob import * import re # -- repository classes -------------------------------------------------------- class Repo(object): def __init__(self, name, url): self.name = name self.url = url class GitRepo(Repo): def __init__(self, name, url): super(GitRepo, self).__init__(name, url) def co_cmd(self, pars): depth = '' if not pars['GIT_FULLCLONE'].val: depth = '--depth %s' % pars['GIT_DEPTH'].val branch = pars['GIT_BRANCH'].val if not self.doesBranchExist(branch): print('INFO: branch %s does not exist on %s' % (branch, self.url)) branch = 'master' print('INFO: checking out %s' % branch) cmd = "git clone --recursive --branch %s %s --quiet %s %s" % \ (branch, depth, self.url, self.name) return cmd def doesBranchExist(self, name): cmd = ['git', 'ls-remote', '--heads', self.url, name] out = subprocess.check_output(cmd) out = out.decode() # python 3 returns bytes m = re.search(name, out) return (m != None) class SVNRepo(Repo): def __init__(self, name, url): super(SVNRepo, self).__init__(name, url) def co_cmd(self, pars): cmd = "svn co --quiet %s %s" % (self.url, self.name) return cmd # -- CompJob class ------------------------------------------------------------- class CompJob(ParametricJob): """ Manage a compilation + battery.py """ def __init__(self, _jobId=''): # init base class self.jobId = _jobId cfgfile = "comp%s.cfg" % self.jobId ParametricJob.__init__(self, cfgfile) # list of required repositories self.repos = [] self.repos.append(GitRepo('oo_meta', 'git@gitlab.uliege.be:am-dept/MN2L/oo_meta.git')) self.repos.append(GitRepo('oo_nda', 'git@gitlab.uliege.be:am-dept/MN2L/oo_nda.git')) self.repos.append(GitRepo('linuxbin', 'git@gitlab.uliege.be:am-dept/linuxbin.git')) self.repos.append(GitRepo('parasolid', 'git@gitlab.uliege.be:am-dept/MN2L/parasolid.git')) def setDefaultPars(self): if len(self.pars)!=0: return TextPRM(self.pars, 'MAIL_ADDR', 'e-mail address (reports)', os.getenv('USER')) TextPRM(self.pars, 'SMTP_SERV', 'SMTP email server', 'smtp.ulg.ac.be') TextPRM(self.pars, 'ARC_NAME', 'archive name', '~/dev.zip') try: machineName = socket.gethostbyaddr(socket.gethostname())[0].split('.')[0] # lpx : marche pas dans des vbox except: machineName = socket.gethostname().split('.')[0] # marche dans ma vbox TextPRM(self.pars, 'CMAKELIST', 'build options', "%s.cmake" %machineName) YesNoPRM(self.pars, 'DEBUG_MODE', 'debug mode', False) TextPRM(self.pars, 'PYTHONEXE', 'Python executable', sys.executable) TextPRM(self.pars, 'PRIORITY', 'priority [1-5]', "3") TextPRM(self.pars, 'NB_TASKS', 'nb of tasks launched in parallel', "1") TextPRM(self.pars, 'NB_THREADS', 'nb of threads by task', "1") YesNoPRM(self.pars, 'GIT_FULLCLONE', 'clone the whole repository', False) TextPRM(self.pars, 'GIT_DEPTH', 'git clone depth', '10') TextPRM(self.pars, 'GIT_BRANCH', 'git branch name', 'master') MultiPRM(self.pars, 'BATTERY_ARG', 'battery argument', ["", "--fpe", "--withWER", "--keep"], "") MultiPRM(self.pars, 'RUNMETHOD', 'Run Method', ["interactive", "at", "batch"], "batch") TextPRM(self.pars, 'AT_TIME' , 'Delay for at launch (no syntax check, use with care)', "now") MultiPRM(self.pars, 'UNZIP', 'source', ["zip", "checkout", "present"], "checkout") YesNoPRM(self.pars, 'COMPILE', 'compile', True) MultiPRM(self.pars, 'BATTERY', 'battery', [True, False, "continue"], True) PRMAction(self.actions, 'a', self.pars['MAIL_ADDR']) PRMAction(self.actions, 'b', self.pars['ARC_NAME']) PRMAction(self.actions, 'c', self.pars['CMAKELIST']) PRMAction(self.actions, 'd', self.pars['DEBUG_MODE']) PRMAction(self.actions, 'e', self.pars['PYTHONEXE']) PRMAction(self.actions, 'f', self.pars['GIT_FULLCLONE']) PRMAction(self.actions, 'g', self.pars['GIT_DEPTH']) PRMAction(self.actions, 'h', self.pars['GIT_BRANCH']) PRMAction(self.actions, 'i', self.pars['PRIORITY']) PRMAction(self.actions, 'j', self.pars['NB_TASKS']) PRMAction(self.actions, 'k', self.pars['NB_THREADS']) PRMAction(self.actions, 'l', self.pars['BATTERY_ARG']) PRMAction(self.actions, 'm', self.pars['RUNMETHOD']) # AT paramters PRMAction(self.actions, 'n', self.pars['AT_TIME']) # Actions NoAction(self.actions) PRMAction(self.actions, '1', self.pars['UNZIP']) PRMAction(self.actions, '2', self.pars['COMPILE']) PRMAction(self.actions, '3', self.pars['BATTERY']) NoAction (self.actions) GoAction (self.actions, 'G') SaveAction(self.actions, 'S') QuitAction(self.actions, 'Q') def configActions(self): self.pars['ARC_NAME'].enable(self.pars['UNZIP'].val=="zip") self.pars['NB_TASKS'].enable(self.pars['COMPILE'].val==True or self.pars['BATTERY'].val!=False) self.pars['NB_THREADS'].enable(self.pars['COMPILE'].val==True or self.pars['BATTERY'].val!=False) self.pars['CMAKELIST'].enable(self.pars['COMPILE'].val==True) self.pars['DEBUG_MODE'].enable(self.pars['COMPILE'].val==True) self.pars['PRIORITY'].enable(self.pars['BATTERY'].val!=False and self.pars['RUNMETHOD'].val!='sge') self.pars['GIT_DEPTH'].enable(self.pars['UNZIP'].val=="checkout" and not self.pars['GIT_FULLCLONE'].val) self.pars['GIT_BRANCH'].enable(self.pars['UNZIP'].val=="checkout") # Batch self.pars['AT_TIME'].enable(self.pars['RUNMETHOD'].val=='at') # battery arg self.pars['BATTERY_ARG'].enable(self.pars['BATTERY']!=False) def touchFiles(self): for repo in self.repos: print("touching %s" % repo.name) for path, dirs, files in os.walk(repo.name): for file in files: os.utime(os.path.join(path,file), None) # touch file def checkOut(self): for repo in self.repos: if not os.path.isdir(repo.name): print('checking out "%s" from %s...' % (repo.name, repo.url)) cmd = repo.co_cmd(self.pars) print(cmd) os.system(cmd) def doClean(self): dirs = [ repo.name for repo in self.repos ] dirs.append('oo_metaB') for dir in dirs: if os.path.isdir(dir): print("removing old %s directory" % dir) shutil.rmtree(dir) def doUnzip(self): print("unzipping files...") file = self.pars['ARC_NAME'].val if not os.path.isfile(os.path.expanduser(file)): self.error("archive %s is not here!" % file) ext = os.path.splitext(file)[1] if ext==".zip": # unzip the source and try to convert text files cmd = 'unzip -a %s -x "*/.git/*" >/dev/null' % file sysOutput = os.system(cmd) if (sysOutput != 0): self.error("unable to unzip archive %s !" % file) # no conversion for ".git" database cmd = 'unzip %s "*/.git/*" >/dev/null' % file sysOutput = os.system(cmd) if (sysOutput != 0): self.error("unable to unzip archive %s !" % file) # convert some text files (if zip "text compression" was disabled) dos2unix([ repo.name for repo in self.repos ], '*.txt;*.CPE;*.CRE;*.stp;*.l;*.y;*.dat') elif ext==".tgz" or ext==".tar.gz": tar = tarfile.open(os.path.expanduser(file),'r:gz') for tarinfo in tar: tar.extract(tarinfo) tar.close() else: self.error("archive %s of unknown extension!" % file) def compileMETAFOR(self): # release or debug names/flags exe='bin/Metafor' dflag='' if self.pars['DEBUG_MODE'].val: dflag='-DCMAKE_BUILD_TYPE=Debug' # first check if not os.path.isdir('oo_meta'): self.error('oo_meta not here!') # create bin dir if os.path.isdir('oo_metaB'): print('removing old %s directory' % 'oo_metaB') shutil.rmtree('oo_metaB') os.mkdir('oo_metaB') os.chdir('oo_metaB') # which python? out = subprocess.check_output([self.pars['PYTHONEXE'].val, '-c', 'import sys; print(sys.version_info.major)']) try: pyver = int(out) except: self.error('unable to get python version number') print('Python version is', pyver) if pyver==2: pyflag='-DMETAFOR_USE_PY3=OFF' else: pyflag='-DMETAFOR_USE_PY3=ON' # configure print("configuring oo_meta") cmfile = '../oo_meta/CMake/%s' % self.pars['CMAKELIST'].val #print cmfile if not os.path.isfile(cmfile): msg = '%s not found!' % cmfile print(msg) self.mailmsg(msg) cmd = 'cmake -C %s %s %s ../oo_meta >autocf.log 2>&1' % (cmfile, pyflag, dflag) print (cmd) os.system(cmd) # compile ncpu = int(self.pars['NB_TASKS'].val) * int(self.pars['NB_THREADS'].val) print('compiling %s using %s cpu(s) (have a coffee)' % (exe, ncpu)) os.system('make -j %d >compile.log 2>&1' % (ncpu)) # check exe if os.path.isfile(exe) and os.access(exe, os.X_OK): msg='compilation of %s OK' % exe print(msg) self.mailmsg(msg, 'compile.log') else: msg='compilation of %s FAILED' % exe self.error(msg, 'compile.log') os.chdir('..') def compile(self): self.compileMETAFOR() def cleanBattery(self): os.chdir('oo_metaB/bin') print("cleaning old results") os.system("%s battery.py clean >/dev/null 2>&1" % self.pars['PYTHONEXE'].val) os.chdir('../..') def startBat(self): now = datetime.datetime.now() print("starting battery at %s (come back tomorrow)" % now.ctime()) os.chdir('oo_metaB/bin') #cmd="nice -%s %s battery.py %s -j %s -k %s >battery.log 2>&1" % \ # (self.pars['NICE_VALUE'].val, self.pars['PYTHONEXE'].val, \ # self.pars['BATTERY_ARG'].val,\ # self.pars['NB_TASKS'].val, self.pars['NB_THREADS'].val) cmd="%s battery.py %s -p %s -j %s -k %s >battery.log 2>&1" % \ (self.pars['PYTHONEXE'].val,\ self.pars['BATTERY_ARG'].val,\ self.pars['PRIORITY'].val,\ self.pars['NB_TASKS'].val,\ self.pars['NB_THREADS'].val) p = subprocess.Popen(cmd, shell=True) p.wait() # finish script now = datetime.datetime.now() print("battery completed at %s" % now.ctime()) self.mailmsg("battery complete", file='battery.log') os.chdir('../..') def checkResults(self): # pars indep os.chdir('oo_metaB/bin') print ("diff'ing results") # cmd="%s battery.py diffTSC" % self.pars['PYTHONEXE'].val # <= future battery.py (using TSC) cmd="%s battery.py diff" % self.pars['PYTHONEXE'].val print ("checkResults: cmd = %s" % cmd) os.system(cmd) # file='verif/%s-diffsTSC.html' % machineid() # <= future battery.py (using TSC) file='verif/%s-diffs.html' % machineid() print("verif file name = %s" % file) #self.mailhtml(file, "html report") self.mailHtmlAsAttachement(file, "html report") print("file %s sent as attachement ..." % file) os.chdir('../..') def getJobName(self): return os.path.basename(os.getcwd())+".battery" def run(self): # kill script that kills running tree self.killScript(self.jobId, os.getpgrp()) if self.pars['UNZIP'].val=="checkout": self.doClean() self.checkOut() elif self.pars['UNZIP'].val=="zip": self.doClean() self.doUnzip() self.checkOut() # only missing folders self.touchFiles() if self.pars['COMPILE'].val: self.compile() if self.pars['BATTERY'].val==True: self.cleanBattery() if not self.pars['BATTERY'].val==False: self.startBat() self.checkResults() if os.path.isfile("kill%s.py" % self.jobId): os.remove("kill%s.py" % self.jobId) if (self.pars['RUNMETHOD'].val == 'at' or self.pars['RUNMETHOD'].val == 'batch'): if os.path.isfile("atrm%s.py" % self.jobId): os.remove("atrm%s.py" % self.jobId) if os.path.isfile(self.cfgfile): os.remove(self.cfgfile) print("done.") # -- main ---------------------------------------------------------------------- if __name__ == "__main__": try: import signal signal.signal(signal.SIGBREAK, sigbreak) except: pass from optparse import OptionParser parser = OptionParser() parser.add_option("-d", "--directory", dest="rundir", metavar="DIR", help="specify run directory (batch mode)") parser.add_option("-x", "--nogui", action="store_false", dest="usegui",default=True, help="disable menu") parser.add_option("-i", "--jobId", dest="jobId", type="str", default='', help="job id") (options, args) = parser.parse_args() #print "options = ", options #print "args = ", args if len(args)!=0: parser.error("too many arguments") if options.rundir: os.chdir(options.rundir) #print "options.jobId = %s"% options.jobId job = CompJob(options.jobId) if options.usegui: job.menu() else: job.run()