xref: /petsc/config/gmakegentest.py (revision e551db170525c6950e3ad11edcf7f326fbf4d6ae)
129921a8fSScott Kruger#!/usr/bin/env python
229921a8fSScott Kruger
329921a8fSScott Krugerimport os,shutil, string, re
429921a8fSScott Krugerfrom distutils.sysconfig import parse_makefile
529921a8fSScott Krugerimport sys
66ac365aeSScott Krugerimport logging, time
729921a8fSScott Krugerimport types
829921a8fSScott Krugersys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
929921a8fSScott Krugerfrom cmakegen import Mistakes, stripsplit, AUTODIRS, SKIPDIRS
1029921a8fSScott Krugerfrom cmakegen import defaultdict # collections.defaultdict, with fallback for python-2.4
1129921a8fSScott Krugerfrom gmakegen import *
1229921a8fSScott Kruger
1329921a8fSScott Krugerimport inspect
1429921a8fSScott Krugerthisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
1529921a8fSScott Krugersys.path.insert(0,thisscriptdir)
1629921a8fSScott Krugerimport testparse
1729921a8fSScott Krugerimport example_template
1829921a8fSScott Kruger
1929921a8fSScott Krugerclass generateExamples(Petsc):
2029921a8fSScott Kruger  """
2129921a8fSScott Kruger    gmakegen.py has basic structure for finding the files, writing out
2229921a8fSScott Kruger      the dependencies, etc.
2329921a8fSScott Kruger  """
24*e551db17SScott Kruger  def __init__(self,petsc_dir=None, petsc_arch=None, testdir=None, verbose=False, single_ex=False, srcdir=None):
25*e551db17SScott Kruger    super(generateExamples, self).__init__(petsc_dir, petsc_arch, verbose)
2629921a8fSScott Kruger
2729921a8fSScott Kruger    self.single_ex=single_ex
28*e551db17SScott Kruger
29*e551db17SScott Kruger    # Determine if we are running from an install directory:
30*e551db17SScott Kruger    dirlist=thisscriptdir.split("/")
31*e551db17SScott Kruger    if len(dirlist)>4:
32*e551db17SScott Kruger      lastfour="/".join(dirlist[len(dirlist)-4:])
33*e551db17SScott Kruger      installdir="/".join(dirlist[0:len(dirlist)-4])
34*e551db17SScott Kruger      srcdir=os.path.join(os.path.dirname(thisscriptdir),'src')
35*e551db17SScott Kruger      self.inInstallDir=True if lastfour=='share/petsc/examples/config' else False
36*e551db17SScott Kruger    else:
37*e551db17SScott Kruger      self.inInstallDir=False
38*e551db17SScott Kruger
39*e551db17SScott Kruger    if not self.inInstallDir:
4029921a8fSScott Kruger      self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch)
41*e551db17SScott Kruger    else:
42*e551db17SScott Kruger      self.arch_dir=installdir
43*e551db17SScott Kruger
44*e551db17SScott Kruger    # Do some initialization
45*e551db17SScott Kruger    if testdir:
46*e551db17SScott Kruger      # If full path given, then use it, otherwise assume relative to arch_dir
47*e551db17SScott Kruger      if testdir.strip().startswith("/"):
48*e551db17SScott Kruger        self.testroot_dir=testdir.strip()
49*e551db17SScott Kruger      else:
50*e551db17SScott Kruger        self.testroot_dir=os.path.join(self.arch_dir,testdir.strip())
51*e551db17SScott Kruger    else:
52*e551db17SScott Kruger      self.testroot_dir=os.path.join(self.arch_dir,"tests")
53*e551db17SScott Kruger
54*e551db17SScott Kruger    if srcdir:
55*e551db17SScott Kruger      self.srcdir=srcdir
56*e551db17SScott Kruger    else:
57*e551db17SScott Kruger      if not self.inInstallDir:
58*e551db17SScott Kruger        self.srcdir=os.path.join(self.petsc_dir,'src')
59*e551db17SScott Kruger      else:
60*e551db17SScott Kruger        self.srcdir=srcdir
61*e551db17SScott Kruger
6229921a8fSScott Kruger    self.ptNaming=True
6329921a8fSScott Kruger    # Whether to write out a useful debugging
6429921a8fSScott Kruger    #if verbose: self.summarize=True
6529921a8fSScott Kruger    self.summarize=True
6629921a8fSScott Kruger
6729921a8fSScott Kruger    # For help in setting the requirements
6812df5dc0SToby Isaac    self.precision_types="single double __float128 int32".split()
6929921a8fSScott Kruger    self.integer_types="int32 int64".split()
7029921a8fSScott Kruger    self.languages="fortran cuda cxx".split()    # Always requires C so do not list
7129921a8fSScott Kruger
7229921a8fSScott Kruger    # Things that are not test
7329921a8fSScott Kruger    self.buildkeys=testparse.buildkeys
7429921a8fSScott Kruger
7529921a8fSScott Kruger    # Adding a dictionary for storing sources, objects, and tests
7629921a8fSScott Kruger    # to make building the dependency tree easier
7729921a8fSScott Kruger    self.sources={}
7829921a8fSScott Kruger    self.objects={}
7929921a8fSScott Kruger    self.tests={}
8029921a8fSScott Kruger    for pkg in PKGS:
8129921a8fSScott Kruger      self.sources[pkg]={}
8229921a8fSScott Kruger      self.objects[pkg]=[]
8329921a8fSScott Kruger      self.tests[pkg]={}
8429921a8fSScott Kruger      for lang in LANGS:
8529921a8fSScott Kruger        self.sources[pkg][lang]={}
8629921a8fSScott Kruger        self.sources[pkg][lang]['srcs']=[]
8729921a8fSScott Kruger        self.tests[pkg][lang]={}
8829921a8fSScott Kruger
8929921a8fSScott Kruger    if not os.path.isdir(self.testroot_dir): os.makedirs(self.testroot_dir)
900357d61fSScott Kruger
910357d61fSScott Kruger    self.indent="   "
9229921a8fSScott Kruger    return
9329921a8fSScott Kruger
9429921a8fSScott Kruger  def nameSpace(self,srcfile,srcdir):
9529921a8fSScott Kruger    """
9629921a8fSScott Kruger    Because the scripts have a non-unique naming, the pretty-printing
9729921a8fSScott Kruger    needs to convey the srcdir and srcfile.  There are two ways of doing this.
9829921a8fSScott Kruger    """
9929921a8fSScott Kruger    if self.ptNaming:
10029921a8fSScott Kruger      cdir=srcdir.split('src')[1].lstrip("/").rstrip("/")
10129921a8fSScott Kruger      prefix=cdir.replace('/examples/','_').replace("/","_")+"-"
10229921a8fSScott Kruger      nameString=prefix+srcfile
10329921a8fSScott Kruger    else:
10429921a8fSScott Kruger      #nameString=srcdir+": "+srcfile
10529921a8fSScott Kruger      nameString=srcfile
10629921a8fSScott Kruger    return nameString
10729921a8fSScott Kruger
10829921a8fSScott Kruger  def getLanguage(self,srcfile):
10929921a8fSScott Kruger    """
11029921a8fSScott Kruger    Based on the source, determine associated language as found in gmakegen.LANGS
11129921a8fSScott Kruger    Can we just return srcext[1:\] now?
11229921a8fSScott Kruger    """
11329921a8fSScott Kruger    langReq=None
11429921a8fSScott Kruger    srcext=os.path.splitext(srcfile)[-1]
11529921a8fSScott Kruger    if srcext in ".F90".split(): langReq="F90"
11629921a8fSScott Kruger    if srcext in ".F".split(): langReq="F"
11729921a8fSScott Kruger    if srcext in ".cxx".split(): langReq="cxx"
11829921a8fSScott Kruger    if srcext == ".cu": langReq="cu"
11929921a8fSScott Kruger    if srcext == ".c": langReq="c"
1200aac2865SBarry Smith    #if not langReq: print "ERROR: ", srcext, srcfile
12129921a8fSScott Kruger    return langReq
12229921a8fSScott Kruger
12396d5c3b5SScott Kruger  def _getLoopVars(self,inDict,testname, isSubtest=False):
124e9b06b45SScott Kruger    """
125e9b06b45SScott Kruger    Given: 'args: -bs {{1 2 3 4 5}} -pc_type {{cholesky sor}} -ksp_monitor'
126e9b06b45SScott Kruger    Return:
12796d5c3b5SScott Kruger      inDict['args']: -ksp_monitor
12896d5c3b5SScott Kruger      inDict['subargs']: -bs ${bs} -pc_type ${pc_type}
1290357d61fSScott Kruger      loopVars['subargs']['varlist']=['bs' 'pc_type']   # Don't worry about OrderedDict
1307827e0d6SScott Kruger      loopVars['subargs']['bs']=[["bs"],["1 2 3 4 5"]]
1317827e0d6SScott Kruger      loopVars['subargs']['pc_type']=[["pc_type"],["cholesky sor"]]
13296d5c3b5SScott Kruger    subst should be passed in instead of inDict
133e9b06b45SScott Kruger    """
1340357d61fSScott Kruger    loopVars={}; newargs=""
13596d5c3b5SScott Kruger    lkeys=inDict.keys()
13696d5c3b5SScott Kruger    lsuffix='_'
137aae9f2d9SScott Kruger    from testparse import parseLoopArgs
1380357d61fSScott Kruger    for key in lkeys:
13996d5c3b5SScott Kruger      if type(inDict[key])!=types.StringType: continue
14096d5c3b5SScott Kruger      keystr = str(inDict[key])
1410357d61fSScott Kruger      akey=('subargs' if key=='args' else key)  # what to assign
142862148f4SScott Kruger      if akey not in inDict: inDict[akey]=''
1430357d61fSScott Kruger      varlist=[]
144e9b06b45SScott Kruger      for varset in re.split('-(?=[a-zA-Z])',keystr):
145e9b06b45SScott Kruger        if not varset.strip(): continue
146aae9f2d9SScott Kruger        if '{{' in varset:
147aae9f2d9SScott Kruger          keyvar,lvars,ftype=parseLoopArgs(varset)
148862148f4SScott Kruger          if akey not in loopVars: loopVars[akey]={}
1497827e0d6SScott Kruger          varlist.append(keyvar)
1502521ea3cSScott Kruger          loopVars[akey][keyvar]=[keyvar,lvars]
1517827e0d6SScott Kruger          if akey=='nsize':
15296d5c3b5SScott Kruger            inDict[akey] = '${' + keyvar + '}'
15396d5c3b5SScott Kruger            lsuffix+=akey+'-'+inDict[akey]+'_'
1547827e0d6SScott Kruger          else:
15596d5c3b5SScott Kruger            inDict[akey] += ' -'+keyvar+' ${' + keyvar + '}'
15696d5c3b5SScott Kruger            lsuffix+=keyvar+'-${' + keyvar + '}_'
1577827e0d6SScott Kruger        else:
1587827e0d6SScott Kruger          if key=='args': newargs+=" -"+varset.strip()
1590357d61fSScott Kruger        if len(varlist)>0: loopVars[akey]['varlist']=varlist
1608ba3acebSToby Isaac
1610357d61fSScott Kruger
1620357d61fSScott Kruger    # For subtests, args are always substituted in (not top level)
1630357d61fSScott Kruger    if isSubtest:
16496d5c3b5SScott Kruger      inDict['subargs']+=" "+newargs.strip()
16596d5c3b5SScott Kruger      inDict['args']=''
166862148f4SScott Kruger      if 'label_suffix' in inDict:
16796d5c3b5SScott Kruger        inDict['label_suffix']+=lsuffix.rstrip('_')
1680357d61fSScott Kruger      else:
16996d5c3b5SScott Kruger        inDict['label_suffix']=lsuffix.rstrip('_')
17096d5c3b5SScott Kruger    else:
17196d5c3b5SScott Kruger      if len(loopVars.keys())>0:
17296d5c3b5SScott Kruger        inDict['args']=newargs.strip()
17396d5c3b5SScott Kruger        inDict['label_suffix']=lsuffix.rstrip('_')
1740357d61fSScott Kruger    if len(loopVars.keys())>0:
175e9b06b45SScott Kruger      return loopVars
1760357d61fSScott Kruger    else:
1770357d61fSScott Kruger      return None
1788ba3acebSToby Isaac
17929921a8fSScott Kruger  def getArgLabel(self,testDict):
18029921a8fSScott Kruger    """
18129921a8fSScott Kruger    In all of the arguments in the test dictionary, create a simple
18229921a8fSScott Kruger    string for searching within the makefile system.  For simplicity in
18329921a8fSScott Kruger    search, remove "-", for strings, etc.
18429921a8fSScott Kruger    Also, concatenate the arg commands
18529921a8fSScott Kruger    For now, ignore nsize -- seems hard to search for anyway
18629921a8fSScott Kruger    """
18729921a8fSScott Kruger    # Collect all of the args associated with a test
188862148f4SScott Kruger    argStr=("" if 'args' not in testDict else testDict['args'])
189862148f4SScott Kruger    if 'subtests' in testDict:
19029921a8fSScott Kruger      for stest in testDict["subtests"]:
19129921a8fSScott Kruger         sd=testDict[stest]
192862148f4SScott Kruger         argStr=argStr+("" if 'args' not in sd else sd['args'])
19329921a8fSScott Kruger
19429921a8fSScott Kruger    # Now go through and cleanup
19529921a8fSScott Kruger    argStr=re.sub('{{(.*?)}}',"",argStr)
19629921a8fSScott Kruger    argStr=re.sub('-'," ",argStr)
19729921a8fSScott Kruger    for digit in string.digits: argStr=re.sub(digit," ",argStr)
19829921a8fSScott Kruger    argStr=re.sub("\.","",argStr)
19929921a8fSScott Kruger    argStr=re.sub(",","",argStr)
20029921a8fSScott Kruger    argStr=re.sub('\+',' ',argStr)
20129921a8fSScott Kruger    argStr=re.sub(' +',' ',argStr)  # Remove repeated white space
20229921a8fSScott Kruger    return argStr.strip()
20329921a8fSScott Kruger
20429921a8fSScott Kruger  def addToSources(self,exfile,root,srcDict):
20529921a8fSScott Kruger    """
20629921a8fSScott Kruger      Put into data structure that allows easy generation of makefile
20729921a8fSScott Kruger    """
208*e551db17SScott Kruger    rpath=os.path.join('src',os.path.relpath(root,self.srcdir))
209*e551db17SScott Kruger    pkg=rpath.split("/")[1]
21029921a8fSScott Kruger    fullfile=os.path.join(root,exfile)
211*e551db17SScott Kruger    relpfile=os.path.join(rpath,exfile)
21229921a8fSScott Kruger    lang=self.getLanguage(exfile)
2130aac2865SBarry Smith    if not lang: return
21429921a8fSScott Kruger    self.sources[pkg][lang]['srcs'].append(relpfile)
215862148f4SScott Kruger    if 'depends' in srcDict:
21629921a8fSScott Kruger      depSrc=srcDict['depends']
21729921a8fSScott Kruger      depObj=os.path.splitext(depSrc)[0]+".o"
21829921a8fSScott Kruger      self.sources[pkg][lang][exfile]=depObj
21929921a8fSScott Kruger
22029921a8fSScott Kruger    # In gmakefile, ${TESTDIR} var specifies the object compilation
22129921a8fSScott Kruger    testsdir=self.relpath(self.petsc_dir,root)+"/"
22229921a8fSScott Kruger    objfile="${TESTDIR}/"+testsdir+os.path.splitext(exfile)[0]+".o"
22329921a8fSScott Kruger    self.objects[pkg].append(objfile)
22429921a8fSScott Kruger    return
22529921a8fSScott Kruger
22629921a8fSScott Kruger  def addToTests(self,test,root,exfile,execname,testDict):
22729921a8fSScott Kruger    """
22829921a8fSScott Kruger      Put into data structure that allows easy generation of makefile
22929921a8fSScott Kruger      Organized by languages to allow testing of languages
23029921a8fSScott Kruger    """
231*e551db17SScott Kruger    rpath=os.path.join('src',os.path.relpath(root,self.srcdir))
232*e551db17SScott Kruger    pkg=rpath.split("/")[1]
23329921a8fSScott Kruger    #nmtest=self.nameSpace(test,root)
23429921a8fSScott Kruger    nmtest=os.path.join(rpath,test)
23529921a8fSScott Kruger    lang=self.getLanguage(exfile)
2360aac2865SBarry Smith    if not lang: return
23729921a8fSScott Kruger    self.tests[pkg][lang][nmtest]={}
23829921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['exfile']=os.path.join(rpath,exfile)
23929921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['exec']=execname
24029921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['argLabel']=self.getArgLabel(testDict)
24129921a8fSScott Kruger    return
24229921a8fSScott Kruger
24329921a8fSScott Kruger  def getExecname(self,exfile,root):
24429921a8fSScott Kruger    """
24529921a8fSScott Kruger      Generate bash script using template found next to this file.
24629921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
24729921a8fSScott Kruger    """
248*e551db17SScott Kruger    rpath=os.path.join('src',os.path.relpath(root,self.srcdir))
24929921a8fSScott Kruger    if self.single_ex:
25029921a8fSScott Kruger      execname=rpath.split("/")[1]+"-ex"
25129921a8fSScott Kruger    else:
25229921a8fSScott Kruger      execname=os.path.splitext(exfile)[0]
25329921a8fSScott Kruger    return execname
25429921a8fSScott Kruger
25529921a8fSScott Kruger  def getSubstVars(self,testDict,rpath,testname):
25629921a8fSScott Kruger    """
25729921a8fSScott Kruger      Create a dictionary with all of the variables that get substituted
25829921a8fSScott Kruger      into the template commands found in example_template.py
25929921a8fSScott Kruger    """
26029921a8fSScott Kruger    subst={}
26196d5c3b5SScott Kruger
26296d5c3b5SScott Kruger    # Handle defaults of testparse.acceptedkeys (e.g., ignores subtests)
263862148f4SScott Kruger    if 'nsize' not in testDict: testDict['nsize']=1
2640a091e3eSScott Kruger    if 'timeoutfactor' not in testDict: testDict['timeoutfactor']="1"
26596d5c3b5SScott Kruger    for ak in testparse.acceptedkeys:
26696d5c3b5SScott Kruger      if ak=='test': continue
267862148f4SScott Kruger      subst[ak]=(testDict[ak] if ak in testDict else '')
26896d5c3b5SScott Kruger
26996d5c3b5SScott Kruger    # Now do other variables
27096d5c3b5SScott Kruger    subst['execname']=testDict['execname']
271862148f4SScott Kruger    if 'filter' in testDict:
27296d5c3b5SScott Kruger      subst['filter']="'"+testDict['filter']+"'"   # Quotes are tricky - overwrite
27368a9e459SScott Kruger
27496d5c3b5SScott Kruger    # Others
27596d5c3b5SScott Kruger    subst['subargs']=''  # Default.  For variables override
276*e551db17SScott Kruger    subst['srcdir']=os.path.join(os.path.dirname(self.srcdir),rpath)
27768a9e459SScott Kruger    subst['label_suffix']=''
27896d5c3b5SScott Kruger    subst['comments']="\n#".join(subst['comments'].split("\n"))
27968a9e459SScott Kruger    if subst['comments']: subst['comments']="#"+subst['comments']
28096d5c3b5SScott Kruger    subst['exec']="../"+subst['execname']
28129921a8fSScott Kruger    subst['testroot']=self.testroot_dir
28229921a8fSScott Kruger    subst['testname']=testname
28309cf0baaSJed Brown    dp = self.conf.get('DATAFILESPATH','')
28409cf0baaSJed Brown    subst['datafilespath_line'] = 'DATAFILESPATH=${DATAFILESPATH:-"'+dp+'"}'
28529921a8fSScott Kruger
2860bcc1aabSScott Kruger    # This is used to label some matrices
2870bcc1aabSScott Kruger    subst['petsc_index_size']=str(self.conf['PETSC_INDEX_SIZE'])
2880bcc1aabSScott Kruger    subst['petsc_scalar_size']=str(self.conf['PETSC_SCALAR_SIZE'])
2890bcc1aabSScott Kruger
29029921a8fSScott Kruger    # These can have for loops and are treated separately later
29196d5c3b5SScott Kruger    subst['nsize']=str(subst['nsize'])
29229921a8fSScott Kruger
29329921a8fSScott Kruger    #Conf vars
29426646c0bSSatish Balay    if self.petsc_arch.find('valgrind')>=0:
29526646c0bSSatish Balay      subst['mpiexec']='petsc_mpiexec_valgrind ' + self.conf['MPIEXEC']
29626646c0bSSatish Balay    else:
29726646c0bSSatish Balay      subst['mpiexec']=self.conf['MPIEXEC']
2984c8d737cSSatish Balay    subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path
2990a091e3eSScott Kruger    subst['petsc_arch']=self.petsc_arch
300*e551db17SScott Kruger    if not self.inInstallDir:
301*e551db17SScott Kruger      subst['CONFIG_DIR']=os.path.join(self.petsc_dir,'config')
302*e551db17SScott Kruger    else:
303*e551db17SScott Kruger      subst['CONFIG_DIR']=os.path.join(os.path.dirname(self.srcdir),'config')
30429921a8fSScott Kruger    subst['diff']=self.conf['DIFF']
30529921a8fSScott Kruger    subst['rm']=self.conf['RM']
30629921a8fSScott Kruger    subst['grep']=self.conf['GREP']
307d6f00007SSatish Balay    subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR']
3080eb9b082SSatish Balay    subst['wpetsc_dir']=self.conf['wPETSC_DIR']
30929921a8fSScott Kruger
3103bcca444SScott Kruger    # Output file is special because of subtests override
3113bcca444SScott Kruger    defroot=(re.sub("run","",testname) if testname.startswith("run") else testname)
3123bcca444SScott Kruger    if not "_" in defroot: defroot=defroot+"_1"
3133bcca444SScott Kruger    subst['defroot']=defroot
3143bcca444SScott Kruger    subst['label']=self.nameSpace(defroot,subst['srcdir'])
3153bcca444SScott Kruger    subst['redirect_file']=defroot+".tmp"
316862148f4SScott Kruger    if 'output_file' not in testDict:
3173bcca444SScott Kruger      subst['output_file']="output/"+defroot+".out"
3183bcca444SScott Kruger    # Add in the full path here.
3193bcca444SScott Kruger    subst['output_file']=os.path.join(subst['srcdir'],subst['output_file'])
3203bcca444SScott Kruger    if not os.path.isfile(os.path.join(self.petsc_dir,subst['output_file'])):
3213bcca444SScott Kruger      if not subst['TODO']:
3223bcca444SScott Kruger        print "Warning: "+subst['output_file']+" not found."
3233bcca444SScott Kruger    # Worry about alt files here -- see
3243bcca444SScott Kruger    #   src/snes/examples/tutorials/output/ex22*.out
3253bcca444SScott Kruger    altlist=[subst['output_file']]
3263bcca444SScott Kruger    for i in range(1,3):
3273bcca444SScott Kruger      altroot=defroot+"_alt"
3283bcca444SScott Kruger      if i==2: altroot=altroot+"_2"
3293bcca444SScott Kruger      af="output/"+altroot+".out"
3303bcca444SScott Kruger      srcaf=os.path.join(subst['srcdir'],af)
3313bcca444SScott Kruger      fullaf=os.path.join(self.petsc_dir,srcaf)
3323bcca444SScott Kruger      if os.path.isfile(fullaf): altlist.append(srcaf)
3333bcca444SScott Kruger    if len(altlist)>1: subst['altfiles']=altlist
3343bcca444SScott Kruger    #if len(altlist)>1: print "Found alt files: ",altlist
3353bcca444SScott Kruger
33629921a8fSScott Kruger    return subst
33729921a8fSScott Kruger
3380357d61fSScott Kruger  def getCmds(self,subst,i):
33929921a8fSScott Kruger    """
34029921a8fSScott Kruger      Generate bash script using template found next to this file.
34129921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
34229921a8fSScott Kruger    """
3430357d61fSScott Kruger    nindnt=i # the start and has to be consistent with below
3447a853109SScott Kruger    cmdindnt=self.indent*nindnt
34529921a8fSScott Kruger    cmdLines=""
34668a9e459SScott Kruger
34729921a8fSScott Kruger    # MPI is the default -- but we have a few odd commands
34896d5c3b5SScott Kruger    if not subst['command']:
3497a853109SScott Kruger      cmd=cmdindnt+self._substVars(subst,example_template.mpitest)
35029921a8fSScott Kruger    else:
3517a853109SScott Kruger      cmd=cmdindnt+self._substVars(subst,example_template.commandtest)
3527a853109SScott Kruger    cmdLines+=cmd+"\n"+cmdindnt+"res=$?\n\n"
35329921a8fSScott Kruger
3547a853109SScott Kruger    cmdLines+=cmdindnt+'if test $res = 0; then\n'
3557a853109SScott Kruger    diffindnt=self.indent*(nindnt+1)
35664ca018dSScott Kruger    if not subst['filter_output']:
357862148f4SScott Kruger      if 'altfiles' not in subst:
3587a853109SScott Kruger        cmd=diffindnt+self._substVars(subst,example_template.difftest)
35964ca018dSScott Kruger      else:
3603bcca444SScott Kruger        # Have to do it by hand a bit because of variable number of alt files
3613bcca444SScott Kruger        rf=subst['redirect_file']
3627a853109SScott Kruger        cmd=diffindnt+example_template.difftest.split('@')[0]
3633bcca444SScott Kruger        for i in range(len(subst['altfiles'])):
3643bcca444SScott Kruger          af=subst['altfiles'][i]
3653bcca444SScott Kruger          cmd+=af+' '+rf+' > diff-${testname}-'+str(i)+'.out 2> diff-${testname}-'+str(i)+'.out'
3663bcca444SScott Kruger          if i!=len(subst['altfiles'])-1:
3673bcca444SScott Kruger            cmd+=' || ${diff_exe} '
3683bcca444SScott Kruger          else:
3693bcca444SScott Kruger            cmd+='" diff-${testname}.out diff-${testname}.out diff-${label}'
3703bcca444SScott Kruger            cmd+=subst['label_suffix']+' ""'  # Quotes are painful
3713bcca444SScott Kruger    else:
3727a853109SScott Kruger      cmd=diffindnt+self._substVars(subst,example_template.filterdifftest)
37368a9e459SScott Kruger    cmdLines+=cmd+"\n"
3747a853109SScott Kruger    cmdLines+=cmdindnt+'else\n'
3757a853109SScott Kruger    cmdLines+=diffindnt+'printf "ok ${label} # SKIP Command failed so no diff\\n"\n'
3767a853109SScott Kruger    cmdLines+=cmdindnt+'fi\n'
37729921a8fSScott Kruger    return cmdLines
37829921a8fSScott Kruger
37929921a8fSScott Kruger  def _substVars(self,subst,origStr):
38029921a8fSScott Kruger    """
3817827e0d6SScott Kruger      Substitute variables
38229921a8fSScott Kruger    """
38329921a8fSScott Kruger    Str=origStr
38429921a8fSScott Kruger    for subkey in subst:
38529921a8fSScott Kruger      if type(subst[subkey])!=types.StringType: continue
38629921a8fSScott Kruger      patt="@"+subkey.upper()+"@"
38729921a8fSScott Kruger      Str=re.sub(patt,subst[subkey],Str)
38829921a8fSScott Kruger    return Str
38929921a8fSScott Kruger
39009cf0baaSJed Brown  def _writeTodoSkip(self,fh,tors,reasons,footer):
39168a9e459SScott Kruger    """
39268a9e459SScott Kruger    Write out the TODO and SKIP lines in the file
39368a9e459SScott Kruger    The TODO or SKIP variable, tors, should be lower case
39468a9e459SScott Kruger    """
39568a9e459SScott Kruger    TORS=tors.upper()
39668a9e459SScott Kruger    template=eval("example_template."+tors+"line")
39709cf0baaSJed Brown    tsStr=re.sub("@"+TORS+"COMMENT@",', '.join(reasons),template)
39809cf0baaSJed Brown    tab = ''
3992f2809e3SToby Isaac    if reasons:
4002f2809e3SToby Isaac      fh.write('if ! $force; then\n')
4012f2809e3SToby Isaac      tab = tab + '    '
40209cf0baaSJed Brown    if reasons == ["Requires DATAFILESPATH"]:
40309cf0baaSJed Brown      # The only reason not to run is DATAFILESPATH, which we check at run-time
4042f2809e3SToby Isaac      fh.write(tab + 'if test -z "${DATAFILESPATH}"; then\n')
4052f2809e3SToby Isaac      tab = tab + '    '
40609cf0baaSJed Brown    if reasons:
4072f2809e3SToby Isaac      fh.write(tab+tsStr+"\n" + tab + "total=1; "+tors+"=1\n")
40809cf0baaSJed Brown      fh.write(tab+footer+"\n")
40909cf0baaSJed Brown      fh.write(tab+"exit\n")
41009cf0baaSJed Brown    if reasons == ["Requires DATAFILESPATH"]:
41109cf0baaSJed Brown      fh.write('    fi\n')
4122f2809e3SToby Isaac    if reasons:
4132f2809e3SToby Isaac      fh.write('fi\n')
41409cf0baaSJed Brown    fh.write('\n\n')
41568a9e459SScott Kruger    return
41668a9e459SScott Kruger
4178ba3acebSToby Isaac  def getLoopVarsHead(self,loopVars,i):
4180357d61fSScott Kruger    """
4190357d61fSScott Kruger    Generate a nicely indented string with the format loops
4200357d61fSScott Kruger    Here is what the data structure looks like
4210357d61fSScott Kruger      loopVars['subargs']['varlist']=['bs' 'pc_type']   # Don't worry about OrderedDict
4220357d61fSScott Kruger      loopVars['subargs']['bs']=["i","1 2 3 4 5"]
4230357d61fSScott Kruger      loopVars['subargs']['pc_type']=["j","cholesky sor"]
4240357d61fSScott Kruger    """
4250357d61fSScott Kruger    outstr=''; indnt=self.indent
4268ba3acebSToby Isaac    for key in loopVars:
4270357d61fSScott Kruger      for var in loopVars[key]['varlist']:
4280357d61fSScott Kruger        varval=loopVars[key][var]
4290357d61fSScott Kruger        outstr += indnt * i + "for "+varval[0]+" in "+varval[1]+"; do\n"
4308ba3acebSToby Isaac        i = i + 1
4318ba3acebSToby Isaac    return (outstr,i)
4328ba3acebSToby Isaac
4338ba3acebSToby Isaac  def getLoopVarsFoot(self,loopVars,i):
4340357d61fSScott Kruger    outstr=''; indnt=self.indent
4358ba3acebSToby Isaac    for key in loopVars:
4360357d61fSScott Kruger      for var in loopVars[key]['varlist']:
4378ba3acebSToby Isaac        i = i - 1
4380357d61fSScott Kruger        outstr += indnt * i + "done\n"
4398ba3acebSToby Isaac    return (outstr,i)
4408ba3acebSToby Isaac
44129921a8fSScott Kruger  def genRunScript(self,testname,root,isRun,srcDict):
44229921a8fSScott Kruger    """
44329921a8fSScott Kruger      Generate bash script using template found next to this file.
44429921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
44529921a8fSScott Kruger    """
44629921a8fSScott Kruger    # runscript_dir directory has to be consistent with gmakefile
44729921a8fSScott Kruger    testDict=srcDict[testname]
448*e551db17SScott Kruger    rpath=os.path.join('src',os.path.relpath(root,self.srcdir))
44929921a8fSScott Kruger    runscript_dir=os.path.join(self.testroot_dir,rpath)
45029921a8fSScott Kruger    if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir)
45129921a8fSScott Kruger    fh=open(os.path.join(runscript_dir,testname+".sh"),"w")
45229921a8fSScott Kruger    petscvarfile=os.path.join(self.arch_dir,'lib','petsc','conf','petscvariables')
45329921a8fSScott Kruger
45496d5c3b5SScott Kruger    # Get variables to go into shell scripts.  last time testDict used
45529921a8fSScott Kruger    subst=self.getSubstVars(testDict,rpath,testname)
45696d5c3b5SScott Kruger    loopVars = self._getLoopVars(subst,testname)  # Alters subst as well
45796d5c3b5SScott Kruger    #if '33_' in testname: print subst['subargs']
45829921a8fSScott Kruger
45964ca018dSScott Kruger    #Handle runfiles
460862148f4SScott Kruger    for lfile in subst.get('localrunfiles','').split():
461*e551db17SScott Kruger      fullfile=os.path.join(root,lfile)
46264ca018dSScott Kruger      shutil.copy(fullfile,runscript_dir)
46364ca018dSScott Kruger    # Check subtests for local runfiles
464862148f4SScott Kruger    for stest in subst.get("subtests",[]):
465862148f4SScott Kruger      for lfile in testDict[stest].get('localrunfiles','').split():
466*e551db17SScott Kruger        fullfile=os.path.join(root,lfile)
46764ca018dSScott Kruger        shutil.copy(fullfile,self.runscript_dir)
46864ca018dSScott Kruger
46929921a8fSScott Kruger    # Now substitute the key variables into the header and footer
47029921a8fSScott Kruger    header=self._substVars(subst,example_template.header)
4710bcc1aabSScott Kruger    # The header is done twice to enable @...@ in header
4720bcc1aabSScott Kruger    header=self._substVars(subst,header)
4735e7f8670SScott Kruger    footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer)
47429921a8fSScott Kruger
47529921a8fSScott Kruger    # Start writing the file
47629921a8fSScott Kruger    fh.write(header+"\n")
47729921a8fSScott Kruger
47829921a8fSScott Kruger    # If there is a TODO or a SKIP then we do it before writing out the
47929921a8fSScott Kruger    # rest of the command (which is useful for working on the test)
48029921a8fSScott Kruger    # SKIP and TODO can be for the source file or for the runs
48109cf0baaSJed Brown    self._writeTodoSkip(fh,'todo',[s for s in [srcDict.get('TODO',''), testDict.get('TODO','')] if s],footer)
48209cf0baaSJed Brown    self._writeTodoSkip(fh,'skip',srcDict.get('SKIP',[]) + testDict.get('SKIP',[]),footer)
48329921a8fSScott Kruger
48429921a8fSScott Kruger    j=0  # for indentation
48529921a8fSScott Kruger
4860357d61fSScott Kruger    if loopVars:
4878ba3acebSToby Isaac      (loopHead,j) = self.getLoopVarsHead(loopVars,j)
4888ba3acebSToby Isaac      if (loopHead): fh.write(loopHead+"\n")
48929921a8fSScott Kruger
49029921a8fSScott Kruger    # Subtests are special
491862148f4SScott Kruger    if 'subtests' in testDict:
49229921a8fSScott Kruger      substP=subst   # Subtests can inherit args but be careful
49329921a8fSScott Kruger      for stest in testDict["subtests"]:
4941e4ea733SToby Isaac        subst=substP.copy()
4950357d61fSScott Kruger        subst.update(testDict[stest])
4960357d61fSScott Kruger        subst['nsize']=str(subst['nsize'])
4977827e0d6SScott Kruger        sLoopVars = self._getLoopVars(subst,testname,isSubtest=True)
4987827e0d6SScott Kruger        #if '10_9' in testname: print sLoopVars
4990357d61fSScott Kruger        if sLoopVars:
5008ba3acebSToby Isaac          (sLoopHead,j) = self.getLoopVarsHead(sLoopVars,j)
5010357d61fSScott Kruger          fh.write(sLoopHead+"\n")
5020357d61fSScott Kruger        fh.write(self.getCmds(subst,j)+"\n")
5030357d61fSScott Kruger        if sLoopVars:
5048ba3acebSToby Isaac          (sLoopFoot,j) = self.getLoopVarsFoot(sLoopVars,j)
5050357d61fSScott Kruger          fh.write(sLoopFoot+"\n")
50629921a8fSScott Kruger    else:
50729921a8fSScott Kruger      fh.write(self.getCmds(subst,j)+"\n")
5088ba3acebSToby Isaac
5090357d61fSScott Kruger    if loopVars:
5108ba3acebSToby Isaac      (loopFoot,j) = self.getLoopVarsFoot(loopVars,j)
5110357d61fSScott Kruger      fh.write(loopFoot+"\n")
51229921a8fSScott Kruger
51329921a8fSScott Kruger    fh.write(footer+"\n")
514b181ea86SSatish Balay    os.chmod(os.path.join(runscript_dir,testname+".sh"),0755)
5157827e0d6SScott Kruger    #if '10_9' in testname: sys.exit()
51629921a8fSScott Kruger    return
51729921a8fSScott Kruger
51829921a8fSScott Kruger  def  genScriptsAndInfo(self,exfile,root,srcDict):
51929921a8fSScott Kruger    """
52029921a8fSScott Kruger    Generate scripts from the source file, determine if built, etc.
52129921a8fSScott Kruger     For every test in the exfile with info in the srcDict:
52229921a8fSScott Kruger      1. Determine if it needs to be run for this arch
52329921a8fSScott Kruger      2. Generate the script
52429921a8fSScott Kruger      3. Generate the data needed to write out the makefile in a
52529921a8fSScott Kruger         convenient way
52629921a8fSScott Kruger     All tests are *always* run, but some may be SKIP'd per the TAP standard
52729921a8fSScott Kruger    """
52829921a8fSScott Kruger    debug=False
52929921a8fSScott Kruger    execname=self.getExecname(exfile,root)
53029921a8fSScott Kruger    isBuilt=self._isBuilt(exfile,srcDict)
53129921a8fSScott Kruger    for test in srcDict:
53229921a8fSScott Kruger      if test in self.buildkeys: continue
53329921a8fSScott Kruger      if debug: print self.nameSpace(exfile,root), test
53429921a8fSScott Kruger      srcDict[test]['execname']=execname   # Convenience in generating scripts
53529921a8fSScott Kruger      isRun=self._isRun(srcDict[test])
53629921a8fSScott Kruger      self.genRunScript(test,root,isRun,srcDict)
53729921a8fSScott Kruger      srcDict[test]['isrun']=isRun
53829921a8fSScott Kruger      self.addToTests(test,root,exfile,execname,srcDict[test])
53929921a8fSScott Kruger
54029921a8fSScott Kruger    # This adds to datastructure for building deps
541a8eb4092SScott Kruger    if isBuilt: self.addToSources(exfile,root,srcDict)
54229921a8fSScott Kruger    return
54329921a8fSScott Kruger
54429921a8fSScott Kruger  def _isBuilt(self,exfile,srcDict):
54529921a8fSScott Kruger    """
54629921a8fSScott Kruger    Determine if this file should be built.
54729921a8fSScott Kruger    """
54829921a8fSScott Kruger    # Get the language based on file extension
54909cf0baaSJed Brown    srcDict['SKIP'] = []
55029921a8fSScott Kruger    lang=self.getLanguage(exfile)
551c2426ab2SScott Kruger    if (lang=="F" or lang=="F90"):
552c2426ab2SScott Kruger      if not self.have_fortran:
55309cf0baaSJed Brown        srcDict["SKIP"].append("Fortran required for this test")
554c2426ab2SScott Kruger      elif lang=="F90" and 'PETSC_USING_F90FREEFORM' not in self.conf:
555c2426ab2SScott Kruger        srcDict["SKIP"].append("Fortran f90freeform required for this test")
556862148f4SScott Kruger    if lang=="cu" and 'PETSC_HAVE_CUDA' not in self.conf:
55709cf0baaSJed Brown      srcDict["SKIP"].append("CUDA required for this test")
558862148f4SScott Kruger    if lang=="cxx" and 'PETSC_HAVE_CXX' not in self.conf:
55909cf0baaSJed Brown      srcDict["SKIP"].append("C++ required for this test")
56029921a8fSScott Kruger
56129921a8fSScott Kruger    # Deprecated source files
56209cf0baaSJed Brown    if srcDict.get("TODO"):
56309cf0baaSJed Brown      return False
56429921a8fSScott Kruger
56529921a8fSScott Kruger    # isRun can work with srcDict to handle the requires
566862148f4SScott Kruger    if "requires" in srcDict:
56729921a8fSScott Kruger      if len(srcDict["requires"])>0:
56829921a8fSScott Kruger        return self._isRun(srcDict)
56929921a8fSScott Kruger
57009cf0baaSJed Brown    return srcDict['SKIP'] == []
57129921a8fSScott Kruger
57229921a8fSScott Kruger
57329921a8fSScott Kruger  def _isRun(self,testDict):
57429921a8fSScott Kruger    """
57529921a8fSScott Kruger    Based on the requirements listed in the src file and the petscconf.h
57629921a8fSScott Kruger    info, determine whether this test should be run or not.
57729921a8fSScott Kruger    """
57829921a8fSScott Kruger    indent="  "
57929921a8fSScott Kruger    debug=False
58029921a8fSScott Kruger
58109cf0baaSJed Brown    if 'SKIP' not in testDict:
58209cf0baaSJed Brown      testDict['SKIP'] = []
58329921a8fSScott Kruger    # MPI requirements
584862148f4SScott Kruger    if testDict.get('nsize',1)>1 and 'MPI_IS_MPIUNI' in self.conf:
58529921a8fSScott Kruger      if debug: print indent+"Cannot run parallel tests"
58609cf0baaSJed Brown      testDict['SKIP'].append("Parallel test with serial build")
58729921a8fSScott Kruger
58829921a8fSScott Kruger    # The requirements for the test are the sum of all the run subtests
589862148f4SScott Kruger    if 'subtests' in testDict:
590862148f4SScott Kruger      if 'requires' not in testDict: testDict['requires']=""
59129921a8fSScott Kruger      for stest in testDict['subtests']:
592862148f4SScott Kruger        if 'requires' in testDict[stest]:
593862148f4SScott Kruger          testDict['requires']+=" "+testDict[stest]['requires']
59429921a8fSScott Kruger
59529921a8fSScott Kruger
59629921a8fSScott Kruger    # Now go through all requirements
597862148f4SScott Kruger    if 'requires' in testDict:
59829921a8fSScott Kruger      for requirement in testDict['requires'].split():
59929921a8fSScott Kruger        requirement=requirement.strip()
60029921a8fSScott Kruger        if not requirement: continue
60129921a8fSScott Kruger        if debug: print indent+"Requirement: ", requirement
60229921a8fSScott Kruger        isNull=False
60329921a8fSScott Kruger        if requirement.startswith("!"):
60429921a8fSScott Kruger          requirement=requirement[1:]; isNull=True
60529921a8fSScott Kruger        # Precision requirement for reals
60629921a8fSScott Kruger        if requirement in self.precision_types:
60729921a8fSScott Kruger          if self.conf['PETSC_PRECISION']==requirement:
60809cf0baaSJed Brown            if isNull:
60909cf0baaSJed Brown              testDict['SKIP'].append("not "+requirement+" required")
61009cf0baaSJed Brown              continue
6114bb4d03dSScott Kruger            continue  # Success
61209cf0baaSJed Brown          elif not isNull:
61309cf0baaSJed Brown            testDict['SKIP'].append(requirement+" required")
61409cf0baaSJed Brown            continue
61529921a8fSScott Kruger        # Precision requirement for ints
61629921a8fSScott Kruger        if requirement in self.integer_types:
61729921a8fSScott Kruger          if requirement=="int32":
61829921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==4:
61909cf0baaSJed Brown              if isNull:
62009cf0baaSJed Brown                testDict['SKIP'].append("not int32 required")
62109cf0baaSJed Brown                continue
6224bb4d03dSScott Kruger              continue  # Success
62309cf0baaSJed Brown            elif not isNull:
62409cf0baaSJed Brown              testDict['SKIP'].append("int32 required")
62509cf0baaSJed Brown              continue
62629921a8fSScott Kruger          if requirement=="int64":
62729921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==8:
62809cf0baaSJed Brown              if isNull:
62909cf0baaSJed Brown                testDict['SKIP'].append("NOT int64 required")
63009cf0baaSJed Brown                continue
6314bb4d03dSScott Kruger              continue  # Success
63209cf0baaSJed Brown            elif not isNull:
63309cf0baaSJed Brown              testDict['SKIP'].append("int64 required")
63409cf0baaSJed Brown              continue
63529921a8fSScott Kruger        # Datafilespath
63609cf0baaSJed Brown        if requirement=="datafilespath" and not isNull:
63709cf0baaSJed Brown          testDict['SKIP'].append("Requires DATAFILESPATH")
63809cf0baaSJed Brown          continue
63929921a8fSScott Kruger        # Defines -- not sure I have comments matching
6408304fa3fSScott Kruger        if "define(" in requirement.lower():
64129921a8fSScott Kruger          reqdef=requirement.split("(")[1].split(")")[0]
64209cf0baaSJed Brown          if reqdef in self.conf:
64329921a8fSScott Kruger            if isNull:
64409cf0baaSJed Brown              testDict['SKIP'].append("Null requirement not met: "+requirement)
64509cf0baaSJed Brown              continue
6464bb4d03dSScott Kruger            continue  # Success
6474bb4d03dSScott Kruger          elif not isNull:
64809cf0baaSJed Brown            testDict['SKIP'].append("Required: "+requirement)
64909cf0baaSJed Brown            continue
65029921a8fSScott Kruger
65129921a8fSScott Kruger        # Rest should be packages that we can just get from conf
65209cf0baaSJed Brown        if requirement == "complex":
65309cf0baaSJed Brown          petscconfvar="PETSC_USE_COMPLEX"
65409cf0baaSJed Brown        else:
65509cf0baaSJed Brown          petscconfvar="PETSC_HAVE_"+requirement.upper()
65629921a8fSScott Kruger        if self.conf.get(petscconfvar):
65729921a8fSScott Kruger          if isNull:
65809cf0baaSJed Brown            testDict['SKIP'].append("Not "+petscconfvar+" requirement not met")
65909cf0baaSJed Brown            continue
6604bb4d03dSScott Kruger          continue  # Success
661df3aec83SJed Brown        elif not isNull:
66229921a8fSScott Kruger          if debug: print "requirement not found: ", requirement
66309cf0baaSJed Brown          testDict['SKIP'].append(petscconfvar+" requirement not met")
66409cf0baaSJed Brown          continue
66529921a8fSScott Kruger
66609cf0baaSJed Brown    return testDict['SKIP'] == []
66729921a8fSScott Kruger
66829921a8fSScott Kruger  def genPetscTests_summarize(self,dataDict):
66929921a8fSScott Kruger    """
67029921a8fSScott Kruger    Required method to state what happened
67129921a8fSScott Kruger    """
67229921a8fSScott Kruger    if not self.summarize: return
67329921a8fSScott Kruger    indent="   "
674cfaa06beSSatish Balay    fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt')
67529921a8fSScott Kruger    fh=open(fhname,"w")
67664ca018dSScott Kruger    #print "See ", fhname
67729921a8fSScott Kruger    for root in dataDict:
678*e551db17SScott Kruger      relroot=os.path.join('src',os.path.relpath(root,self.srcdir))
67929921a8fSScott Kruger      pkg=relroot.split("/")[1]
68029921a8fSScott Kruger      fh.write(relroot+"\n")
68129921a8fSScott Kruger      allSrcs=[]
682*e551db17SScott Kruger      for lang in LANGS: allSrcs+=self.sources[pkg][lang]['srcs']
68329921a8fSScott Kruger      for exfile in dataDict[root]:
68429921a8fSScott Kruger        # Basic  information
68529921a8fSScott Kruger        fullfile=os.path.join(root,exfile)
686*e551db17SScott Kruger        rfile=os.path.join('src',os.path.relpath(root,self.srcdir))
68729921a8fSScott Kruger        builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built")
68829921a8fSScott Kruger        fh.write(indent+exfile+indent*4+builtStatus+"\n")
68929921a8fSScott Kruger
69029921a8fSScott Kruger        for test in dataDict[root][exfile]:
69129921a8fSScott Kruger          if test in self.buildkeys: continue
69229921a8fSScott Kruger          line=indent*2+test
69329921a8fSScott Kruger          fh.write(line+"\n")
69429921a8fSScott Kruger          # Looks nice to have the keys in order
69529921a8fSScott Kruger          #for key in dataDict[root][exfile][test]:
69629921a8fSScott Kruger          for key in "isrun abstracted nsize args requires script".split():
697862148f4SScott Kruger            if key not in dataDict[root][exfile][test]: continue
69829921a8fSScott Kruger            line=indent*3+key+": "+str(dataDict[root][exfile][test][key])
69929921a8fSScott Kruger            fh.write(line+"\n")
70029921a8fSScott Kruger          fh.write("\n")
70129921a8fSScott Kruger        fh.write("\n")
70229921a8fSScott Kruger      fh.write("\n")
70329921a8fSScott Kruger    #fh.write("\nClass Sources\n"+str(self.sources)+"\n")
70429921a8fSScott Kruger    #fh.write("\nClass Tests\n"+str(self.tests)+"\n")
70529921a8fSScott Kruger    fh.close()
70629921a8fSScott Kruger    return
70729921a8fSScott Kruger
70829921a8fSScott Kruger  def genPetscTests(self,root,dirs,files,dataDict):
70929921a8fSScott Kruger    """
71029921a8fSScott Kruger     Go through and parse the source files in the directory to generate
71129921a8fSScott Kruger     the examples based on the metadata contained in the source files
71229921a8fSScott Kruger    """
71329921a8fSScott Kruger    debug=False
71429921a8fSScott Kruger    # Use examplesAnalyze to get what the makefles think are sources
71529921a8fSScott Kruger    #self.examplesAnalyze(root,dirs,files,anlzDict)
71629921a8fSScott Kruger
71729921a8fSScott Kruger    dataDict[root]={}
71829921a8fSScott Kruger
71929921a8fSScott Kruger    for exfile in files:
72029921a8fSScott Kruger      #TST: Until we replace files, still leaving the orginals as is
72129921a8fSScott Kruger      #if not exfile.startswith("new_"+"ex"): continue
72262197512SBarry Smith      #if not exfile.startswith("ex"): continue
72329921a8fSScott Kruger
72429921a8fSScott Kruger      # Convenience
72529921a8fSScott Kruger      fullex=os.path.join(root,exfile)
726*e551db17SScott Kruger      relpfile=os.path.join('src',os.path.relpath(fullex,self.srcdir))
72729921a8fSScott Kruger      if debug: print relpfile
72896d5c3b5SScott Kruger      dataDict[root].update(testparse.parseTestFile(fullex,0))
72929921a8fSScott Kruger      # Need to check and make sure tests are in the file
73029921a8fSScott Kruger      # if verbosity>=1: print relpfile
731862148f4SScott Kruger      if exfile in dataDict[root]:
73229921a8fSScott Kruger        self.genScriptsAndInfo(exfile,root,dataDict[root][exfile])
73329921a8fSScott Kruger
73429921a8fSScott Kruger    return
73529921a8fSScott Kruger
73629921a8fSScott Kruger  def walktree(self,top,action="printFiles"):
73729921a8fSScott Kruger    """
73829921a8fSScott Kruger    Walk a directory tree, starting from 'top'
73929921a8fSScott Kruger    """
74029921a8fSScott Kruger    #print "action", action
74129921a8fSScott Kruger    # Goal of action is to fill this dictionary
74229921a8fSScott Kruger    dataDict={}
74329921a8fSScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
74429921a8fSScott Kruger      if not "examples" in root: continue
74529921a8fSScott Kruger      if not os.path.isfile(os.path.join(root,"makefile")): continue
74629921a8fSScott Kruger      bname=os.path.basename(root.rstrip("/"))
74729921a8fSScott Kruger      if bname=="tests" or bname=="tutorials":
74829921a8fSScott Kruger        eval("self."+action+"(root,dirs,files,dataDict)")
74929921a8fSScott Kruger      if type(top) != types.StringType:
75029921a8fSScott Kruger          raise TypeError("top must be a string")
75129921a8fSScott Kruger    # Now summarize this dictionary
75229921a8fSScott Kruger    eval("self."+action+"_summarize(dataDict)")
75329921a8fSScott Kruger    return dataDict
75429921a8fSScott Kruger
755b0790570SJed Brown  def gen_gnumake(self, fd):
75629921a8fSScott Kruger    """
75729921a8fSScott Kruger     Overwrite of the method in the base PETSc class
75829921a8fSScott Kruger    """
75929921a8fSScott Kruger    def write(stem, srcs):
76029921a8fSScott Kruger      for lang in LANGS:
761*e551db17SScott Kruger        if self.inInstallDir:
762*e551db17SScott Kruger          if len(srcs[lang]['srcs'])>0:
763*e551db17SScott Kruger            fd.write('%(stem)s.%(lang)s := $(EXAMPLESDIR)/%(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' $(EXAMPLESDIR)/'.join(srcs[lang]['srcs'])))
764*e551db17SScott Kruger          else:
765*e551db17SScott Kruger            fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs'])))
766*e551db17SScott Kruger        else:
76729921a8fSScott Kruger          fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs'])))
76829921a8fSScott Kruger    for pkg in PKGS:
76929921a8fSScott Kruger        srcs = self.gen_pkg(pkg)
770b0790570SJed Brown        write('testsrcs-' + pkg, srcs)
77129921a8fSScott Kruger    return self.gendeps
77229921a8fSScott Kruger
77329921a8fSScott Kruger  def gen_pkg(self, pkg):
77429921a8fSScott Kruger    """
77529921a8fSScott Kruger     Overwrite of the method in the base PETSc class
77629921a8fSScott Kruger    """
77729921a8fSScott Kruger    return self.sources[pkg]
77829921a8fSScott Kruger
77929921a8fSScott Kruger  def write_gnumake(self,dataDict):
78029921a8fSScott Kruger    """
78129921a8fSScott Kruger     Write out something similar to files from gmakegen.py
78229921a8fSScott Kruger
78329921a8fSScott Kruger     Test depends on script which also depends on source
78429921a8fSScott Kruger     file, but since I don't have a good way generating
78529921a8fSScott Kruger     acting on a single file (oops) just depend on
78629921a8fSScott Kruger     executable which in turn will depend on src file
78729921a8fSScott Kruger    """
78868f6ad6bSScott Kruger    # Different options for how to set up the targets
78968f6ad6bSScott Kruger    compileExecsFirst=False
79068f6ad6bSScott Kruger
79129921a8fSScott Kruger    # Open file
792*e551db17SScott Kruger    arch_files = os.path.join(self.arch_dir,'lib','petsc','conf', 'testfiles')
79329921a8fSScott Kruger    fd = open(arch_files, 'w')
79429921a8fSScott Kruger
79529921a8fSScott Kruger    # Write out the sources
796b0790570SJed Brown    gendeps = self.gen_gnumake(fd)
79729921a8fSScott Kruger
79829921a8fSScott Kruger    # Write out the tests and execname targets
79929921a8fSScott Kruger    fd.write("\n#Tests and executables\n")    # Delimiter
80029921a8fSScott Kruger
80129921a8fSScott Kruger    for pkg in PKGS:
80229921a8fSScott Kruger      # These grab the ones that are built
80329921a8fSScott Kruger      for lang in LANGS:
80485a27222SJed Brown        testdeps=[]
80529921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
80629921a8fSScott Kruger          test=os.path.basename(ftest)
80729921a8fSScott Kruger          basedir=os.path.dirname(ftest)
80885a27222SJed Brown          testdeps.append(self.nameSpace(test,basedir))
809612eee3eSJed Brown        fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n")
81065ea9442SJed Brown        fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang))
81129921a8fSScott Kruger
81229921a8fSScott Kruger        # test targets
81329921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
81429921a8fSScott Kruger          test=os.path.basename(ftest)
81529921a8fSScott Kruger          basedir=os.path.dirname(ftest)
81629921a8fSScott Kruger          testdir="${TESTDIR}/"+basedir+"/"
81729921a8fSScott Kruger          nmtest=self.nameSpace(test,basedir)
81829921a8fSScott Kruger          rundir=os.path.join(testdir,test)
81929921a8fSScott Kruger          #print test, nmtest
82029921a8fSScott Kruger          script=test+".sh"
82129921a8fSScott Kruger
82229921a8fSScott Kruger          # Deps
82329921a8fSScott Kruger          exfile=self.tests[pkg][lang][ftest]['exfile']
824*e551db17SScott Kruger          fullex=os.path.join(os.path.dirname(self.srcdir),exfile)
82529921a8fSScott Kruger          localexec=self.tests[pkg][lang][ftest]['exec']
82629921a8fSScott Kruger          execname=os.path.join(testdir,localexec)
82768f6ad6bSScott Kruger          fullscript=os.path.join(testdir,script)
82868f6ad6bSScott Kruger          tmpfile=os.path.join(testdir,test,test+".tmp")
82929921a8fSScott Kruger
830b91d4a07SJed Brown          # *.counts depends on the script and either executable (will
831b91d4a07SJed Brown          # be run) or the example source file (SKIP or TODO)
832b91d4a07SJed Brown          fd.write('%s.counts : %s %s\n'
833b91d4a07SJed Brown                 % (os.path.join('$(TESTDIR)/counts', nmtest),
834b91d4a07SJed Brown                    fullscript,
835b91d4a07SJed Brown                    execname if exfile in self.sources[pkg][lang]['srcs'] else fullex))
83629921a8fSScott Kruger          # Now write the args:
837612eee3eSJed Brown          fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n")
838df2e1f37SScott Kruger
839612eee3eSJed Brown    fd.close()
84029921a8fSScott Kruger    return
84129921a8fSScott Kruger
84229921a8fSScott Kruger  def writeHarness(self,output,dataDict):
84329921a8fSScott Kruger    """
84429921a8fSScott Kruger     This is set up to write out multiple harness even if only gnumake
84529921a8fSScott Kruger     is supported now
84629921a8fSScott Kruger    """
84729921a8fSScott Kruger    eval("self.write_"+output+"(dataDict)")
84829921a8fSScott Kruger    return
84929921a8fSScott Kruger
850*e551db17SScott Krugerdef main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False, srcdir=None, testdir=None):
85129921a8fSScott Kruger    if output is None:
85229921a8fSScott Kruger        output = 'gnumake'
85329921a8fSScott Kruger
85429921a8fSScott Kruger
855*e551db17SScott Kruger    pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch,
856*e551db17SScott Kruger                         verbose=verbose, single_ex=single_ex, srcdir=srcdir,
857*e551db17SScott Kruger                         testdir=testdir)
858*e551db17SScott Kruger    dataDict=pEx.walktree(os.path.join(pEx.srcdir),action="genPetscTests")
85929921a8fSScott Kruger    pEx.writeHarness(output,dataDict)
86029921a8fSScott Kruger
86129921a8fSScott Krugerif __name__ == '__main__':
86229921a8fSScott Kruger    import optparse
86329921a8fSScott Kruger    parser = optparse.OptionParser()
86429921a8fSScott Kruger    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
86529921a8fSScott Kruger    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
866*e551db17SScott Kruger    parser.add_option('--srcdir', help='Set location of sources different from PETSC_DIR/src', default=None)
86729921a8fSScott Kruger    parser.add_option('--output', help='Location to write output file', default=None)
86829921a8fSScott Kruger    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')
869*e551db17SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',  help='Test directory: PETSC_DIR/PETSC_ARCH/testdir.  Default is "tests"')
870*e551db17SScott Kruger    opts, extra_args = parser.parse_args()
87129921a8fSScott Kruger    opts, extra_args = parser.parse_args()
87229921a8fSScott Kruger    if extra_args:
87329921a8fSScott Kruger        import sys
87429921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
87529921a8fSScott Kruger        exit(1)
876*e551db17SScott Kruger    main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose,
877*e551db17SScott Kruger         single_ex=opts.single_executable, srcdir=opts.srcdir, testdir=opts.testdir)
878