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