xref: /petsc/config/gmakegentest.py (revision c3a89c15c66be42c1ea3c2eab6faebba95f76ffa)
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
194ff3c6a1SScott Kruger
204ff3c6a1SScott Kruger"""
214ff3c6a1SScott Kruger
224ff3c6a1SScott KrugerThere are 3 modes of running tests: Normal builds, test installs from builds,
234ff3c6a1SScott Krugertest installs from within install dir.  They affect where to find things:
244ff3c6a1SScott Kruger
254ff3c6a1SScott Kruger
264ff3c6a1SScott KrugerCase 1.  Normal builds:
274ff3c6a1SScott Kruger
284ff3c6a1SScott Kruger     +---------------------+----------------------------------+
294ff3c6a1SScott Kruger     | PETSC_DIR           | <git dir>                        |
304ff3c6a1SScott Kruger     +---------------------+----------------------------------+
314ff3c6a1SScott Kruger     | PETSC_ARCH          | arch-foo                         |
324ff3c6a1SScott Kruger     +---------------------+----------------------------------+
334ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib         |
344ff3c6a1SScott Kruger     +---------------------+----------------------------------+
354ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_DIR/src                    |
364ff3c6a1SScott Kruger     +---------------------+----------------------------------+
374ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests       |
384ff3c6a1SScott Kruger     +---------------------+----------------------------------+
394ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/gmakefile.test         |
404ff3c6a1SScott Kruger     +---------------------+----------------------------------+
414ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/config/gmakegentest.py |
424ff3c6a1SScott Kruger     +---------------------+----------------------------------+
434ff3c6a1SScott Kruger
444ff3c6a1SScott Kruger
454ff3c6a1SScott KrugerCase 2.  Test immediately after build through makefile & lib/petsc/conf/test:
464ff3c6a1SScott Kruger    (Not in installDir, but using prefix dir.  PETSC_ARCH='')
474ff3c6a1SScott Kruger
484ff3c6a1SScott Kruger     +---------------------+----------------------------------+
494ff3c6a1SScott Kruger     | PETSC_DIR           | <prefix dir>                     |
504ff3c6a1SScott Kruger     +---------------------+----------------------------------+
514ff3c6a1SScott Kruger     | PETSC_ARCH          | ''                               |
524ff3c6a1SScott Kruger     +---------------------+----------------------------------+
534ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib         |
544ff3c6a1SScott Kruger     +---------------------+----------------------------------+
554ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_SRC_DIR/src                |
564ff3c6a1SScott Kruger     +---------------------+----------------------------------+
574ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests       |
584ff3c6a1SScott Kruger     +---------------------+----------------------------------+
594ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/gmakefile.test         |
604ff3c6a1SScott Kruger     +---------------------+----------------------------------+
614ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/config/gmakegentest.py |
624ff3c6a1SScott Kruger     +---------------------+----------------------------------+
634ff3c6a1SScott Kruger
644ff3c6a1SScott KrugerCase 3.  From install dir:
654ff3c6a1SScott Kruger
664ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
674ff3c6a1SScott Kruger     | PETSC_DIR           | <prefix dir>                                          |
684ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
694ff3c6a1SScott Kruger     | PETSC_ARCH          | ''                                                    |
704ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
714ff3c6a1SScott Kruger     | PETSC_LIBDIR        | PETSC_DIR/PETSC_ARCH/lib                              |
724ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
734ff3c6a1SScott Kruger     | PETSC_EXAMPLESDIR   | PETSC_DIR/share/petsc/examples/src                    |
744ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
754ff3c6a1SScott Kruger     | PETSC_TESTDIR       | PETSC_DIR/PETSC_ARCH/tests                            |
764ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
774ff3c6a1SScott Kruger     | PETSC_GMAKEFILETEST | PETSC_DIR/share/petsc/examples/gmakefile.test         |
784ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
794ff3c6a1SScott Kruger     | PETSC_GMAKEGENTEST  | PETSC_DIR/share/petsc/examples/config/gmakegentest.py |
804ff3c6a1SScott Kruger     +---------------------+-------------------------------------------------------+
814ff3c6a1SScott Kruger
824ff3c6a1SScott 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)
954ff3c6a1SScott Kruger
96fc46264cSScott Kruger    if not self.inInstallDir:
974ff3c6a1SScott Kruger      if not petsc_arch == '':
984ff3c6a1SScott 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:
1024ff3c6a1SScott Kruger        # Case 2 discussed above
1034ff3c6a1SScott Kruger        self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch)
1044ff3c6a1SScott Kruger        self.srcdir=os.path.join(os.path.dirname(thisscriptdir),'src')
1054ff3c6a1SScott Kruger    else:
1064ff3c6a1SScott 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:
3894ff3c6a1SScott Kruger      if not self.petsc_arch == '':
3904ff3c6a1SScott Kruger        # Case 1
391e551db17SScott Kruger        subst['CONFIG_DIR']=os.path.join(self.petsc_dir,'config')
392*c3a89c15SBarry Smith        subst['PETSC_BINDIR']=os.path.join(self.petsc_dir,'lib','petsc','bin')
393e551db17SScott Kruger      else:
3944ff3c6a1SScott Kruger        # Case 2
3954ff3c6a1SScott Kruger        subst['CONFIG_DIR']=os.path.join(os.path.dirname(self.srcdir),'config')
396*c3a89c15SBarry Smith        subst['PETSC_BINDIR']=os.path.join(os.path.dirname(self.srcdir),'lib','petsc','bin')
3974ff3c6a1SScott Kruger    else:
3984ff3c6a1SScott 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']
70573de2b55SScott Kruger        if 'nsize' in testDict[stest]:
70673de2b55SScott Kruger          if testDict[stest].get('nsize',1)>1 and 'MPI_IS_MPIUNI' in self.conf:
70773de2b55SScott Kruger            testDict['SKIP'].append("Parallel test with serial build")
70829921a8fSScott Kruger
70929921a8fSScott Kruger
71029921a8fSScott Kruger    # Now go through all requirements
711862148f4SScott Kruger    if 'requires' in testDict:
71229921a8fSScott Kruger      for requirement in testDict['requires'].split():
71329921a8fSScott Kruger        requirement=requirement.strip()
71429921a8fSScott Kruger        if not requirement: continue
71529921a8fSScott Kruger        if debug: print indent+"Requirement: ", requirement
71629921a8fSScott Kruger        isNull=False
71729921a8fSScott Kruger        if requirement.startswith("!"):
71829921a8fSScott Kruger          requirement=requirement[1:]; isNull=True
71929921a8fSScott Kruger        # Precision requirement for reals
72029921a8fSScott Kruger        if requirement in self.precision_types:
72129921a8fSScott Kruger          if self.conf['PETSC_PRECISION']==requirement:
72209cf0baaSJed Brown            if isNull:
72309cf0baaSJed Brown              testDict['SKIP'].append("not "+requirement+" required")
72409cf0baaSJed Brown              continue
7254bb4d03dSScott Kruger            continue  # Success
72609cf0baaSJed Brown          elif not isNull:
72709cf0baaSJed Brown            testDict['SKIP'].append(requirement+" required")
72809cf0baaSJed Brown            continue
72929921a8fSScott Kruger        # Precision requirement for ints
73029921a8fSScott Kruger        if requirement in self.integer_types:
73129921a8fSScott Kruger          if requirement=="int32":
73229921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==4:
73309cf0baaSJed Brown              if isNull:
73409cf0baaSJed Brown                testDict['SKIP'].append("not int32 required")
73509cf0baaSJed Brown                continue
7364bb4d03dSScott Kruger              continue  # Success
73709cf0baaSJed Brown            elif not isNull:
73809cf0baaSJed Brown              testDict['SKIP'].append("int32 required")
73909cf0baaSJed Brown              continue
74029921a8fSScott Kruger          if requirement=="int64":
74129921a8fSScott Kruger            if self.conf['PETSC_SIZEOF_INT']==8:
74209cf0baaSJed Brown              if isNull:
74309cf0baaSJed Brown                testDict['SKIP'].append("NOT int64 required")
74409cf0baaSJed Brown                continue
7454bb4d03dSScott Kruger              continue  # Success
74609cf0baaSJed Brown            elif not isNull:
74709cf0baaSJed Brown              testDict['SKIP'].append("int64 required")
74809cf0baaSJed Brown              continue
74929921a8fSScott Kruger        # Datafilespath
75009cf0baaSJed Brown        if requirement=="datafilespath" and not isNull:
75109cf0baaSJed Brown          testDict['SKIP'].append("Requires DATAFILESPATH")
75209cf0baaSJed Brown          continue
75329921a8fSScott Kruger        # Defines -- not sure I have comments matching
7548304fa3fSScott Kruger        if "define(" in requirement.lower():
75529921a8fSScott Kruger          reqdef=requirement.split("(")[1].split(")")[0]
75609cf0baaSJed Brown          if reqdef in self.conf:
75729921a8fSScott Kruger            if isNull:
75809cf0baaSJed Brown              testDict['SKIP'].append("Null requirement not met: "+requirement)
75909cf0baaSJed Brown              continue
7604bb4d03dSScott Kruger            continue  # Success
7614bb4d03dSScott Kruger          elif not isNull:
76209cf0baaSJed Brown            testDict['SKIP'].append("Required: "+requirement)
76309cf0baaSJed Brown            continue
76429921a8fSScott Kruger
76529921a8fSScott Kruger        # Rest should be packages that we can just get from conf
76609cf0baaSJed Brown        if requirement == "complex":
76709cf0baaSJed Brown          petscconfvar="PETSC_USE_COMPLEX"
76809cf0baaSJed Brown        else:
76909cf0baaSJed Brown          petscconfvar="PETSC_HAVE_"+requirement.upper()
77029921a8fSScott Kruger        if self.conf.get(petscconfvar):
77129921a8fSScott Kruger          if isNull:
77209cf0baaSJed Brown            testDict['SKIP'].append("Not "+petscconfvar+" requirement not met")
77309cf0baaSJed Brown            continue
7744bb4d03dSScott Kruger          continue  # Success
775df3aec83SJed Brown        elif not isNull:
77629921a8fSScott Kruger          if debug: print "requirement not found: ", requirement
77709cf0baaSJed Brown          testDict['SKIP'].append(petscconfvar+" requirement not met")
77809cf0baaSJed Brown          continue
77929921a8fSScott Kruger
78009cf0baaSJed Brown    return testDict['SKIP'] == []
78129921a8fSScott Kruger
78229921a8fSScott Kruger  def genPetscTests_summarize(self,dataDict):
78329921a8fSScott Kruger    """
78429921a8fSScott Kruger    Required method to state what happened
78529921a8fSScott Kruger    """
78629921a8fSScott Kruger    if not self.summarize: return
78729921a8fSScott Kruger    indent="   "
788cfaa06beSSatish Balay    fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt')
78929921a8fSScott Kruger    fh=open(fhname,"w")
79064ca018dSScott Kruger    #print "See ", fhname
79129921a8fSScott Kruger    for root in dataDict:
792c173c275SScott Kruger      relroot=self.srcrelpath(root)
79329921a8fSScott Kruger      pkg=relroot.split("/")[1]
79429921a8fSScott Kruger      fh.write(relroot+"\n")
79529921a8fSScott Kruger      allSrcs=[]
796e551db17SScott Kruger      for lang in LANGS: allSrcs+=self.sources[pkg][lang]['srcs']
79729921a8fSScott Kruger      for exfile in dataDict[root]:
79829921a8fSScott Kruger        # Basic  information
799c173c275SScott Kruger        rfile=os.path.join(relroot,exfile)
80029921a8fSScott Kruger        builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built")
80129921a8fSScott Kruger        fh.write(indent+exfile+indent*4+builtStatus+"\n")
80229921a8fSScott Kruger
80329921a8fSScott Kruger        for test in dataDict[root][exfile]:
80429921a8fSScott Kruger          if test in self.buildkeys: continue
80529921a8fSScott Kruger          line=indent*2+test
80629921a8fSScott Kruger          fh.write(line+"\n")
80729921a8fSScott Kruger          # Looks nice to have the keys in order
80829921a8fSScott Kruger          #for key in dataDict[root][exfile][test]:
80929921a8fSScott Kruger          for key in "isrun abstracted nsize args requires script".split():
810862148f4SScott Kruger            if key not in dataDict[root][exfile][test]: continue
81129921a8fSScott Kruger            line=indent*3+key+": "+str(dataDict[root][exfile][test][key])
81229921a8fSScott Kruger            fh.write(line+"\n")
81329921a8fSScott Kruger          fh.write("\n")
81429921a8fSScott Kruger        fh.write("\n")
81529921a8fSScott Kruger      fh.write("\n")
81629921a8fSScott Kruger    #fh.write("\nClass Sources\n"+str(self.sources)+"\n")
81729921a8fSScott Kruger    #fh.write("\nClass Tests\n"+str(self.tests)+"\n")
81829921a8fSScott Kruger    fh.close()
81929921a8fSScott Kruger    return
82029921a8fSScott Kruger
82129921a8fSScott Kruger  def genPetscTests(self,root,dirs,files,dataDict):
82229921a8fSScott Kruger    """
82329921a8fSScott Kruger     Go through and parse the source files in the directory to generate
82429921a8fSScott Kruger     the examples based on the metadata contained in the source files
82529921a8fSScott Kruger    """
82629921a8fSScott Kruger    debug=False
82729921a8fSScott Kruger    # Use examplesAnalyze to get what the makefles think are sources
82829921a8fSScott Kruger    #self.examplesAnalyze(root,dirs,files,anlzDict)
82929921a8fSScott Kruger
83029921a8fSScott Kruger    dataDict[root]={}
83129921a8fSScott Kruger
83229921a8fSScott Kruger    for exfile in files:
83329921a8fSScott Kruger      #TST: Until we replace files, still leaving the orginals as is
83429921a8fSScott Kruger      #if not exfile.startswith("new_"+"ex"): continue
83562197512SBarry Smith      #if not exfile.startswith("ex"): continue
83629921a8fSScott Kruger
837e4653983SScott Kruger      # Ignore emacs and other temporary files
838e4653983SScott Kruger      if exfile.startswith("."): continue
839e4653983SScott Kruger      if exfile.startswith("#"): continue
84013ddbc6dSScott Kruger
84129921a8fSScott Kruger      # Convenience
84229921a8fSScott Kruger      fullex=os.path.join(root,exfile)
843cadd188bSScott Kruger      if self.verbose: print('   --> '+fullex)
84496d5c3b5SScott Kruger      dataDict[root].update(testparse.parseTestFile(fullex,0))
845862148f4SScott Kruger      if exfile in dataDict[root]:
84629921a8fSScott Kruger        self.genScriptsAndInfo(exfile,root,dataDict[root][exfile])
84729921a8fSScott Kruger
84829921a8fSScott Kruger    return
84929921a8fSScott Kruger
850cadd188bSScott Kruger  def walktree(self,top):
85129921a8fSScott Kruger    """
85229921a8fSScott Kruger    Walk a directory tree, starting from 'top'
85329921a8fSScott Kruger    """
85429921a8fSScott Kruger    #print "action", action
85529921a8fSScott Kruger    # Goal of action is to fill this dictionary
85629921a8fSScott Kruger    dataDict={}
857f98eef70SScott Kruger    for root, dirs, files in os.walk(top, topdown=True):
85829921a8fSScott Kruger      if not "examples" in root: continue
859f98eef70SScott Kruger      if "dSYM" in root: continue
860f98eef70SScott Kruger      if os.path.basename(root.rstrip("/")) == 'output': continue
861cadd188bSScott Kruger      if self.verbose: print(root)
862b6d69c80SScott Kruger      self.genPetscTests(root,dirs,files,dataDict)
86329921a8fSScott Kruger    # Now summarize this dictionary
864cadd188bSScott Kruger    self.genPetscTests_summarize(dataDict)
86529921a8fSScott Kruger    return dataDict
86629921a8fSScott Kruger
867b0790570SJed Brown  def gen_gnumake(self, fd):
86829921a8fSScott Kruger    """
86929921a8fSScott Kruger     Overwrite of the method in the base PETSc class
87029921a8fSScott Kruger    """
87129921a8fSScott Kruger    def write(stem, srcs):
87229921a8fSScott Kruger      for lang in LANGS:
8732ae8c56aSScott Kruger        if srcs[lang]['srcs']:
87429921a8fSScott Kruger          fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs'])))
87529921a8fSScott Kruger    for pkg in PKGS:
87629921a8fSScott Kruger        srcs = self.gen_pkg(pkg)
877b0790570SJed Brown        write('testsrcs-' + pkg, srcs)
8782ae8c56aSScott Kruger        # Handle dependencies
8792ae8c56aSScott Kruger        for lang in LANGS:
8802ae8c56aSScott Kruger            for exfile in srcs[lang]['srcs']:
8812ae8c56aSScott Kruger                if exfile in srcs[lang]:
8822ae8c56aSScott Kruger                    ex='$(TESTDIR)/'+os.path.splitext(exfile)[0]
8832ae8c56aSScott Kruger                    exfo='$(TESTDIR)/'+os.path.splitext(exfile)[0]+'.o'
88449defe6fSJed Brown                    deps = [os.path.join('$(TESTDIR)', dep) for dep in srcs[lang][exfile]]
88549defe6fSJed Brown                    if deps:
88649defe6fSJed Brown                        # The executable literally depends on the object file because it is linked
88749defe6fSJed Brown                        fd.write(ex   +": " + " ".join(deps) +'\n')
88849defe6fSJed Brown                        # The object file containing 'main' does not normally depend on other object
88949defe6fSJed Brown                        # files, but it does when it includes their modules.  This dependency is
89049defe6fSJed Brown                        # overly blunt and could be reduced to only depend on object files for
89149defe6fSJed Brown                        # modules that are used, like "*f90aux.o".
89249defe6fSJed Brown                        fd.write(exfo +": " + " ".join(deps) +'\n')
8932ae8c56aSScott Kruger
89429921a8fSScott Kruger    return self.gendeps
89529921a8fSScott Kruger
89629921a8fSScott Kruger  def gen_pkg(self, pkg):
89729921a8fSScott Kruger    """
89829921a8fSScott Kruger     Overwrite of the method in the base PETSc class
89929921a8fSScott Kruger    """
90029921a8fSScott Kruger    return self.sources[pkg]
90129921a8fSScott Kruger
90229921a8fSScott Kruger  def write_gnumake(self,dataDict):
90329921a8fSScott Kruger    """
90429921a8fSScott Kruger     Write out something similar to files from gmakegen.py
90529921a8fSScott Kruger
90629921a8fSScott Kruger     Test depends on script which also depends on source
90729921a8fSScott Kruger     file, but since I don't have a good way generating
90829921a8fSScott Kruger     acting on a single file (oops) just depend on
90929921a8fSScott Kruger     executable which in turn will depend on src file
91029921a8fSScott Kruger    """
91168f6ad6bSScott Kruger    # Different options for how to set up the targets
91268f6ad6bSScott Kruger    compileExecsFirst=False
91368f6ad6bSScott Kruger
91429921a8fSScott Kruger    # Open file
915e551db17SScott Kruger    arch_files = os.path.join(self.arch_dir,'lib','petsc','conf', 'testfiles')
91629921a8fSScott Kruger    fd = open(arch_files, 'w')
91729921a8fSScott Kruger
91829921a8fSScott Kruger    # Write out the sources
919b0790570SJed Brown    gendeps = self.gen_gnumake(fd)
92029921a8fSScott Kruger
92129921a8fSScott Kruger    # Write out the tests and execname targets
92229921a8fSScott Kruger    fd.write("\n#Tests and executables\n")    # Delimiter
92329921a8fSScott Kruger
92429921a8fSScott Kruger    for pkg in PKGS:
92529921a8fSScott Kruger      # These grab the ones that are built
92629921a8fSScott Kruger      for lang in LANGS:
92785a27222SJed Brown        testdeps=[]
92829921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
92929921a8fSScott Kruger          test=os.path.basename(ftest)
93029921a8fSScott Kruger          basedir=os.path.dirname(ftest)
93185a27222SJed Brown          testdeps.append(self.nameSpace(test,basedir))
932612eee3eSJed Brown        fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n")
93365ea9442SJed Brown        fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang))
93429921a8fSScott Kruger
93529921a8fSScott Kruger        # test targets
93629921a8fSScott Kruger        for ftest in self.tests[pkg][lang]:
93729921a8fSScott Kruger          test=os.path.basename(ftest)
93829921a8fSScott Kruger          basedir=os.path.dirname(ftest)
93929921a8fSScott Kruger          testdir="${TESTDIR}/"+basedir+"/"
94029921a8fSScott Kruger          nmtest=self.nameSpace(test,basedir)
94129921a8fSScott Kruger          rundir=os.path.join(testdir,test)
94229921a8fSScott Kruger          #print test, nmtest
94329921a8fSScott Kruger          script=test+".sh"
94429921a8fSScott Kruger
94529921a8fSScott Kruger          # Deps
94629921a8fSScott Kruger          exfile=self.tests[pkg][lang][ftest]['exfile']
947e551db17SScott Kruger          fullex=os.path.join(os.path.dirname(self.srcdir),exfile)
94829921a8fSScott Kruger          localexec=self.tests[pkg][lang][ftest]['exec']
94929921a8fSScott Kruger          execname=os.path.join(testdir,localexec)
95068f6ad6bSScott Kruger          fullscript=os.path.join(testdir,script)
95168f6ad6bSScott Kruger          tmpfile=os.path.join(testdir,test,test+".tmp")
95229921a8fSScott Kruger
953b91d4a07SJed Brown          # *.counts depends on the script and either executable (will
954b91d4a07SJed Brown          # be run) or the example source file (SKIP or TODO)
955fa9d32b8SSatish Balay          fd.write('%s.counts : %s %s'
956b91d4a07SJed Brown              % (os.path.join('$(TESTDIR)/counts', nmtest),
957b91d4a07SJed Brown                 fullscript,
9584fedfc52SScott Kruger                 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)
9594fedfc52SScott Kruger              )
960fa9d32b8SSatish Balay          if exfile in self.sources[pkg][lang]:
961fa9d32b8SSatish Balay            for dep in self.sources[pkg][lang][exfile]:
962fa9d32b8SSatish Balay              fd.write(' %s' % os.path.join('$(TESTDIR)',dep))
963fa9d32b8SSatish Balay          fd.write('\n')
9644fedfc52SScott Kruger
96529921a8fSScott Kruger          # Now write the args:
966612eee3eSJed Brown          fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n")
967df2e1f37SScott Kruger
968612eee3eSJed Brown    fd.close()
96929921a8fSScott Kruger    return
97029921a8fSScott Kruger
97129921a8fSScott Kruger  def writeHarness(self,output,dataDict):
97229921a8fSScott Kruger    """
97329921a8fSScott Kruger     This is set up to write out multiple harness even if only gnumake
97429921a8fSScott Kruger     is supported now
97529921a8fSScott Kruger    """
97629921a8fSScott Kruger    eval("self.write_"+output+"(dataDict)")
97729921a8fSScott Kruger    return
97829921a8fSScott Kruger
979e551db17SScott Krugerdef main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False, srcdir=None, testdir=None):
98029921a8fSScott Kruger    if output is None:
98129921a8fSScott Kruger        output = 'gnumake'
98229921a8fSScott Kruger
983c173c275SScott Kruger    # Allow petsc_arch to have both petsc_dir and petsc_arch for convenience
984cadd188bSScott Kruger    if petsc_arch:
985c173c275SScott Kruger        if len(petsc_arch.split(os.path.sep))>1:
986c173c275SScott Kruger            petsc_dir,petsc_arch=os.path.split(petsc_arch.rstrip(os.path.sep))
98729921a8fSScott Kruger
988e551db17SScott Kruger    pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch,
989e551db17SScott Kruger                         verbose=verbose, single_ex=single_ex, srcdir=srcdir,
990e551db17SScott Kruger                         testdir=testdir)
991cadd188bSScott Kruger    dataDict=pEx.walktree(os.path.join(pEx.srcdir))
99229921a8fSScott Kruger    pEx.writeHarness(output,dataDict)
99329921a8fSScott Kruger
99429921a8fSScott Krugerif __name__ == '__main__':
99529921a8fSScott Kruger    import optparse
99629921a8fSScott Kruger    parser = optparse.OptionParser()
99729921a8fSScott Kruger    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
9984ff3c6a1SScott Kruger    parser.add_option('--petsc-dir', help='Set PETSC_DIR different from environment', default=os.environ.get('PETSC_DIR'))
99929921a8fSScott Kruger    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
1000e551db17SScott Kruger    parser.add_option('--srcdir', help='Set location of sources different from PETSC_DIR/src', default=None)
100129921a8fSScott Kruger    parser.add_option('--output', help='Location to write output file', default=None)
100229921a8fSScott 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')
1003e551db17SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',  help='Test directory: PETSC_DIR/PETSC_ARCH/testdir.  Default is "tests"')
10044ff3c6a1SScott Kruger
100529921a8fSScott Kruger    opts, extra_args = parser.parse_args()
100629921a8fSScott Kruger    if extra_args:
100729921a8fSScott Kruger        import sys
100829921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
100929921a8fSScott Kruger        exit(1)
10104ff3c6a1SScott Kruger
10114ff3c6a1SScott Kruger    main(petsc_dir=opts.petsc_dir, petsc_arch=opts.petsc_arch,
10124ff3c6a1SScott Kruger         output=opts.output, verbose=opts.verbose,
10134ff3c6a1SScott Kruger         single_ex=opts.single_executable, srcdir=opts.srcdir,
10144ff3c6a1SScott Kruger         testdir=opts.testdir)
1015