xref: /petsc/config/gmakegentest.py (revision 4ff3c6a13f545594ce0dbe7df03759119d8fd813)
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
19*4ff3c6a1SScott Kruger
20*4ff3c6a1SScott Kruger"""
21*4ff3c6a1SScott Kruger
22*4ff3c6a1SScott KrugerThere are 3 modes of running tests: Normal builds, test installs from builds,
23*4ff3c6a1SScott Krugertest installs from within install dir.  They affect where to find things:
24*4ff3c6a1SScott Kruger
25*4ff3c6a1SScott Kruger
26*4ff3c6a1SScott KrugerCase 1.  Normal builds:
27*4ff3c6a1SScott Kruger
28*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
29*4ff3c6a1SScott Kruger     | PETSC_DIR           | <git dir>                        |
30*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
31*4ff3c6a1SScott Kruger     | PETSC_ARCH          | arch-foo                         |
32*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
33*4ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib         |
34*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
35*4ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_DIR/src                    |
36*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
37*4ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests       |
38*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
39*4ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/gmakefile.test         |
40*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
41*4ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/config/gmakegentest.py |
42*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
43*4ff3c6a1SScott Kruger
44*4ff3c6a1SScott Kruger
45*4ff3c6a1SScott KrugerCase 2.  Test immediately after build through makefile & lib/petsc/conf/test:
46*4ff3c6a1SScott Kruger    (Not in installDir, but using prefix dir.  PETSC_ARCH='')
47*4ff3c6a1SScott Kruger
48*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
49*4ff3c6a1SScott Kruger     | PETSC_DIR           | <prefix dir>                     |
50*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
51*4ff3c6a1SScott Kruger     | PETSC_ARCH          | ''                               |
52*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
53*4ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib         |
54*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
55*4ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_SRC_DIR/src                |
56*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
57*4ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests       |
58*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
59*4ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/gmakefile.test         |
60*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
61*4ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/config/gmakegentest.py |
62*4ff3c6a1SScott Kruger     +---------------------+----------------------------------+
63*4ff3c6a1SScott Kruger
64*4ff3c6a1SScott KrugerCase 3.  From install dir:
65*4ff3c6a1SScott Kruger
66*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
67*4ff3c6a1SScott Kruger     | PETSC_DIR           | <prefix dir>                                          |
68*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
69*4ff3c6a1SScott Kruger     | PETSC_ARCH          | ''                                                    |
70*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
71*4ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib                              |
72*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
73*4ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_DIR/share/petsc/examples/src                    |
74*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
75*4ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests                            |
76*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
77*4ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/share/petsc/examples/gmakefile.test         |
78*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
79*4ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/share/petsc/examples/config/gmakegentest.py |
80*4ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
81*4ff3c6a1SScott Kruger
82*4ff3c6a1SScott Kruger"""
8329921a8fSScott Krugerclass generateExamples(Petsc):
8429921a8fSScott Kruger  """
8529921a8fSScott Kruger    gmakegen.py has basic structure for finding the files, writing out
8629921a8fSScott Kruger      the dependencies, etc.
8729921a8fSScott Kruger  """
88e551db17SScott Kruger  def __init__(self,petsc_dir=None, petsc_arch=None, testdir=None, verbose=False, single_ex=False, srcdir=None):
89e551db17SScott Kruger    super(generateExamples, self).__init__(petsc_dir, petsc_arch, verbose)
9029921a8fSScott Kruger
9129921a8fSScott Kruger    self.single_ex=single_ex
92e551db17SScott Kruger
93c173c275SScott Kruger    # Set locations to handle movement
94fc46264cSScott Kruger    self.inInstallDir=self.getInInstallDir(thisscriptdir)
95*4ff3c6a1SScott Kruger
96fc46264cSScott Kruger    if not self.inInstallDir:
97*4ff3c6a1SScott Kruger      if not petsc_arch == '':
98*4ff3c6a1SScott Kruger        # Case 1 discussed above
9929921a8fSScott Kruger        self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch)
100c173c275SScott Kruger        self.srcdir=os.path.join(self.petsc_dir,'src')
101e551db17SScott Kruger      else:
102*4ff3c6a1SScott Kruger        # Case 2 discussed above
103*4ff3c6a1SScott Kruger        self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch)
104*4ff3c6a1SScott Kruger        self.srcdir=os.path.join(os.path.dirname(thisscriptdir),'src')
105*4ff3c6a1SScott Kruger    else:
106*4ff3c6a1SScott Kruger      # Case 3 discussed above
107c173c275SScott Kruger      # set PETSC_ARCH to install directory to allow script to work in both
108c173c275SScott Kruger      dirlist=thisscriptdir.split(os.path.sep)
109c173c275SScott Kruger      installdir=os.path.sep.join(dirlist[0:len(dirlist)-4])
110e551db17SScott Kruger      self.arch_dir=installdir
111c173c275SScott Kruger      self.srcdir=os.path.join(os.path.dirname(thisscriptdir),'src')
112e551db17SScott Kruger
113e551db17SScott Kruger    # Do some initialization
114e551db17SScott Kruger    if testdir:
115e551db17SScott Kruger      # If full path given, then use it, otherwise assume relative to arch_dir
116c173c275SScott Kruger      if testdir.strip().startswith(os.path.sep):
117e551db17SScott Kruger        self.testroot_dir=testdir.strip()
118e551db17SScott Kruger      else:
119e551db17SScott Kruger        self.testroot_dir=os.path.join(self.arch_dir,testdir.strip())
120e551db17SScott Kruger    else:
121e551db17SScott Kruger      self.testroot_dir=os.path.join(self.arch_dir,"tests")
122e551db17SScott Kruger
12329921a8fSScott Kruger    self.ptNaming=True
124cadd188bSScott Kruger    self.verbose=verbose
12529921a8fSScott Kruger    # Whether to write out a useful debugging
126cadd188bSScott Kruger    self.summarize=True if verbose else False
12729921a8fSScott Kruger
12829921a8fSScott Kruger    # For help in setting the requirements
12912df5dc0SToby Isaac    self.precision_types="single double __float128 int32".split()
13029921a8fSScott Kruger    self.integer_types="int32 int64".split()
13129921a8fSScott Kruger    self.languages="fortran cuda cxx".split()    # Always requires C so do not list
13229921a8fSScott Kruger
13329921a8fSScott Kruger    # Things that are not test
13429921a8fSScott Kruger    self.buildkeys=testparse.buildkeys
13529921a8fSScott Kruger
13629921a8fSScott Kruger    # Adding a dictionary for storing sources, objects, and tests
13729921a8fSScott Kruger    # to make building the dependency tree easier
13829921a8fSScott Kruger    self.sources={}
13929921a8fSScott Kruger    self.objects={}
14029921a8fSScott Kruger    self.tests={}
14129921a8fSScott Kruger    for pkg in PKGS:
14229921a8fSScott Kruger      self.sources[pkg]={}
14329921a8fSScott Kruger      self.objects[pkg]=[]
14429921a8fSScott Kruger      self.tests[pkg]={}
14529921a8fSScott Kruger      for lang in LANGS:
14629921a8fSScott Kruger        self.sources[pkg][lang]={}
14729921a8fSScott Kruger        self.sources[pkg][lang]['srcs']=[]
14829921a8fSScott Kruger        self.tests[pkg][lang]={}
14929921a8fSScott Kruger
15029921a8fSScott Kruger    if not os.path.isdir(self.testroot_dir): os.makedirs(self.testroot_dir)
1510357d61fSScott Kruger
1520357d61fSScott Kruger    self.indent="   "
153cadd188bSScott Kruger    if self.verbose: print('Finishing the constructor')
15429921a8fSScott Kruger    return
15529921a8fSScott Kruger
156c173c275SScott Kruger  def srcrelpath(self,rdir):
157c173c275SScott Kruger    """
158c173c275SScott Kruger    Get relative path to source directory
159c173c275SScott Kruger    """
160c173c275SScott Kruger    return os.path.join('src',os.path.relpath(rdir,self.srcdir))
161c173c275SScott Kruger
162fc46264cSScott Kruger  def getInInstallDir(self,thisscriptdir):
163c173c275SScott Kruger    """
164c173c275SScott Kruger    When petsc is installed then this file in installed in:
165c173c275SScott Kruger         <PREFIX>/share/petsc/examples/config/gmakegentest.py
166c173c275SScott Kruger    otherwise the path is:
167c173c275SScott Kruger         <PETSC_DIR>/config/gmakegentest.py
168c173c275SScott Kruger    We use this difference to determine if we are in installdir
169c173c275SScott Kruger    """
170c173c275SScott Kruger    dirlist=thisscriptdir.split(os.path.sep)
171c173c275SScott Kruger    if len(dirlist)>4:
172c173c275SScott Kruger      lastfour=os.path.sep.join(dirlist[len(dirlist)-4:])
173c173c275SScott Kruger      if lastfour==os.path.join('share','petsc','examples','config'):
174c173c275SScott Kruger        return True
175c173c275SScott Kruger      else:
176c173c275SScott Kruger        return False
177c173c275SScott Kruger    else:
178c173c275SScott Kruger      return False
179c173c275SScott Kruger
18029921a8fSScott Kruger  def nameSpace(self,srcfile,srcdir):
18129921a8fSScott Kruger    """
18229921a8fSScott Kruger    Because the scripts have a non-unique naming, the pretty-printing
18329921a8fSScott Kruger    needs to convey the srcdir and srcfile.  There are two ways of doing this.
18429921a8fSScott Kruger    """
18529921a8fSScott Kruger    if self.ptNaming:
186886063b6SScott Kruger      if srcfile.startswith('run'): srcfile=re.sub('^run','',srcfile)
18729921a8fSScott Kruger      cdir=srcdir.split('src')[1].lstrip("/").rstrip("/")
18829921a8fSScott Kruger      prefix=cdir.replace('/examples/','_').replace("/","_")+"-"
18929921a8fSScott Kruger      nameString=prefix+srcfile
19029921a8fSScott Kruger    else:
19129921a8fSScott Kruger      #nameString=srcdir+": "+srcfile
19229921a8fSScott Kruger      nameString=srcfile
19329921a8fSScott Kruger    return nameString
19429921a8fSScott Kruger
19529921a8fSScott Kruger  def getLanguage(self,srcfile):
19629921a8fSScott Kruger    """
19729921a8fSScott Kruger    Based on the source, determine associated language as found in gmakegen.LANGS
19829921a8fSScott Kruger    Can we just return srcext[1:\] now?
19929921a8fSScott Kruger    """
20029921a8fSScott Kruger    langReq=None
20129921a8fSScott Kruger    srcext=os.path.splitext(srcfile)[-1]
20229921a8fSScott Kruger    if srcext in ".F90".split(): langReq="F90"
20329921a8fSScott Kruger    if srcext in ".F".split(): langReq="F"
20429921a8fSScott Kruger    if srcext in ".cxx".split(): langReq="cxx"
20529921a8fSScott Kruger    if srcext == ".cu": langReq="cu"
20629921a8fSScott Kruger    if srcext == ".c": langReq="c"
2070aac2865SBarry Smith    #if not langReq: print "ERROR: ", srcext, srcfile
20829921a8fSScott Kruger    return langReq
20929921a8fSScott Kruger
21096d5c3b5SScott Kruger  def _getLoopVars(self,inDict,testname, isSubtest=False):
211e9b06b45SScott Kruger    """
212e9b06b45SScott Kruger    Given: 'args: -bs {{1 2 3 4 5}} -pc_type {{cholesky sor}} -ksp_monitor'
213e9b06b45SScott Kruger    Return:
21496d5c3b5SScott Kruger      inDict['args']: -ksp_monitor
21596d5c3b5SScott Kruger      inDict['subargs']: -bs ${bs} -pc_type ${pc_type}
2160357d61fSScott Kruger      loopVars['subargs']['varlist']=['bs' 'pc_type']   # Don't worry about OrderedDict
2177827e0d6SScott Kruger      loopVars['subargs']['bs']=[["bs"],["1 2 3 4 5"]]
2187827e0d6SScott Kruger      loopVars['subargs']['pc_type']=[["pc_type"],["cholesky sor"]]
21996d5c3b5SScott Kruger    subst should be passed in instead of inDict
220e9b06b45SScott Kruger    """
2210357d61fSScott Kruger    loopVars={}; newargs=""
22296d5c3b5SScott Kruger    lkeys=inDict.keys()
22396d5c3b5SScott Kruger    lsuffix='_'
224aae9f2d9SScott Kruger    from testparse import parseLoopArgs
2250357d61fSScott Kruger    for key in lkeys:
22696d5c3b5SScott Kruger      if type(inDict[key])!=types.StringType: continue
22796d5c3b5SScott Kruger      keystr = str(inDict[key])
2280357d61fSScott Kruger      akey=('subargs' if key=='args' else key)  # what to assign
229862148f4SScott Kruger      if akey not in inDict: inDict[akey]=''
2300357d61fSScott Kruger      varlist=[]
231e9b06b45SScott Kruger      for varset in re.split('-(?=[a-zA-Z])',keystr):
232e9b06b45SScott Kruger        if not varset.strip(): continue
233aae9f2d9SScott Kruger        if '{{' in varset:
234aae9f2d9SScott Kruger          keyvar,lvars,ftype=parseLoopArgs(varset)
235862148f4SScott Kruger          if akey not in loopVars: loopVars[akey]={}
2367827e0d6SScott Kruger          varlist.append(keyvar)
2372521ea3cSScott Kruger          loopVars[akey][keyvar]=[keyvar,lvars]
2387827e0d6SScott Kruger          if akey=='nsize':
23996d5c3b5SScott Kruger            inDict[akey] = '${' + keyvar + '}'
24096d5c3b5SScott Kruger            lsuffix+=akey+'-'+inDict[akey]+'_'
2417827e0d6SScott Kruger          else:
24296d5c3b5SScott Kruger            inDict[akey] += ' -'+keyvar+' ${' + keyvar + '}'
24396d5c3b5SScott Kruger            lsuffix+=keyvar+'-${' + keyvar + '}_'
2447827e0d6SScott Kruger        else:
2457827e0d6SScott Kruger          if key=='args': newargs+=" -"+varset.strip()
246cadd188bSScott Kruger        if varlist: loopVars[akey]['varlist']=varlist
2478ba3acebSToby Isaac
2480357d61fSScott Kruger
2490357d61fSScott Kruger    # For subtests, args are always substituted in (not top level)
2500357d61fSScott Kruger    if isSubtest:
25196d5c3b5SScott Kruger      inDict['subargs']+=" "+newargs.strip()
25296d5c3b5SScott Kruger      inDict['args']=''
253862148f4SScott Kruger      if 'label_suffix' in inDict:
25496d5c3b5SScott Kruger        inDict['label_suffix']+=lsuffix.rstrip('_')
2550357d61fSScott Kruger      else:
25696d5c3b5SScott Kruger        inDict['label_suffix']=lsuffix.rstrip('_')
25796d5c3b5SScott Kruger    else:
258cadd188bSScott Kruger      if loopVars.keys():
25996d5c3b5SScott Kruger        inDict['args']=newargs.strip()
26096d5c3b5SScott Kruger        inDict['label_suffix']=lsuffix.rstrip('_')
261cadd188bSScott Kruger    if loopVars.keys():
262e9b06b45SScott Kruger      return loopVars
2630357d61fSScott Kruger    else:
2640357d61fSScott Kruger      return None
2658ba3acebSToby Isaac
26629921a8fSScott Kruger  def getArgLabel(self,testDict):
26729921a8fSScott Kruger    """
26829921a8fSScott Kruger    In all of the arguments in the test dictionary, create a simple
26929921a8fSScott Kruger    string for searching within the makefile system.  For simplicity in
27029921a8fSScott Kruger    search, remove "-", for strings, etc.
27129921a8fSScott Kruger    Also, concatenate the arg commands
27229921a8fSScott Kruger    For now, ignore nsize -- seems hard to search for anyway
27329921a8fSScott Kruger    """
27429921a8fSScott Kruger    # Collect all of the args associated with a test
275862148f4SScott Kruger    argStr=("" if 'args' not in testDict else testDict['args'])
276862148f4SScott Kruger    if 'subtests' in testDict:
27729921a8fSScott Kruger      for stest in testDict["subtests"]:
27829921a8fSScott Kruger         sd=testDict[stest]
279862148f4SScott Kruger         argStr=argStr+("" if 'args' not in sd else sd['args'])
28029921a8fSScott Kruger
28129921a8fSScott Kruger    # Now go through and cleanup
28229921a8fSScott Kruger    argStr=re.sub('{{(.*?)}}',"",argStr)
28329921a8fSScott Kruger    argStr=re.sub('-'," ",argStr)
28429921a8fSScott Kruger    for digit in string.digits: argStr=re.sub(digit," ",argStr)
28529921a8fSScott Kruger    argStr=re.sub("\.","",argStr)
28629921a8fSScott Kruger    argStr=re.sub(",","",argStr)
28729921a8fSScott Kruger    argStr=re.sub('\+',' ',argStr)
28829921a8fSScott Kruger    argStr=re.sub(' +',' ',argStr)  # Remove repeated white space
28929921a8fSScott Kruger    return argStr.strip()
29029921a8fSScott Kruger
29129921a8fSScott Kruger  def addToSources(self,exfile,root,srcDict):
29229921a8fSScott Kruger    """
29329921a8fSScott Kruger      Put into data structure that allows easy generation of makefile
29429921a8fSScott Kruger    """
295c173c275SScott Kruger    rpath=self.srcrelpath(root)
296c173c275SScott Kruger    pkg=rpath.split(os.path.sep)[1]
297e551db17SScott Kruger    relpfile=os.path.join(rpath,exfile)
29829921a8fSScott Kruger    lang=self.getLanguage(exfile)
2990aac2865SBarry Smith    if not lang: return
30029921a8fSScott Kruger    self.sources[pkg][lang]['srcs'].append(relpfile)
301fa9d32b8SSatish Balay    self.sources[pkg][lang][relpfile] = []
302862148f4SScott Kruger    if 'depends' in srcDict:
303fa9d32b8SSatish Balay      depSrcList=srcDict['depends'].split()
304fa9d32b8SSatish Balay      for depSrc in depSrcList:
30529921a8fSScott Kruger        depObj=os.path.splitext(depSrc)[0]+".o"
306fa9d32b8SSatish Balay        self.sources[pkg][lang][relpfile].append(os.path.join(rpath,depObj))
30729921a8fSScott Kruger
30829921a8fSScott Kruger    # In gmakefile, ${TESTDIR} var specifies the object compilation
309c173c275SScott Kruger    testsdir=self.srcrelpath(root)+"/"
31029921a8fSScott Kruger    objfile="${TESTDIR}/"+testsdir+os.path.splitext(exfile)[0]+".o"
31129921a8fSScott Kruger    self.objects[pkg].append(objfile)
31229921a8fSScott Kruger    return
31329921a8fSScott Kruger
31429921a8fSScott Kruger  def addToTests(self,test,root,exfile,execname,testDict):
31529921a8fSScott Kruger    """
31629921a8fSScott Kruger      Put into data structure that allows easy generation of makefile
31729921a8fSScott Kruger      Organized by languages to allow testing of languages
31829921a8fSScott Kruger    """
319c173c275SScott Kruger    rpath=self.srcrelpath(root)
320e551db17SScott Kruger    pkg=rpath.split("/")[1]
32129921a8fSScott Kruger    #nmtest=self.nameSpace(test,root)
32229921a8fSScott Kruger    nmtest=os.path.join(rpath,test)
32329921a8fSScott Kruger    lang=self.getLanguage(exfile)
3240aac2865SBarry Smith    if not lang: return
32529921a8fSScott Kruger    self.tests[pkg][lang][nmtest]={}
32629921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['exfile']=os.path.join(rpath,exfile)
32729921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['exec']=execname
32829921a8fSScott Kruger    self.tests[pkg][lang][nmtest]['argLabel']=self.getArgLabel(testDict)
32929921a8fSScott Kruger    return
33029921a8fSScott Kruger
33129921a8fSScott Kruger  def getExecname(self,exfile,root):
33229921a8fSScott Kruger    """
33329921a8fSScott Kruger      Generate bash script using template found next to this file.
33429921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
33529921a8fSScott Kruger    """
336c173c275SScott Kruger    rpath=self.srcrelpath(root)
33729921a8fSScott Kruger    if self.single_ex:
33829921a8fSScott Kruger      execname=rpath.split("/")[1]+"-ex"
33929921a8fSScott Kruger    else:
34029921a8fSScott Kruger      execname=os.path.splitext(exfile)[0]
34129921a8fSScott Kruger    return execname
34229921a8fSScott Kruger
34329921a8fSScott Kruger  def getSubstVars(self,testDict,rpath,testname):
34429921a8fSScott Kruger    """
34529921a8fSScott Kruger      Create a dictionary with all of the variables that get substituted
34629921a8fSScott Kruger      into the template commands found in example_template.py
34729921a8fSScott Kruger    """
34829921a8fSScott Kruger    subst={}
34996d5c3b5SScott Kruger
35096d5c3b5SScott Kruger    # Handle defaults of testparse.acceptedkeys (e.g., ignores subtests)
351862148f4SScott Kruger    if 'nsize' not in testDict: testDict['nsize']=1
3520a091e3eSScott Kruger    if 'timeoutfactor' not in testDict: testDict['timeoutfactor']="1"
35396d5c3b5SScott Kruger    for ak in testparse.acceptedkeys:
35496d5c3b5SScott Kruger      if ak=='test': continue
355862148f4SScott Kruger      subst[ak]=(testDict[ak] if ak in testDict else '')
35696d5c3b5SScott Kruger
35796d5c3b5SScott Kruger    # Now do other variables
35896d5c3b5SScott Kruger    subst['execname']=testDict['execname']
359862148f4SScott Kruger    if 'filter' in testDict:
36096d5c3b5SScott Kruger      subst['filter']="'"+testDict['filter']+"'"   # Quotes are tricky - overwrite
36168a9e459SScott Kruger
36296d5c3b5SScott Kruger    # Others
36396d5c3b5SScott Kruger    subst['subargs']=''  # Default.  For variables override
364e551db17SScott Kruger    subst['srcdir']=os.path.join(os.path.dirname(self.srcdir),rpath)
36568a9e459SScott Kruger    subst['label_suffix']=''
36696d5c3b5SScott Kruger    subst['comments']="\n#".join(subst['comments'].split("\n"))
36768a9e459SScott Kruger    if subst['comments']: subst['comments']="#"+subst['comments']
36896d5c3b5SScott Kruger    subst['exec']="../"+subst['execname']
36929921a8fSScott Kruger    subst['testroot']=self.testroot_dir
37029921a8fSScott Kruger    subst['testname']=testname
37109cf0baaSJed Brown    dp = self.conf.get('DATAFILESPATH','')
37209cf0baaSJed Brown    subst['datafilespath_line'] = 'DATAFILESPATH=${DATAFILESPATH:-"'+dp+'"}'
37329921a8fSScott Kruger
3740bcc1aabSScott Kruger    # This is used to label some matrices
3750bcc1aabSScott Kruger    subst['petsc_index_size']=str(self.conf['PETSC_INDEX_SIZE'])
3760bcc1aabSScott Kruger    subst['petsc_scalar_size']=str(self.conf['PETSC_SCALAR_SIZE'])
3770bcc1aabSScott Kruger
37829921a8fSScott Kruger    # These can have for loops and are treated separately later
37996d5c3b5SScott Kruger    subst['nsize']=str(subst['nsize'])
38029921a8fSScott Kruger
38129921a8fSScott Kruger    #Conf vars
38226646c0bSSatish Balay    if self.petsc_arch.find('valgrind')>=0:
38326646c0bSSatish Balay      subst['mpiexec']='petsc_mpiexec_valgrind ' + self.conf['MPIEXEC']
38426646c0bSSatish Balay    else:
38526646c0bSSatish Balay      subst['mpiexec']=self.conf['MPIEXEC']
3864c8d737cSSatish Balay    subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path
3870a091e3eSScott Kruger    subst['petsc_arch']=self.petsc_arch
388e551db17SScott Kruger    if not self.inInstallDir:
389*4ff3c6a1SScott Kruger      if not self.petsc_arch == '':
390*4ff3c6a1SScott Kruger        # Case 1
391e551db17SScott Kruger        subst['CONFIG_DIR']=os.path.join(self.petsc_dir,'config')
392c173c275SScott Kruger        subst['PETSC_BINDIR']=os.path.join(self.petsc_dir,'bin')
393e551db17SScott Kruger      else:
394*4ff3c6a1SScott Kruger        # Case 2
395*4ff3c6a1SScott Kruger        subst['CONFIG_DIR']=os.path.join(os.path.dirname(self.srcdir),'config')
396*4ff3c6a1SScott Kruger        subst['PETSC_BINDIR']=os.path.join(os.path.dirname(self.srcdir),'bin')
397*4ff3c6a1SScott Kruger    else:
398*4ff3c6a1SScott Kruger      # Case 3
399e551db17SScott Kruger      subst['CONFIG_DIR']=os.path.join(os.path.dirname(self.srcdir),'config')
400c173c275SScott Kruger      subst['PETSC_BINDIR']=os.path.join(self.petsc_dir,self.petsc_arch,'bin')
40129921a8fSScott Kruger    subst['diff']=self.conf['DIFF']
40229921a8fSScott Kruger    subst['rm']=self.conf['RM']
40329921a8fSScott Kruger    subst['grep']=self.conf['GREP']
404d6f00007SSatish Balay    subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR']
4050eb9b082SSatish Balay    subst['wpetsc_dir']=self.conf['wPETSC_DIR']
40629921a8fSScott Kruger
4073bcca444SScott Kruger    # Output file is special because of subtests override
4083bcca444SScott Kruger    defroot=(re.sub("run","",testname) if testname.startswith("run") else testname)
4093bcca444SScott Kruger    if not "_" in defroot: defroot=defroot+"_1"
4103bcca444SScott Kruger    subst['defroot']=defroot
4113bcca444SScott Kruger    subst['label']=self.nameSpace(defroot,subst['srcdir'])
4123bcca444SScott Kruger    subst['redirect_file']=defroot+".tmp"
413862148f4SScott Kruger    if 'output_file' not in testDict:
4143bcca444SScott Kruger      subst['output_file']="output/"+defroot+".out"
4153bcca444SScott Kruger    # Add in the full path here.
4163bcca444SScott Kruger    subst['output_file']=os.path.join(subst['srcdir'],subst['output_file'])
4173bcca444SScott Kruger    if not os.path.isfile(os.path.join(self.petsc_dir,subst['output_file'])):
4183bcca444SScott Kruger      if not subst['TODO']:
4193bcca444SScott Kruger        print "Warning: "+subst['output_file']+" not found."
4203bcca444SScott Kruger    # Worry about alt files here -- see
4213bcca444SScott Kruger    #   src/snes/examples/tutorials/output/ex22*.out
4223bcca444SScott Kruger    altlist=[subst['output_file']]
4239af0da4bSSatish Balay    basefile,ext = os.path.splitext(subst['output_file'])
424940ae1cbSBarry Smith    for i in range(1,9):
4259af0da4bSSatish Balay      altroot=basefile+"_alt"
426940ae1cbSBarry Smith      if i > 1: altroot=altroot+"_"+str(i)
4279af0da4bSSatish Balay      af=altroot+".out"
4283bcca444SScott Kruger      srcaf=os.path.join(subst['srcdir'],af)
4293bcca444SScott Kruger      fullaf=os.path.join(self.petsc_dir,srcaf)
4303bcca444SScott Kruger      if os.path.isfile(fullaf): altlist.append(srcaf)
4313bcca444SScott Kruger    if len(altlist)>1: subst['altfiles']=altlist
4323bcca444SScott Kruger    #if len(altlist)>1: print "Found alt files: ",altlist
4333bcca444SScott Kruger
43429921a8fSScott Kruger    return subst
43529921a8fSScott Kruger
4360357d61fSScott Kruger  def getCmds(self,subst,i):
43729921a8fSScott Kruger    """
43829921a8fSScott Kruger      Generate bash script using template found next to this file.
43929921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
44029921a8fSScott Kruger    """
4410357d61fSScott Kruger    nindnt=i # the start and has to be consistent with below
4427a853109SScott Kruger    cmdindnt=self.indent*nindnt
44329921a8fSScott Kruger    cmdLines=""
44468a9e459SScott Kruger
44529921a8fSScott Kruger    # MPI is the default -- but we have a few odd commands
44696d5c3b5SScott Kruger    if not subst['command']:
4477a853109SScott Kruger      cmd=cmdindnt+self._substVars(subst,example_template.mpitest)
44829921a8fSScott Kruger    else:
4497a853109SScott Kruger      cmd=cmdindnt+self._substVars(subst,example_template.commandtest)
4507a853109SScott Kruger    cmdLines+=cmd+"\n"+cmdindnt+"res=$?\n\n"
45129921a8fSScott Kruger
4527a853109SScott Kruger    cmdLines+=cmdindnt+'if test $res = 0; then\n'
4537a853109SScott Kruger    diffindnt=self.indent*(nindnt+1)
45464ca018dSScott Kruger    if not subst['filter_output']:
455862148f4SScott Kruger      if 'altfiles' not in subst:
4567a853109SScott Kruger        cmd=diffindnt+self._substVars(subst,example_template.difftest)
45764ca018dSScott Kruger      else:
4583bcca444SScott Kruger        # Have to do it by hand a bit because of variable number of alt files
4593bcca444SScott Kruger        rf=subst['redirect_file']
4607a853109SScott Kruger        cmd=diffindnt+example_template.difftest.split('@')[0]
4613bcca444SScott Kruger        for i in range(len(subst['altfiles'])):
4623bcca444SScott Kruger          af=subst['altfiles'][i]
463886063b6SScott Kruger          cmd+=af+' '+rf
4643bcca444SScott Kruger          if i!=len(subst['altfiles'])-1:
465886063b6SScott Kruger            cmd+=' > diff-${testname}-'+str(i)+'.out 2> diff-${testname}-'+str(i)+'.out'
466886063b6SScott Kruger            cmd+=' || ${diff_exe} '
4673bcca444SScott Kruger          else:
4683bcca444SScott Kruger            cmd+='" diff-${testname}.out diff-${testname}.out diff-${label}'
4693bcca444SScott Kruger            cmd+=subst['label_suffix']+' ""'  # Quotes are painful
4703bcca444SScott Kruger    else:
4717a853109SScott Kruger      cmd=diffindnt+self._substVars(subst,example_template.filterdifftest)
47268a9e459SScott Kruger    cmdLines+=cmd+"\n"
4737a853109SScott Kruger    cmdLines+=cmdindnt+'else\n'
4747a853109SScott Kruger    cmdLines+=diffindnt+'printf "ok ${label} # SKIP Command failed so no diff\\n"\n'
4757a853109SScott Kruger    cmdLines+=cmdindnt+'fi\n'
47629921a8fSScott Kruger    return cmdLines
47729921a8fSScott Kruger
47829921a8fSScott Kruger  def _substVars(self,subst,origStr):
47929921a8fSScott Kruger    """
4807827e0d6SScott Kruger      Substitute variables
48129921a8fSScott Kruger    """
48229921a8fSScott Kruger    Str=origStr
48329921a8fSScott Kruger    for subkey in subst:
48429921a8fSScott Kruger      if type(subst[subkey])!=types.StringType: continue
48529921a8fSScott Kruger      patt="@"+subkey.upper()+"@"
48629921a8fSScott Kruger      Str=re.sub(patt,subst[subkey],Str)
48729921a8fSScott Kruger    return Str
48829921a8fSScott Kruger
48909cf0baaSJed Brown  def _writeTodoSkip(self,fh,tors,reasons,footer):
49068a9e459SScott Kruger    """
49168a9e459SScott Kruger    Write out the TODO and SKIP lines in the file
49268a9e459SScott Kruger    The TODO or SKIP variable, tors, should be lower case
49368a9e459SScott Kruger    """
49468a9e459SScott Kruger    TORS=tors.upper()
49568a9e459SScott Kruger    template=eval("example_template."+tors+"line")
49609cf0baaSJed Brown    tsStr=re.sub("@"+TORS+"COMMENT@",', '.join(reasons),template)
49709cf0baaSJed Brown    tab = ''
4982f2809e3SToby Isaac    if reasons:
4992f2809e3SToby Isaac      fh.write('if ! $force; then\n')
5002f2809e3SToby Isaac      tab = tab + '    '
50109cf0baaSJed Brown    if reasons == ["Requires DATAFILESPATH"]:
50209cf0baaSJed Brown      # The only reason not to run is DATAFILESPATH, which we check at run-time
5032f2809e3SToby Isaac      fh.write(tab + 'if test -z "${DATAFILESPATH}"; then\n')
5042f2809e3SToby Isaac      tab = tab + '    '
50509cf0baaSJed Brown    if reasons:
5062f2809e3SToby Isaac      fh.write(tab+tsStr+"\n" + tab + "total=1; "+tors+"=1\n")
50709cf0baaSJed Brown      fh.write(tab+footer+"\n")
50809cf0baaSJed Brown      fh.write(tab+"exit\n")
50909cf0baaSJed Brown    if reasons == ["Requires DATAFILESPATH"]:
51009cf0baaSJed Brown      fh.write('    fi\n')
5112f2809e3SToby Isaac    if reasons:
5122f2809e3SToby Isaac      fh.write('fi\n')
51309cf0baaSJed Brown    fh.write('\n\n')
51468a9e459SScott Kruger    return
51568a9e459SScott Kruger
5168ba3acebSToby Isaac  def getLoopVarsHead(self,loopVars,i):
5170357d61fSScott Kruger    """
5180357d61fSScott Kruger    Generate a nicely indented string with the format loops
5190357d61fSScott Kruger    Here is what the data structure looks like
5200357d61fSScott Kruger      loopVars['subargs']['varlist']=['bs' 'pc_type']   # Don't worry about OrderedDict
5210357d61fSScott Kruger      loopVars['subargs']['bs']=["i","1 2 3 4 5"]
5220357d61fSScott Kruger      loopVars['subargs']['pc_type']=["j","cholesky sor"]
5230357d61fSScott Kruger    """
5240357d61fSScott Kruger    outstr=''; indnt=self.indent
5258ba3acebSToby Isaac    for key in loopVars:
5260357d61fSScott Kruger      for var in loopVars[key]['varlist']:
5270357d61fSScott Kruger        varval=loopVars[key][var]
5280357d61fSScott Kruger        outstr += indnt * i + "for "+varval[0]+" in "+varval[1]+"; do\n"
5298ba3acebSToby Isaac        i = i + 1
5308ba3acebSToby Isaac    return (outstr,i)
5318ba3acebSToby Isaac
5328ba3acebSToby Isaac  def getLoopVarsFoot(self,loopVars,i):
5330357d61fSScott Kruger    outstr=''; indnt=self.indent
5348ba3acebSToby Isaac    for key in loopVars:
5350357d61fSScott Kruger      for var in loopVars[key]['varlist']:
5368ba3acebSToby Isaac        i = i - 1
5370357d61fSScott Kruger        outstr += indnt * i + "done\n"
5388ba3acebSToby Isaac    return (outstr,i)
5398ba3acebSToby Isaac
54029921a8fSScott Kruger  def genRunScript(self,testname,root,isRun,srcDict):
54129921a8fSScott Kruger    """
54229921a8fSScott Kruger      Generate bash script using template found next to this file.
54329921a8fSScott Kruger      This file is read in at constructor time to avoid file I/O
54429921a8fSScott Kruger    """
54529921a8fSScott Kruger    # runscript_dir directory has to be consistent with gmakefile
54629921a8fSScott Kruger    testDict=srcDict[testname]
547c173c275SScott Kruger    rpath=self.srcrelpath(root)
54829921a8fSScott Kruger    runscript_dir=os.path.join(self.testroot_dir,rpath)
54929921a8fSScott Kruger    if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir)
55029921a8fSScott Kruger    fh=open(os.path.join(runscript_dir,testname+".sh"),"w")
55129921a8fSScott Kruger
55296d5c3b5SScott Kruger    # Get variables to go into shell scripts.  last time testDict used
55329921a8fSScott Kruger    subst=self.getSubstVars(testDict,rpath,testname)
55496d5c3b5SScott Kruger    loopVars = self._getLoopVars(subst,testname)  # Alters subst as well
55596d5c3b5SScott Kruger    #if '33_' in testname: print subst['subargs']
55629921a8fSScott Kruger
55764ca018dSScott Kruger    #Handle runfiles
558862148f4SScott Kruger    for lfile in subst.get('localrunfiles','').split():
559e551db17SScott Kruger      fullfile=os.path.join(root,lfile)
56001ad06ccSBarry Smith      if os.path.isdir(fullfile):
56101ad06ccSBarry Smith        if not os.path.isdir(os.path.join(runscript_dir,lfile)):
56201ad06ccSBarry Smith          shutil.copytree(fullfile,os.path.join(runscript_dir,lfile))
56301ad06ccSBarry Smith      else:
56464ca018dSScott Kruger        shutil.copy(fullfile,runscript_dir)
56564ca018dSScott Kruger    # Check subtests for local runfiles
566862148f4SScott Kruger    for stest in subst.get("subtests",[]):
567862148f4SScott Kruger      for lfile in testDict[stest].get('localrunfiles','').split():
568e551db17SScott Kruger        fullfile=os.path.join(root,lfile)
56901ad06ccSBarry Smith        if os.path.isdir(fullfile):
57001ad06ccSBarry Smith          if not os.path.isdir(os.path.join(runscript_dir,lfile)):
57101ad06ccSBarry Smith            shutil.copytree(fullfile,os.path.join(runscript_dir,lfile))
57201ad06ccSBarry Smith        else:
57364ca018dSScott Kruger          shutil.copy(fullfile,self.runscript_dir)
57464ca018dSScott Kruger
57529921a8fSScott Kruger    # Now substitute the key variables into the header and footer
57629921a8fSScott Kruger    header=self._substVars(subst,example_template.header)
5770bcc1aabSScott Kruger    # The header is done twice to enable @...@ in header
5780bcc1aabSScott Kruger    header=self._substVars(subst,header)
5795e7f8670SScott Kruger    footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer)
58029921a8fSScott Kruger
58129921a8fSScott Kruger    # Start writing the file
58229921a8fSScott Kruger    fh.write(header+"\n")
58329921a8fSScott Kruger
58429921a8fSScott Kruger    # If there is a TODO or a SKIP then we do it before writing out the
58529921a8fSScott Kruger    # rest of the command (which is useful for working on the test)
58629921a8fSScott Kruger    # SKIP and TODO can be for the source file or for the runs
58709cf0baaSJed Brown    self._writeTodoSkip(fh,'todo',[s for s in [srcDict.get('TODO',''), testDict.get('TODO','')] if s],footer)
58809cf0baaSJed Brown    self._writeTodoSkip(fh,'skip',srcDict.get('SKIP',[]) + testDict.get('SKIP',[]),footer)
58929921a8fSScott Kruger
59029921a8fSScott Kruger    j=0  # for indentation
59129921a8fSScott Kruger
5920357d61fSScott Kruger    if loopVars:
5938ba3acebSToby Isaac      (loopHead,j) = self.getLoopVarsHead(loopVars,j)
5948ba3acebSToby Isaac      if (loopHead): fh.write(loopHead+"\n")
59529921a8fSScott Kruger
59629921a8fSScott Kruger    # Subtests are special
597862148f4SScott Kruger    if 'subtests' in testDict:
59829921a8fSScott Kruger      substP=subst   # Subtests can inherit args but be careful
5994fedfc52SScott Kruger      k=0  # for label suffixes
60029921a8fSScott Kruger      for stest in testDict["subtests"]:
6011e4ea733SToby Isaac        subst=substP.copy()
6020357d61fSScott Kruger        subst.update(testDict[stest])
6034fedfc52SScott Kruger        # nsize is special because it is usually overwritten
6044fedfc52SScott Kruger        if 'nsize' in testDict[stest]:
6054fedfc52SScott Kruger          fh.write("nsize="+str(testDict[stest]['nsize'])+"\n")
6067ddf018aSSatish Balay        else:
6077ddf018aSSatish Balay          fh.write("nsize=1\n")
6084fedfc52SScott Kruger        subst['label_suffix']='-'+string.ascii_letters[k]; k+=1
6097827e0d6SScott Kruger        sLoopVars = self._getLoopVars(subst,testname,isSubtest=True)
6107827e0d6SScott Kruger        #if '10_9' in testname: print sLoopVars
6110357d61fSScott Kruger        if sLoopVars:
6128ba3acebSToby Isaac          (sLoopHead,j) = self.getLoopVarsHead(sLoopVars,j)
6130357d61fSScott Kruger          fh.write(sLoopHead+"\n")
6140357d61fSScott Kruger        fh.write(self.getCmds(subst,j)+"\n")
6150357d61fSScott Kruger        if sLoopVars:
6168ba3acebSToby Isaac          (sLoopFoot,j) = self.getLoopVarsFoot(sLoopVars,j)
6170357d61fSScott Kruger          fh.write(sLoopFoot+"\n")
61829921a8fSScott Kruger    else:
61929921a8fSScott Kruger      fh.write(self.getCmds(subst,j)+"\n")
6208ba3acebSToby Isaac
6210357d61fSScott Kruger    if loopVars:
6228ba3acebSToby Isaac      (loopFoot,j) = self.getLoopVarsFoot(loopVars,j)
6230357d61fSScott Kruger      fh.write(loopFoot+"\n")
62429921a8fSScott Kruger
62529921a8fSScott Kruger    fh.write(footer+"\n")
626b181ea86SSatish Balay    os.chmod(os.path.join(runscript_dir,testname+".sh"),0755)
6277827e0d6SScott Kruger    #if '10_9' in testname: sys.exit()
62829921a8fSScott Kruger    return
62929921a8fSScott Kruger
63029921a8fSScott Kruger  def  genScriptsAndInfo(self,exfile,root,srcDict):
63129921a8fSScott Kruger    """
63229921a8fSScott Kruger    Generate scripts from the source file, determine if built, etc.
63329921a8fSScott Kruger     For every test in the exfile with info in the srcDict:
63429921a8fSScott Kruger      1. Determine if it needs to be run for this arch
63529921a8fSScott Kruger      2. Generate the script
63629921a8fSScott Kruger      3. Generate the data needed to write out the makefile in a
63729921a8fSScott Kruger         convenient way
63829921a8fSScott Kruger     All tests are *always* run, but some may be SKIP'd per the TAP standard
63929921a8fSScott Kruger    """
64029921a8fSScott Kruger    debug=False
64129921a8fSScott Kruger    execname=self.getExecname(exfile,root)
64229921a8fSScott Kruger    isBuilt=self._isBuilt(exfile,srcDict)
64329921a8fSScott Kruger    for test in srcDict:
64429921a8fSScott Kruger      if test in self.buildkeys: continue
64529921a8fSScott Kruger      if debug: print self.nameSpace(exfile,root), test
64629921a8fSScott Kruger      srcDict[test]['execname']=execname   # Convenience in generating scripts
64729921a8fSScott Kruger      isRun=self._isRun(srcDict[test])
64829921a8fSScott Kruger      self.genRunScript(test,root,isRun,srcDict)
64929921a8fSScott Kruger      srcDict[test]['isrun']=isRun
65029921a8fSScott Kruger      self.addToTests(test,root,exfile,execname,srcDict[test])
65129921a8fSScott Kruger
65229921a8fSScott Kruger    # This adds to datastructure for building deps
653a8eb4092SScott Kruger    if isBuilt: self.addToSources(exfile,root,srcDict)
65429921a8fSScott Kruger    return
65529921a8fSScott Kruger
65629921a8fSScott Kruger  def _isBuilt(self,exfile,srcDict):
65729921a8fSScott Kruger    """
65829921a8fSScott Kruger    Determine if this file should be built.
65929921a8fSScott Kruger    """
66029921a8fSScott Kruger    # Get the language based on file extension
66109cf0baaSJed Brown    srcDict['SKIP'] = []
66229921a8fSScott Kruger    lang=self.getLanguage(exfile)
663c2426ab2SScott Kruger    if (lang=="F" or lang=="F90"):
664c2426ab2SScott Kruger      if not self.have_fortran:
66509cf0baaSJed Brown        srcDict["SKIP"].append("Fortran required for this test")
666c2426ab2SScott Kruger      elif lang=="F90" and 'PETSC_USING_F90FREEFORM' not in self.conf:
667c2426ab2SScott Kruger        srcDict["SKIP"].append("Fortran f90freeform required for this test")
668862148f4SScott Kruger    if lang=="cu" and 'PETSC_HAVE_CUDA' not in self.conf:
66909cf0baaSJed Brown      srcDict["SKIP"].append("CUDA required for this test")
670862148f4SScott Kruger    if lang=="cxx" and 'PETSC_HAVE_CXX' not in self.conf:
67109cf0baaSJed Brown      srcDict["SKIP"].append("C++ required for this test")
67229921a8fSScott Kruger
67329921a8fSScott Kruger    # Deprecated source files
67409cf0baaSJed Brown    if srcDict.get("TODO"):
67509cf0baaSJed Brown      return False
67629921a8fSScott Kruger
67729921a8fSScott Kruger    # isRun can work with srcDict to handle the requires
678862148f4SScott Kruger    if "requires" in srcDict:
679cadd188bSScott Kruger      if srcDict["requires"]:
68029921a8fSScott Kruger        return self._isRun(srcDict)
68129921a8fSScott Kruger
68209cf0baaSJed Brown    return srcDict['SKIP'] == []
68329921a8fSScott Kruger
68429921a8fSScott Kruger
685e4653983SScott Kruger  def _isRun(self,testDict, debug=False):
68629921a8fSScott Kruger    """
68729921a8fSScott Kruger    Based on the requirements listed in the src file and the petscconf.h
68829921a8fSScott Kruger    info, determine whether this test should be run or not.
68929921a8fSScott Kruger    """
69029921a8fSScott Kruger    indent="  "
69129921a8fSScott Kruger
69209cf0baaSJed Brown    if 'SKIP' not in testDict:
69309cf0baaSJed Brown      testDict['SKIP'] = []
69429921a8fSScott Kruger    # MPI requirements
695862148f4SScott Kruger    if testDict.get('nsize',1)>1 and 'MPI_IS_MPIUNI' in self.conf:
69629921a8fSScott Kruger      if debug: print indent+"Cannot run parallel tests"
69709cf0baaSJed Brown      testDict['SKIP'].append("Parallel test with serial build")
69829921a8fSScott Kruger
69929921a8fSScott Kruger    # The requirements for the test are the sum of all the run subtests
700862148f4SScott Kruger    if 'subtests' in testDict:
701862148f4SScott Kruger      if 'requires' not in testDict: testDict['requires']=""
70229921a8fSScott Kruger      for stest in testDict['subtests']:
703862148f4SScott Kruger        if 'requires' in testDict[stest]:
704862148f4SScott Kruger          testDict['requires']+=" "+testDict[stest]['requires']
70529921a8fSScott Kruger
70629921a8fSScott Kruger
70729921a8fSScott Kruger    # Now go through all requirements
708862148f4SScott Kruger    if 'requires' in testDict:
70929921a8fSScott Kruger      for requirement in testDict['requires'].split():
71029921a8fSScott Kruger        requirement=requirement.strip()
71129921a8fSScott Kruger        if not requirement: continue
71229921a8fSScott Kruger        if debug: print indent+"Requirement: ", requirement
71329921a8fSScott Kruger        isNull=False
71429921a8fSScott Kruger        if requirement.startswith("!"):
71529921a8fSScott Kruger          requirement=requirement[1:]; isNull=True
71629921a8fSScott Kruger        # Precision requirement for reals
71729921a8fSScott Kruger        if requirement in self.precision_types:
71829921a8fSScott Kruger          if self.conf['PETSC_PRECISION']==requirement:
71909cf0baaSJed Brown            if isNull:
72009cf0baaSJed Brown              testDict['SKIP'].append("not "+requirement+" required")
72109cf0baaSJed Brown              continue
7224bb4d03dSScott Kruger            continue  # Success
72309cf0baaSJed Brown          elif not isNull:
72409cf0baaSJed Brown            testDict['SKIP'].append(requirement+" required")
72509cf0baaSJed Brown            continue
72629921a8fSScott Kruger        # Precision requirement for ints
72729921a8fSScott Kruger        if requirement in self.integer_types:
72829921a8fSScott Kruger          if requirement=="int32":
72929921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==4:
73009cf0baaSJed Brown              if isNull:
73109cf0baaSJed Brown                testDict['SKIP'].append("not int32 required")
73209cf0baaSJed Brown                continue
7334bb4d03dSScott Kruger              continue  # Success
73409cf0baaSJed Brown            elif not isNull:
73509cf0baaSJed Brown              testDict['SKIP'].append("int32 required")
73609cf0baaSJed Brown              continue
73729921a8fSScott Kruger          if requirement=="int64":
73829921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==8:
73909cf0baaSJed Brown              if isNull:
74009cf0baaSJed Brown                testDict['SKIP'].append("NOT int64 required")
74109cf0baaSJed Brown                continue
7424bb4d03dSScott Kruger              continue  # Success
74309cf0baaSJed Brown            elif not isNull:
74409cf0baaSJed Brown              testDict['SKIP'].append("int64 required")
74509cf0baaSJed Brown              continue
74629921a8fSScott Kruger        # Datafilespath
74709cf0baaSJed Brown        if requirement=="datafilespath" and not isNull:
74809cf0baaSJed Brown          testDict['SKIP'].append("Requires DATAFILESPATH")
74909cf0baaSJed Brown          continue
75029921a8fSScott Kruger        # Defines -- not sure I have comments matching
7518304fa3fSScott Kruger        if "define(" in requirement.lower():
75229921a8fSScott Kruger          reqdef=requirement.split("(")[1].split(")")[0]
75309cf0baaSJed Brown          if reqdef in self.conf:
75429921a8fSScott Kruger            if isNull:
75509cf0baaSJed Brown              testDict['SKIP'].append("Null requirement not met: "+requirement)
75609cf0baaSJed Brown              continue
7574bb4d03dSScott Kruger            continue  # Success
7584bb4d03dSScott Kruger          elif not isNull:
75909cf0baaSJed Brown            testDict['SKIP'].append("Required: "+requirement)
76009cf0baaSJed Brown            continue
76129921a8fSScott Kruger
76229921a8fSScott Kruger        # Rest should be packages that we can just get from conf
76309cf0baaSJed Brown        if requirement == "complex":
76409cf0baaSJed Brown          petscconfvar="PETSC_USE_COMPLEX"
76509cf0baaSJed Brown        else:
76609cf0baaSJed Brown          petscconfvar="PETSC_HAVE_"+requirement.upper()
76729921a8fSScott Kruger        if self.conf.get(petscconfvar):
76829921a8fSScott Kruger          if isNull:
76909cf0baaSJed Brown            testDict['SKIP'].append("Not "+petscconfvar+" requirement not met")
77009cf0baaSJed Brown            continue
7714bb4d03dSScott Kruger          continue  # Success
772df3aec83SJed Brown        elif not isNull:
77329921a8fSScott Kruger          if debug: print "requirement not found: ", requirement
77409cf0baaSJed Brown          testDict['SKIP'].append(petscconfvar+" requirement not met")
77509cf0baaSJed Brown          continue
77629921a8fSScott Kruger
77709cf0baaSJed Brown    return testDict['SKIP'] == []
77829921a8fSScott Kruger
77929921a8fSScott Kruger  def genPetscTests_summarize(self,dataDict):
78029921a8fSScott Kruger    """
78129921a8fSScott Kruger    Required method to state what happened
78229921a8fSScott Kruger    """
78329921a8fSScott Kruger    if not self.summarize: return
78429921a8fSScott Kruger    indent="   "
785cfaa06beSSatish Balay    fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt')
78629921a8fSScott Kruger    fh=open(fhname,"w")
78764ca018dSScott Kruger    #print "See ", fhname
78829921a8fSScott Kruger    for root in dataDict:
789c173c275SScott Kruger      relroot=self.srcrelpath(root)
79029921a8fSScott Kruger      pkg=relroot.split("/")[1]
79129921a8fSScott Kruger      fh.write(relroot+"\n")
79229921a8fSScott Kruger      allSrcs=[]
793e551db17SScott Kruger      for lang in LANGS: allSrcs+=self.sources[pkg][lang]['srcs']
79429921a8fSScott Kruger      for exfile in dataDict[root]:
79529921a8fSScott Kruger        # Basic  information
796c173c275SScott Kruger        rfile=os.path.join(relroot,exfile)
79729921a8fSScott Kruger        builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built")
79829921a8fSScott Kruger        fh.write(indent+exfile+indent*4+builtStatus+"\n")
79929921a8fSScott Kruger
80029921a8fSScott Kruger        for test in dataDict[root][exfile]:
80129921a8fSScott Kruger          if test in self.buildkeys: continue
80229921a8fSScott Kruger          line=indent*2+test
80329921a8fSScott Kruger          fh.write(line+"\n")
80429921a8fSScott Kruger          # Looks nice to have the keys in order
80529921a8fSScott Kruger          #for key in dataDict[root][exfile][test]:
80629921a8fSScott Kruger          for key in "isrun abstracted nsize args requires script".split():
807862148f4SScott Kruger            if key not in dataDict[root][exfile][test]: continue
80829921a8fSScott Kruger            line=indent*3+key+": "+str(dataDict[root][exfile][test][key])
80929921a8fSScott Kruger            fh.write(line+"\n")
81029921a8fSScott Kruger          fh.write("\n")
81129921a8fSScott Kruger        fh.write("\n")
81229921a8fSScott Kruger      fh.write("\n")
81329921a8fSScott Kruger    #fh.write("\nClass Sources\n"+str(self.sources)+"\n")
81429921a8fSScott Kruger    #fh.write("\nClass Tests\n"+str(self.tests)+"\n")
81529921a8fSScott Kruger    fh.close()
81629921a8fSScott Kruger    return
81729921a8fSScott Kruger
81829921a8fSScott Kruger  def genPetscTests(self,root,dirs,files,dataDict):
81929921a8fSScott Kruger    """
82029921a8fSScott Kruger     Go through and parse the source files in the directory to generate
82129921a8fSScott Kruger     the examples based on the metadata contained in the source files
82229921a8fSScott Kruger    """
82329921a8fSScott Kruger    debug=False
82429921a8fSScott Kruger    # Use examplesAnalyze to get what the makefles think are sources
82529921a8fSScott Kruger    #self.examplesAnalyze(root,dirs,files,anlzDict)
82629921a8fSScott Kruger
82729921a8fSScott Kruger    dataDict[root]={}
82829921a8fSScott Kruger
82929921a8fSScott Kruger    for exfile in files:
83029921a8fSScott Kruger      #TST: Until we replace files, still leaving the orginals as is
83129921a8fSScott Kruger      #if not exfile.startswith("new_"+"ex"): continue
83262197512SBarry Smith      #if not exfile.startswith("ex"): continue
83329921a8fSScott Kruger
834e4653983SScott Kruger      # Ignore emacs and other temporary files
835e4653983SScott Kruger      if exfile.startswith("."): continue
836e4653983SScott Kruger      if exfile.startswith("#"): continue
83713ddbc6dSScott Kruger
83829921a8fSScott Kruger      # Convenience
83929921a8fSScott Kruger      fullex=os.path.join(root,exfile)
840cadd188bSScott Kruger      if self.verbose: print('   --> '+fullex)
84196d5c3b5SScott Kruger      dataDict[root].update(testparse.parseTestFile(fullex,0))
842862148f4SScott Kruger      if exfile in dataDict[root]:
84329921a8fSScott Kruger        self.genScriptsAndInfo(exfile,root,dataDict[root][exfile])
84429921a8fSScott Kruger
84529921a8fSScott Kruger    return
84629921a8fSScott Kruger
847cadd188bSScott Kruger  def walktree(self,top):
84829921a8fSScott Kruger    """
84929921a8fSScott Kruger    Walk a directory tree, starting from 'top'
85029921a8fSScott Kruger    """
85129921a8fSScott Kruger    #print "action", action
85229921a8fSScott Kruger    # Goal of action is to fill this dictionary
85329921a8fSScott Kruger    dataDict={}
854f98eef70SScott Kruger    for root, dirs, files in os.walk(top, topdown=True):
85529921a8fSScott Kruger      if not "examples" in root: continue
856f98eef70SScott Kruger      if "dSYM" in root: continue
857f98eef70SScott Kruger      if os.path.basename(root.rstrip("/")) == 'output': continue
858cadd188bSScott Kruger      if self.verbose: print(root)
859b6d69c80SScott Kruger      self.genPetscTests(root,dirs,files,dataDict)
86029921a8fSScott Kruger    # Now summarize this dictionary
861cadd188bSScott Kruger    self.genPetscTests_summarize(dataDict)
86229921a8fSScott Kruger    return dataDict
86329921a8fSScott Kruger
864b0790570SJed Brown  def gen_gnumake(self, fd):
86529921a8fSScott Kruger    """
86629921a8fSScott Kruger     Overwrite of the method in the base PETSc class
86729921a8fSScott Kruger    """
86829921a8fSScott Kruger    def write(stem, srcs):
86929921a8fSScott Kruger      for lang in LANGS:
8702ae8c56aSScott Kruger        if srcs[lang]['srcs']:
87129921a8fSScott Kruger          fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs'])))
87229921a8fSScott Kruger    for pkg in PKGS:
87329921a8fSScott Kruger        srcs = self.gen_pkg(pkg)
874b0790570SJed Brown        write('testsrcs-' + pkg, srcs)
8752ae8c56aSScott Kruger        # Handle dependencies
8762ae8c56aSScott Kruger        for lang in LANGS:
8772ae8c56aSScott Kruger            for exfile in srcs[lang]['srcs']:
8782ae8c56aSScott Kruger                if exfile in srcs[lang]:
8792ae8c56aSScott Kruger                    ex='$(TESTDIR)/'+os.path.splitext(exfile)[0]
8802ae8c56aSScott Kruger                    exfo='$(TESTDIR)/'+os.path.splitext(exfile)[0]+'.o'
88149defe6fSJed Brown                    deps = [os.path.join('$(TESTDIR)', dep) for dep in srcs[lang][exfile]]
88249defe6fSJed Brown                    if deps:
88349defe6fSJed Brown                        # The executable literally depends on the object file because it is linked
88449defe6fSJed Brown                        fd.write(ex   +": " + " ".join(deps) +'\n')
88549defe6fSJed Brown                        # The object file containing 'main' does not normally depend on other object
88649defe6fSJed Brown                        # files, but it does when it includes their modules.  This dependency is
88749defe6fSJed Brown                        # overly blunt and could be reduced to only depend on object files for
88849defe6fSJed Brown                        # modules that are used, like "*f90aux.o".
88949defe6fSJed Brown                        fd.write(exfo +": " + " ".join(deps) +'\n')
8902ae8c56aSScott Kruger
89129921a8fSScott Kruger    return self.gendeps
89229921a8fSScott Kruger
89329921a8fSScott Kruger  def gen_pkg(self, pkg):
89429921a8fSScott Kruger    """
89529921a8fSScott Kruger     Overwrite of the method in the base PETSc class
89629921a8fSScott Kruger    """
89729921a8fSScott Kruger    return self.sources[pkg]
89829921a8fSScott Kruger
89929921a8fSScott Kruger  def write_gnumake(self,dataDict):
90029921a8fSScott Kruger    """
90129921a8fSScott Kruger     Write out something similar to files from gmakegen.py
90229921a8fSScott Kruger
90329921a8fSScott Kruger     Test depends on script which also depends on source
90429921a8fSScott Kruger     file, but since I don't have a good way generating
90529921a8fSScott Kruger     acting on a single file (oops) just depend on
90629921a8fSScott Kruger     executable which in turn will depend on src file
90729921a8fSScott Kruger    """
90868f6ad6bSScott Kruger    # Different options for how to set up the targets
90968f6ad6bSScott Kruger    compileExecsFirst=False
91068f6ad6bSScott Kruger
91129921a8fSScott Kruger    # Open file
912e551db17SScott Kruger    arch_files = os.path.join(self.arch_dir,'lib','petsc','conf', 'testfiles')
91329921a8fSScott Kruger    fd = open(arch_files, 'w')
91429921a8fSScott Kruger
91529921a8fSScott Kruger    # Write out the sources
916b0790570SJed Brown    gendeps = self.gen_gnumake(fd)
91729921a8fSScott Kruger
91829921a8fSScott Kruger    # Write out the tests and execname targets
91929921a8fSScott Kruger    fd.write("\n#Tests and executables\n")    # Delimiter
92029921a8fSScott Kruger
92129921a8fSScott Kruger    for pkg in PKGS:
92229921a8fSScott Kruger      # These grab the ones that are built
92329921a8fSScott Kruger      for lang in LANGS:
92485a27222SJed Brown        testdeps=[]
92529921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
92629921a8fSScott Kruger          test=os.path.basename(ftest)
92729921a8fSScott Kruger          basedir=os.path.dirname(ftest)
92885a27222SJed Brown          testdeps.append(self.nameSpace(test,basedir))
929612eee3eSJed Brown        fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n")
93065ea9442SJed Brown        fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang))
93129921a8fSScott Kruger
93229921a8fSScott Kruger        # test targets
93329921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
93429921a8fSScott Kruger          test=os.path.basename(ftest)
93529921a8fSScott Kruger          basedir=os.path.dirname(ftest)
93629921a8fSScott Kruger          testdir="${TESTDIR}/"+basedir+"/"
93729921a8fSScott Kruger          nmtest=self.nameSpace(test,basedir)
93829921a8fSScott Kruger          rundir=os.path.join(testdir,test)
93929921a8fSScott Kruger          #print test, nmtest
94029921a8fSScott Kruger          script=test+".sh"
94129921a8fSScott Kruger
94229921a8fSScott Kruger          # Deps
94329921a8fSScott Kruger          exfile=self.tests[pkg][lang][ftest]['exfile']
944e551db17SScott Kruger          fullex=os.path.join(os.path.dirname(self.srcdir),exfile)
94529921a8fSScott Kruger          localexec=self.tests[pkg][lang][ftest]['exec']
94629921a8fSScott Kruger          execname=os.path.join(testdir,localexec)
94768f6ad6bSScott Kruger          fullscript=os.path.join(testdir,script)
94868f6ad6bSScott Kruger          tmpfile=os.path.join(testdir,test,test+".tmp")
94929921a8fSScott Kruger
950b91d4a07SJed Brown          # *.counts depends on the script and either executable (will
951b91d4a07SJed Brown          # be run) or the example source file (SKIP or TODO)
952fa9d32b8SSatish Balay          fd.write('%s.counts : %s %s'
953b91d4a07SJed Brown              % (os.path.join('$(TESTDIR)/counts', nmtest),
954b91d4a07SJed Brown                 fullscript,
9554fedfc52SScott Kruger                 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)
9564fedfc52SScott Kruger              )
957fa9d32b8SSatish Balay          if exfile in self.sources[pkg][lang]:
958fa9d32b8SSatish Balay            for dep in self.sources[pkg][lang][exfile]:
959fa9d32b8SSatish Balay              fd.write(' %s' % os.path.join('$(TESTDIR)',dep))
960fa9d32b8SSatish Balay          fd.write('\n')
9614fedfc52SScott Kruger
96229921a8fSScott Kruger          # Now write the args:
963612eee3eSJed Brown          fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n")
964df2e1f37SScott Kruger
965612eee3eSJed Brown    fd.close()
96629921a8fSScott Kruger    return
96729921a8fSScott Kruger
96829921a8fSScott Kruger  def writeHarness(self,output,dataDict):
96929921a8fSScott Kruger    """
97029921a8fSScott Kruger     This is set up to write out multiple harness even if only gnumake
97129921a8fSScott Kruger     is supported now
97229921a8fSScott Kruger    """
97329921a8fSScott Kruger    eval("self.write_"+output+"(dataDict)")
97429921a8fSScott Kruger    return
97529921a8fSScott Kruger
976e551db17SScott Krugerdef main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False, srcdir=None, testdir=None):
97729921a8fSScott Kruger    if output is None:
97829921a8fSScott Kruger        output = 'gnumake'
97929921a8fSScott Kruger
980c173c275SScott Kruger    # Allow petsc_arch to have both petsc_dir and petsc_arch for convenience
981cadd188bSScott Kruger    if petsc_arch:
982c173c275SScott Kruger        if len(petsc_arch.split(os.path.sep))>1:
983c173c275SScott Kruger            petsc_dir,petsc_arch=os.path.split(petsc_arch.rstrip(os.path.sep))
98429921a8fSScott Kruger
985e551db17SScott Kruger    pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch,
986e551db17SScott Kruger                         verbose=verbose, single_ex=single_ex, srcdir=srcdir,
987e551db17SScott Kruger                         testdir=testdir)
988cadd188bSScott Kruger    dataDict=pEx.walktree(os.path.join(pEx.srcdir))
98929921a8fSScott Kruger    pEx.writeHarness(output,dataDict)
99029921a8fSScott Kruger
99129921a8fSScott Krugerif __name__ == '__main__':
99229921a8fSScott Kruger    import optparse
99329921a8fSScott Kruger    parser = optparse.OptionParser()
99429921a8fSScott Kruger    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
995*4ff3c6a1SScott Kruger    parser.add_option('--petsc-dir', help='Set PETSC_DIR different from environment', default=os.environ.get('PETSC_DIR'))
99629921a8fSScott Kruger    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
997e551db17SScott Kruger    parser.add_option('--srcdir', help='Set location of sources different from PETSC_DIR/src', default=None)
99829921a8fSScott Kruger    parser.add_option('--output', help='Location to write output file', default=None)
99929921a8fSScott 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')
1000e551db17SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',  help='Test directory: PETSC_DIR/PETSC_ARCH/testdir.  Default is "tests"')
1001*4ff3c6a1SScott Kruger
100229921a8fSScott Kruger    opts, extra_args = parser.parse_args()
100329921a8fSScott Kruger    if extra_args:
100429921a8fSScott Kruger        import sys
100529921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
100629921a8fSScott Kruger        exit(1)
1007*4ff3c6a1SScott Kruger
1008*4ff3c6a1SScott Kruger    main(petsc_dir=opts.petsc_dir, petsc_arch=opts.petsc_arch,
1009*4ff3c6a1SScott Kruger         output=opts.output, verbose=opts.verbose,
1010*4ff3c6a1SScott Kruger         single_ex=opts.single_executable, srcdir=opts.srcdir,
1011*4ff3c6a1SScott Kruger         testdir=opts.testdir)
1012