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