1#!/usr/bin/env python 2 3import os,shutil, string, re 4from distutils.sysconfig import parse_makefile 5import sys 6import logging, time 7import types 8sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 9from cmakegen import Mistakes, stripsplit, AUTODIRS, SKIPDIRS 10from cmakegen import defaultdict # collections.defaultdict, with fallback for python-2.4 11from gmakegen import * 12 13import inspect 14thisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 15sys.path.insert(0,thisscriptdir) 16import testparse 17import example_template 18 19class generateExamples(Petsc): 20 """ 21 gmakegen.py has basic structure for finding the files, writing out 22 the dependencies, etc. 23 """ 24 def __init__(self,petsc_dir=None, petsc_arch=None, verbose=False, single_ex=False): 25 super(generateExamples, self).__init__(petsc_dir=None, petsc_arch=None, verbose=False) 26 27 self.single_ex=single_ex 28 self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch) 29 self.ptNaming=True 30 # Whether to write out a useful debugging 31 #if verbose: self.summarize=True 32 self.summarize=True 33 34 # For help in setting the requirements 35 self.precision_types="single double quad int32".split() 36 self.integer_types="int32 int64".split() 37 self.languages="fortran cuda cxx".split() # Always requires C so do not list 38 39 # Things that are not test 40 self.buildkeys=testparse.buildkeys 41 42 # Adding a dictionary for storing sources, objects, and tests 43 # to make building the dependency tree easier 44 self.sources={} 45 self.objects={} 46 self.tests={} 47 for pkg in PKGS: 48 self.sources[pkg]={} 49 self.objects[pkg]=[] 50 self.tests[pkg]={} 51 for lang in LANGS: 52 self.sources[pkg][lang]={} 53 self.sources[pkg][lang]['srcs']=[] 54 self.tests[pkg][lang]={} 55 56 # Do some initialization 57 self.testroot_dir=os.path.join(self.arch_dir,"tests") 58 if not os.path.isdir(self.testroot_dir): os.makedirs(self.testroot_dir) 59 60 self.indent=" " 61 return 62 63 def nameSpace(self,srcfile,srcdir): 64 """ 65 Because the scripts have a non-unique naming, the pretty-printing 66 needs to convey the srcdir and srcfile. There are two ways of doing this. 67 """ 68 if self.ptNaming: 69 cdir=srcdir.split('src')[1].lstrip("/").rstrip("/") 70 prefix=cdir.replace('/examples/','_').replace("/","_")+"-" 71 nameString=prefix+srcfile 72 else: 73 #nameString=srcdir+": "+srcfile 74 nameString=srcfile 75 return nameString 76 77 def getLanguage(self,srcfile): 78 """ 79 Based on the source, determine associated language as found in gmakegen.LANGS 80 Can we just return srcext[1:\] now? 81 """ 82 langReq=None 83 srcext=os.path.splitext(srcfile)[-1] 84 if srcext in ".F90".split(): langReq="F90" 85 if srcext in ".F".split(): langReq="F" 86 if srcext in ".cxx".split(): langReq="cxx" 87 if srcext == ".cu": langReq="cu" 88 if srcext == ".c": langReq="c" 89 #if not langReq: print "ERROR: ", srcext, srcfile 90 return langReq 91 92 def _getLoopVars(self,inDict,testname, isSubtest=False): 93 """ 94 Given: 'args: -bs {{1 2 3 4 5}} -pc_type {{cholesky sor}} -ksp_monitor' 95 Return: 96 inDict['args']: -ksp_monitor 97 inDict['subargs']: -bs ${bs} -pc_type ${pc_type} 98 loopVars['subargs']['varlist']=['bs' 'pc_type'] # Don't worry about OrderedDict 99 loopVars['subargs']['bs']=[["bs"],["1 2 3 4 5"]] 100 loopVars['subargs']['pc_type']=[["pc_type"],["cholesky sor"]] 101 subst should be passed in instead of inDict 102 """ 103 loopVars={}; newargs="" 104 lkeys=inDict.keys() 105 lsuffix='_' 106 for key in lkeys: 107 if type(inDict[key])!=types.StringType: continue 108 keystr = str(inDict[key]) 109 akey=('subargs' if key=='args' else key) # what to assign 110 if not inDict.has_key(akey): inDict[akey]='' 111 varlist=[] 112 for varset in re.split('-(?=[a-zA-Z])',keystr): 113 if not varset.strip(): continue 114 if len(re.findall('{{(.*?)}(?:[\w\s]*)?}',varset))>0: 115 if not loopVars.has_key(akey): loopVars[akey]={} 116 # Assuming only one for loop per var specification 117 keyvar=varset.split("{{")[0].strip() 118 if not keyvar.strip(): 119 if key=='nsize': 120 keyvar='nsize' 121 else: 122 print testname+": Problem in finding loop variables", keyvar, varset 123 varlist.append(keyvar) 124 loopVars[akey][keyvar]=[keyvar,re.findall('{{(.*?)}(?:[\w\s]*)?}',varset)[0]] 125 if akey=='nsize': 126 inDict[akey] = '${' + keyvar + '}' 127 lsuffix+=akey+'-'+inDict[akey]+'_' 128 else: 129 inDict[akey] += ' -'+keyvar+' ${' + keyvar + '}' 130 lsuffix+=keyvar+'-${' + keyvar + '}_' 131 else: 132 if key=='args': newargs+=" -"+varset.strip() 133 if len(varlist)>0: loopVars[akey]['varlist']=varlist 134 135 136 # For subtests, args are always substituted in (not top level) 137 if isSubtest: 138 inDict['subargs']+=" "+newargs.strip() 139 inDict['args']='' 140 if inDict.has_key('label_suffix'): 141 inDict['label_suffix']+=lsuffix.rstrip('_') 142 else: 143 inDict['label_suffix']=lsuffix.rstrip('_') 144 else: 145 if len(loopVars.keys())>0: 146 inDict['args']=newargs.strip() 147 inDict['label_suffix']=lsuffix.rstrip('_') 148 if len(loopVars.keys())>0: 149 return loopVars 150 else: 151 return None 152 153 def getArgLabel(self,testDict): 154 """ 155 In all of the arguments in the test dictionary, create a simple 156 string for searching within the makefile system. For simplicity in 157 search, remove "-", for strings, etc. 158 Also, concatenate the arg commands 159 For now, ignore nsize -- seems hard to search for anyway 160 """ 161 # Collect all of the args associated with a test 162 argStr=("" if not testDict.has_key('args') else testDict['args']) 163 if testDict.has_key('subtests'): 164 for stest in testDict["subtests"]: 165 sd=testDict[stest] 166 argStr=argStr+("" if not sd.has_key('args') else sd['args']) 167 168 # Now go through and cleanup 169 argStr=re.sub('{{(.*?)}}',"",argStr) 170 argStr=re.sub('-'," ",argStr) 171 for digit in string.digits: argStr=re.sub(digit," ",argStr) 172 argStr=re.sub("\.","",argStr) 173 argStr=re.sub(",","",argStr) 174 argStr=re.sub('\+',' ',argStr) 175 argStr=re.sub(' +',' ',argStr) # Remove repeated white space 176 return argStr.strip() 177 178 def addToSources(self,exfile,root,srcDict): 179 """ 180 Put into data structure that allows easy generation of makefile 181 """ 182 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 183 fullfile=os.path.join(root,exfile) 184 relpfile=self.relpath(self.petsc_dir,fullfile) 185 lang=self.getLanguage(exfile) 186 if not lang: return 187 self.sources[pkg][lang]['srcs'].append(relpfile) 188 if srcDict.has_key('depends'): 189 depSrc=srcDict['depends'] 190 depObj=os.path.splitext(depSrc)[0]+".o" 191 self.sources[pkg][lang][exfile]=depObj 192 193 # In gmakefile, ${TESTDIR} var specifies the object compilation 194 testsdir=self.relpath(self.petsc_dir,root)+"/" 195 objfile="${TESTDIR}/"+testsdir+os.path.splitext(exfile)[0]+".o" 196 self.objects[pkg].append(objfile) 197 return 198 199 def addToTests(self,test,root,exfile,execname,testDict): 200 """ 201 Put into data structure that allows easy generation of makefile 202 Organized by languages to allow testing of languages 203 """ 204 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 205 #nmtest=self.nameSpace(test,root) 206 rpath=self.relpath(self.petsc_dir,root) 207 nmtest=os.path.join(rpath,test) 208 lang=self.getLanguage(exfile) 209 if not lang: return 210 self.tests[pkg][lang][nmtest]={} 211 self.tests[pkg][lang][nmtest]['exfile']=os.path.join(rpath,exfile) 212 self.tests[pkg][lang][nmtest]['exec']=execname 213 self.tests[pkg][lang][nmtest]['argLabel']=self.getArgLabel(testDict) 214 return 215 216 def getExecname(self,exfile,root): 217 """ 218 Generate bash script using template found next to this file. 219 This file is read in at constructor time to avoid file I/O 220 """ 221 rpath=self.relpath(self.petsc_dir,root) 222 if self.single_ex: 223 execname=rpath.split("/")[1]+"-ex" 224 else: 225 execname=os.path.splitext(exfile)[0] 226 return execname 227 228 def getSubstVars(self,testDict,rpath,testname): 229 """ 230 Create a dictionary with all of the variables that get substituted 231 into the template commands found in example_template.py 232 """ 233 subst={} 234 235 # Handle defaults of testparse.acceptedkeys (e.g., ignores subtests) 236 if not testDict.has_key('nsize'): testDict['nsize']=1 237 for ak in testparse.acceptedkeys: 238 if ak=='test': continue 239 subst[ak]=(testDict[ak] if testDict.has_key(ak) else '') 240 241 # Now do other variables 242 subst['execname']=testDict['execname'] 243 if testDict.has_key('filter'): 244 subst['filter']="'"+testDict['filter']+"'" # Quotes are tricky - overwrite 245 246 # Others 247 subst['subargs']='' # Default. For variables override 248 subst['srcdir']=os.path.join(self.petsc_dir,rpath) 249 subst['label_suffix']='' 250 subst['comments']="\n#".join(subst['comments'].split("\n")) 251 if subst['comments']: subst['comments']="#"+subst['comments'] 252 subst['exec']="../"+subst['execname'] 253 subst['testroot']=self.testroot_dir 254 subst['testname']=testname 255 if self.conf['PETSC_HAVE_DATAFILESPATH']: 256 dp=self.conf['DATAFILESPATH'] 257 dpl='DATAFILESPATH=${DATAFILESPATH:-"'+dp+'"}' 258 else: 259 dpl='' 260 subst['datafilespath_line']=dpl 261 262 # This is used to label some matrices 263 subst['petsc_index_size']=str(self.conf['PETSC_INDEX_SIZE']) 264 subst['petsc_scalar_size']=str(self.conf['PETSC_SCALAR_SIZE']) 265 266 # These can have for loops and are treated separately later 267 subst['nsize']=str(subst['nsize']) 268 269 #Conf vars 270 if self.petsc_arch.find('valgrind')>=0: 271 subst['mpiexec']='petsc_mpiexec_valgrind ' + self.conf['MPIEXEC'] 272 else: 273 subst['mpiexec']=self.conf['MPIEXEC'] 274 subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path 275 subst['diff']=self.conf['DIFF'] 276 subst['rm']=self.conf['RM'] 277 subst['grep']=self.conf['GREP'] 278 subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR'] 279 subst['wpetsc_dir']=self.conf['wPETSC_DIR'] 280 281 # Output file is special because of subtests override 282 defroot=(re.sub("run","",testname) if testname.startswith("run") else testname) 283 if not "_" in defroot: defroot=defroot+"_1" 284 subst['defroot']=defroot 285 subst['label']=self.nameSpace(defroot,subst['srcdir']) 286 subst['redirect_file']=defroot+".tmp" 287 if not testDict.has_key('output_file'): 288 subst['output_file']="output/"+defroot+".out" 289 # Add in the full path here. 290 subst['output_file']=os.path.join(subst['srcdir'],subst['output_file']) 291 if not os.path.isfile(os.path.join(self.petsc_dir,subst['output_file'])): 292 if not subst['TODO']: 293 print "Warning: "+subst['output_file']+" not found." 294 # Worry about alt files here -- see 295 # src/snes/examples/tutorials/output/ex22*.out 296 altlist=[subst['output_file']] 297 for i in range(1,3): 298 altroot=defroot+"_alt" 299 if i==2: altroot=altroot+"_2" 300 af="output/"+altroot+".out" 301 srcaf=os.path.join(subst['srcdir'],af) 302 fullaf=os.path.join(self.petsc_dir,srcaf) 303 if os.path.isfile(fullaf): altlist.append(srcaf) 304 if len(altlist)>1: subst['altfiles']=altlist 305 #if len(altlist)>1: print "Found alt files: ",altlist 306 307 return subst 308 309 def getCmds(self,subst,i): 310 """ 311 Generate bash script using template found next to this file. 312 This file is read in at constructor time to avoid file I/O 313 """ 314 indnt=self.indent 315 nindnt=i # the start and has to be consistent with below 316 cmdLines="" 317 318 # MPI is the default -- but we have a few odd commands 319 if not subst['command']: 320 cmd=indnt*nindnt+self._substVars(subst,example_template.mpitest) 321 else: 322 cmd=indnt*nindnt+self._substVars(subst,example_template.commandtest) 323 cmdLines+=cmd+"\n\n" 324 325 if not subst['filter_output']: 326 if not subst.has_key('altfiles'): 327 cmd=indnt*nindnt+self._substVars(subst,example_template.difftest) 328 else: 329 # Have to do it by hand a bit because of variable number of alt files 330 rf=subst['redirect_file'] 331 cmd=indnt*nindnt+example_template.difftest.split('@')[0] 332 for i in range(len(subst['altfiles'])): 333 af=subst['altfiles'][i] 334 cmd+=af+' '+rf+' > diff-${testname}-'+str(i)+'.out 2> diff-${testname}-'+str(i)+'.out' 335 if i!=len(subst['altfiles'])-1: 336 cmd+=' || ${diff_exe} ' 337 else: 338 cmd+='" diff-${testname}.out diff-${testname}.out diff-${label}' 339 cmd+=subst['label_suffix']+' ""' # Quotes are painful 340 else: 341 cmd=indnt*nindnt+self._substVars(subst,example_template.filterdifftest) 342 cmdLines+=cmd+"\n" 343 return cmdLines 344 345 def _substVars(self,subst,origStr): 346 """ 347 Substitute variables 348 """ 349 Str=origStr 350 for subkey in subst: 351 if type(subst[subkey])!=types.StringType: continue 352 patt="@"+subkey.upper()+"@" 353 Str=re.sub(patt,subst[subkey],Str) 354 return Str 355 356 def _writeTodoSkip(self,fh,tors,inDict,footer): 357 """ 358 Write out the TODO and SKIP lines in the file 359 The TODO or SKIP variable, tors, should be lower case 360 """ 361 TORS=tors.upper() 362 template=eval("example_template."+tors+"line") 363 tsStr=re.sub("@"+TORS+"COMMENT@",inDict[TORS],template) 364 fh.write(tsStr+"\ntotal=1; "+tors+"=1\n") 365 fh.write(footer+"\n") 366 fh.write("exit\n\n\n") 367 return 368 369 def getLoopVarsHead(self,loopVars,i): 370 """ 371 Generate a nicely indented string with the format loops 372 Here is what the data structure looks like 373 loopVars['subargs']['varlist']=['bs' 'pc_type'] # Don't worry about OrderedDict 374 loopVars['subargs']['bs']=["i","1 2 3 4 5"] 375 loopVars['subargs']['pc_type']=["j","cholesky sor"] 376 """ 377 outstr=''; indnt=self.indent 378 for key in loopVars: 379 for var in loopVars[key]['varlist']: 380 varval=loopVars[key][var] 381 outstr += indnt * i + "for "+varval[0]+" in "+varval[1]+"; do\n" 382 i = i + 1 383 return (outstr,i) 384 385 def getLoopVarsFoot(self,loopVars,i): 386 outstr=''; indnt=self.indent 387 for key in loopVars: 388 for var in loopVars[key]['varlist']: 389 i = i - 1 390 outstr += indnt * i + "done\n" 391 return (outstr,i) 392 393 def genRunScript(self,testname,root,isRun,srcDict): 394 """ 395 Generate bash script using template found next to this file. 396 This file is read in at constructor time to avoid file I/O 397 """ 398 # runscript_dir directory has to be consistent with gmakefile 399 testDict=srcDict[testname] 400 rpath=self.relpath(self.petsc_dir,root) 401 runscript_dir=os.path.join(self.testroot_dir,rpath) 402 if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir) 403 fh=open(os.path.join(runscript_dir,testname+".sh"),"w") 404 petscvarfile=os.path.join(self.arch_dir,'lib','petsc','conf','petscvariables') 405 406 # Get variables to go into shell scripts. last time testDict used 407 subst=self.getSubstVars(testDict,rpath,testname) 408 loopVars = self._getLoopVars(subst,testname) # Alters subst as well 409 #if '33_' in testname: print subst['subargs'] 410 411 #Handle runfiles 412 if subst.has_key('localrunfiles'): 413 for lfile in subst['localrunfiles'].split(): 414 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 415 shutil.copy(fullfile,runscript_dir) 416 # Check subtests for local runfiles 417 if subst.has_key("subtests"): 418 for stest in subst["subtests"]: 419 if subst[stest].has_key('localrunfiles'): 420 for lfile in testDict[stest]['localrunfiles'].split(): 421 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 422 shutil.copy(fullfile,self.runscript_dir) 423 424 # Now substitute the key variables into the header and footer 425 header=self._substVars(subst,example_template.header) 426 # The header is done twice to enable @...@ in header 427 header=self._substVars(subst,header) 428 footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer) 429 430 # Start writing the file 431 fh.write(header+"\n") 432 433 # If there is a TODO or a SKIP then we do it before writing out the 434 # rest of the command (which is useful for working on the test) 435 # SKIP and TODO can be for the source file or for the runs 436 for tors in "todo skip".split(): 437 for d in [srcDict,testDict]: 438 if d.has_key(tors.upper()): self._writeTodoSkip(fh,tors,d,footer) 439 440 j=0 # for indentation 441 442 if loopVars: 443 (loopHead,j) = self.getLoopVarsHead(loopVars,j) 444 if (loopHead): fh.write(loopHead+"\n") 445 446 # Subtests are special 447 if testDict.has_key("subtests"): 448 substP=subst # Subtests can inherit args but be careful 449 for stest in testDict["subtests"]: 450 subst=substP.copy() 451 subst.update(testDict[stest]) 452 subst['nsize']=str(subst['nsize']) 453 sLoopVars = self._getLoopVars(subst,testname,isSubtest=True) 454 #if '10_9' in testname: print sLoopVars 455 if sLoopVars: 456 (sLoopHead,j) = self.getLoopVarsHead(sLoopVars,j) 457 fh.write(sLoopHead+"\n") 458 fh.write(self.getCmds(subst,j)+"\n") 459 if sLoopVars: 460 (sLoopFoot,j) = self.getLoopVarsFoot(sLoopVars,j) 461 fh.write(sLoopFoot+"\n") 462 else: 463 fh.write(self.getCmds(subst,j)+"\n") 464 465 if loopVars: 466 (loopFoot,j) = self.getLoopVarsFoot(loopVars,j) 467 fh.write(loopFoot+"\n") 468 469 fh.write(footer+"\n") 470 os.chmod(os.path.join(runscript_dir,testname+".sh"),0755) 471 #if '10_9' in testname: sys.exit() 472 return 473 474 def genScriptsAndInfo(self,exfile,root,srcDict): 475 """ 476 Generate scripts from the source file, determine if built, etc. 477 For every test in the exfile with info in the srcDict: 478 1. Determine if it needs to be run for this arch 479 2. Generate the script 480 3. Generate the data needed to write out the makefile in a 481 convenient way 482 All tests are *always* run, but some may be SKIP'd per the TAP standard 483 """ 484 debug=False 485 fileIsTested=False 486 execname=self.getExecname(exfile,root) 487 isBuilt=self._isBuilt(exfile,srcDict) 488 for test in srcDict: 489 if test in self.buildkeys: continue 490 if debug: print self.nameSpace(exfile,root), test 491 srcDict[test]['execname']=execname # Convenience in generating scripts 492 isRun=self._isRun(srcDict[test]) 493 self.genRunScript(test,root,isRun,srcDict) 494 srcDict[test]['isrun']=isRun 495 if isRun: fileIsTested=True 496 self.addToTests(test,root,exfile,execname,srcDict[test]) 497 498 # This adds to datastructure for building deps 499 if fileIsTested and isBuilt: self.addToSources(exfile,root,srcDict) 500 #print self.nameSpace(exfile,root), fileIsTested 501 return 502 503 def _isBuilt(self,exfile,srcDict): 504 """ 505 Determine if this file should be built. 506 """ 507 # Get the language based on file extension 508 lang=self.getLanguage(exfile) 509 if (lang=="F" or lang=="F90") and not self.have_fortran: 510 srcDict["SKIP"]="Fortran required for this test" 511 return False 512 if lang=="cu" and not self.conf.has_key('PETSC_HAVE_CUDA'): 513 srcDict["SKIP"]="CUDA required for this test" 514 return False 515 if lang=="cxx" and not self.conf.has_key('PETSC_HAVE_CXX'): 516 srcDict["SKIP"]="C++ required for this test" 517 return False 518 519 # Deprecated source files 520 if srcDict.has_key("TODO"): return False 521 522 # isRun can work with srcDict to handle the requires 523 if srcDict.has_key("requires"): 524 if len(srcDict["requires"])>0: 525 return self._isRun(srcDict) 526 527 return True 528 529 530 def _isRun(self,testDict): 531 """ 532 Based on the requirements listed in the src file and the petscconf.h 533 info, determine whether this test should be run or not. 534 """ 535 indent=" " 536 debug=False 537 538 # MPI requirements 539 if testDict.has_key('nsize'): 540 if testDict['nsize']>1 and self.conf.has_key('MPI_IS_MPIUNI'): 541 if debug: print indent+"Cannot run parallel tests" 542 testDict['SKIP']="Parallel test with serial build" 543 return False 544 545 # The requirements for the test are the sum of all the run subtests 546 if testDict.has_key('subtests'): 547 if not testDict.has_key('requires'): testDict['requires']="" 548 for stest in testDict['subtests']: 549 if testDict[stest].has_key('requires'): 550 testDict['requires']=testDict['requires']+" "+testDict[stest]['requires'] 551 552 553 # Now go through all requirements 554 if testDict.has_key('requires'): 555 for requirement in testDict['requires'].split(): 556 requirement=requirement.strip() 557 if not requirement: continue 558 if debug: print indent+"Requirement: ", requirement 559 isNull=False 560 if requirement.startswith("!"): 561 requirement=requirement[1:]; isNull=True 562 # Precision requirement for reals 563 if requirement in self.precision_types: 564 if self.conf['PETSC_PRECISION']==requirement: 565 testDict['SKIP']="not "+requirement+" required" 566 if isNull: return False 567 else: 568 testDict['SKIP']=requirement+" required" 569 return False 570 # Precision requirement for ints 571 if requirement in self.integer_types: 572 if requirement=="int32": 573 if self.conf['PETSC_SIZEOF_INT']==4: 574 testDict['SKIP']="not int32 required" 575 if isNull: return False 576 else: 577 testDict['SKIP']="int32 required" 578 return False 579 if requirement=="int64": 580 if self.conf['PETSC_SIZEOF_INT']==8: 581 testDict['SKIP']="NOT int64 required" 582 if isNull: return False 583 else: 584 testDict['SKIP']="int64 required" 585 return False 586 # Datafilespath 587 if requirement=="datafilespath": 588 if not self.conf['PETSC_HAVE_DATAFILESPATH']: 589 testDict['SKIP']="Requires DATAFILESPATH" 590 return False 591 # Defines -- not sure I have comments matching 592 if "define(" in requirement.lower(): 593 reqdef=requirement.split("(")[1].split(")")[0] 594 val=(reqdef.split()[1] if " " in reqdef else "") 595 if self.conf.has_key(reqdef): 596 if val: 597 if self.conf[reqdef]==val: 598 if isNull: 599 testDict['SKIP']="Null requirement not met: "+requirement 600 return False 601 else: 602 testDict['SKIP']="Required: "+requirement 603 return False 604 else: 605 if isNull: 606 testDict['SKIP']="Null requirement not met: "+requirement 607 return False 608 else: 609 return True 610 else: 611 testDict['SKIP']="Requirement not met: "+requirement 612 return False 613 614 # Rest should be packages that we can just get from conf 615 if requirement == "complex": petscconfvar="PETSC_USE_COMPLEX" 616 else: petscconfvar="PETSC_HAVE_"+requirement.upper() 617 if self.conf.get(petscconfvar): 618 if isNull: 619 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 620 return False 621 elif not isNull: 622 if debug: print "requirement not found: ", requirement 623 testDict['SKIP']=petscconfvar+" requirement not met" 624 return False 625 626 return True 627 628 def genPetscTests_summarize(self,dataDict): 629 """ 630 Required method to state what happened 631 """ 632 if not self.summarize: return 633 indent=" " 634 fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt') 635 fh=open(fhname,"w") 636 #print "See ", fhname 637 for root in dataDict: 638 relroot=self.relpath(self.petsc_dir,root) 639 pkg=relroot.split("/")[1] 640 fh.write(relroot+"\n") 641 allSrcs=[] 642 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 643 for exfile in dataDict[root]: 644 # Basic information 645 fullfile=os.path.join(root,exfile) 646 rfile=self.relpath(self.petsc_dir,fullfile) 647 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 648 fh.write(indent+exfile+indent*4+builtStatus+"\n") 649 650 for test in dataDict[root][exfile]: 651 if test in self.buildkeys: continue 652 line=indent*2+test 653 fh.write(line+"\n") 654 # Looks nice to have the keys in order 655 #for key in dataDict[root][exfile][test]: 656 for key in "isrun abstracted nsize args requires script".split(): 657 if not dataDict[root][exfile][test].has_key(key): continue 658 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 659 fh.write(line+"\n") 660 fh.write("\n") 661 fh.write("\n") 662 fh.write("\n") 663 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 664 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 665 fh.close() 666 return 667 668 def genPetscTests(self,root,dirs,files,dataDict): 669 """ 670 Go through and parse the source files in the directory to generate 671 the examples based on the metadata contained in the source files 672 """ 673 debug=False 674 # Use examplesAnalyze to get what the makefles think are sources 675 #self.examplesAnalyze(root,dirs,files,anlzDict) 676 677 dataDict[root]={} 678 679 for exfile in files: 680 #TST: Until we replace files, still leaving the orginals as is 681 #if not exfile.startswith("new_"+"ex"): continue 682 if not exfile.startswith("ex"): continue 683 684 # Convenience 685 fullex=os.path.join(root,exfile) 686 relpfile=self.relpath(self.petsc_dir,fullex) 687 if debug: print relpfile 688 dataDict[root].update(testparse.parseTestFile(fullex,0)) 689 # Need to check and make sure tests are in the file 690 # if verbosity>=1: print relpfile 691 if dataDict[root].has_key(exfile): 692 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 693 694 return 695 696 def walktree(self,top,action="printFiles"): 697 """ 698 Walk a directory tree, starting from 'top' 699 """ 700 #print "action", action 701 # Goal of action is to fill this dictionary 702 dataDict={} 703 for root, dirs, files in os.walk(top, topdown=False): 704 if not "examples" in root: continue 705 if not os.path.isfile(os.path.join(root,"makefile")): continue 706 bname=os.path.basename(root.rstrip("/")) 707 if bname=="tests" or bname=="tutorials": 708 eval("self."+action+"(root,dirs,files,dataDict)") 709 if type(top) != types.StringType: 710 raise TypeError("top must be a string") 711 # Now summarize this dictionary 712 eval("self."+action+"_summarize(dataDict)") 713 return dataDict 714 715 def gen_gnumake(self, fd): 716 """ 717 Overwrite of the method in the base PETSc class 718 """ 719 def write(stem, srcs): 720 for lang in LANGS: 721 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 722 for pkg in PKGS: 723 srcs = self.gen_pkg(pkg) 724 write('testsrcs-' + pkg, srcs) 725 return self.gendeps 726 727 def gen_pkg(self, pkg): 728 """ 729 Overwrite of the method in the base PETSc class 730 """ 731 return self.sources[pkg] 732 733 def write_gnumake(self,dataDict): 734 """ 735 Write out something similar to files from gmakegen.py 736 737 There is not a lot of has_key type checking because 738 should just work and need to know if there are bugs 739 740 Test depends on script which also depends on source 741 file, but since I don't have a good way generating 742 acting on a single file (oops) just depend on 743 executable which in turn will depend on src file 744 """ 745 # Different options for how to set up the targets 746 compileExecsFirst=False 747 748 # Open file 749 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 750 fd = open(arch_files, 'w') 751 752 # Write out the sources 753 gendeps = self.gen_gnumake(fd) 754 755 # Write out the tests and execname targets 756 fd.write("\n#Tests and executables\n") # Delimiter 757 758 for pkg in PKGS: 759 # These grab the ones that are built 760 for lang in LANGS: 761 testdeps=[] 762 for ftest in self.tests[pkg][lang]: 763 test=os.path.basename(ftest) 764 basedir=os.path.dirname(ftest) 765 testdeps.append(self.nameSpace(test,basedir)) 766 fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n") 767 fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang)) 768 769 # test targets 770 for ftest in self.tests[pkg][lang]: 771 test=os.path.basename(ftest) 772 basedir=os.path.dirname(ftest) 773 testdir="${TESTDIR}/"+basedir+"/" 774 nmtest=self.nameSpace(test,basedir) 775 rundir=os.path.join(testdir,test) 776 #print test, nmtest 777 script=test+".sh" 778 779 # Deps 780 exfile=self.tests[pkg][lang][ftest]['exfile'] 781 fullex=os.path.join(self.petsc_dir,exfile) 782 localexec=self.tests[pkg][lang][ftest]['exec'] 783 execname=os.path.join(testdir,localexec) 784 fullscript=os.path.join(testdir,script) 785 tmpfile=os.path.join(testdir,test,test+".tmp") 786 787 # *.counts depends on the script and either executable (will 788 # be run) or the example source file (SKIP or TODO) 789 fd.write('%s.counts : %s %s\n' 790 % (os.path.join('$(TESTDIR)/counts', nmtest), 791 fullscript, 792 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)) 793 # Now write the args: 794 fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 795 796 fd.close() 797 return 798 799 def writeHarness(self,output,dataDict): 800 """ 801 This is set up to write out multiple harness even if only gnumake 802 is supported now 803 """ 804 eval("self.write_"+output+"(dataDict)") 805 return 806 807def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 808 if output is None: 809 output = 'gnumake' 810 811 812 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 813 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 814 pEx.writeHarness(output,dataDict) 815 816if __name__ == '__main__': 817 import optparse 818 parser = optparse.OptionParser() 819 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 820 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 821 parser.add_option('--output', help='Location to write output file', default=None) 822 parser.add_option('-s', '--single_executable', dest='single_executable', action="store_false", help='Whether there should be single executable per src subdir. Default is false') 823 opts, extra_args = parser.parse_args() 824 if extra_args: 825 import sys 826 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 827 exit(1) 828 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 829