xref: /petsc/config/testparse.py (revision 44776d8c709152d7fc2d6f8f7b1a2f9c2350a754)
129921a8fSScott Kruger#!/usr/bin/env python
229921a8fSScott Kruger"""
329921a8fSScott KrugerParse the test file and return a dictionary.
429921a8fSScott Kruger
529921a8fSScott KrugerQuick usage::
629921a8fSScott Kruger
729921a8fSScott Kruger  bin/maint/testparse.py -t src/ksp/ksp/examples/tutorials/ex1.c
829921a8fSScott Kruger
929921a8fSScott KrugerFrom the command line, it prints out the dictionary.
1029921a8fSScott KrugerThis is meant to be used by other scripts, but it is
1129921a8fSScott Krugeruseful to debug individual files.
1229921a8fSScott Kruger
1329921a8fSScott Kruger
1429921a8fSScott Kruger
1529921a8fSScott KrugerExample language
1629921a8fSScott Kruger----------------
1729921a8fSScott Kruger/*T
1829921a8fSScott Kruger   Concepts:
1929921a8fSScott Kruger   requires: moab
2029921a8fSScott KrugerT*/
2129921a8fSScott Kruger
2229921a8fSScott Kruger
2329921a8fSScott Kruger
2429921a8fSScott Kruger/*TEST
2529921a8fSScott Kruger
2629921a8fSScott Kruger   test:
2729921a8fSScott Kruger      args: -pc_type mg -ksp_type fgmres -da_refine 2 -ksp_monitor_short -mg_levels_ksp_monitor_short -mg_levels_ksp_norm_type unpreconditioned -ksp_view -pc_mg_type full
2829921a8fSScott Kruger
2929921a8fSScott Kruger   test:
3029921a8fSScott Kruger      suffix: 2
3129921a8fSScott Kruger      nsize: 2
3229921a8fSScott Kruger      args: -pc_type mg -ksp_type fgmres -da_refine 2 -ksp_monitor_short -mg_levels_ksp_monitor_short -mg_levels_ksp_norm_type unpreconditioned -ksp_view -pc_mg_type full
3329921a8fSScott Kruger
3429921a8fSScott KrugerTEST*/
3529921a8fSScott Kruger
3629921a8fSScott Kruger"""
3729921a8fSScott Kruger
3829921a8fSScott Krugerimport os, re, glob, types
3929921a8fSScott Krugerfrom distutils.sysconfig import parse_makefile
4029921a8fSScott Krugerimport sys
4129921a8fSScott Krugerimport logging
4229921a8fSScott Krugersys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
4329921a8fSScott Kruger
4429921a8fSScott Krugerimport inspect
4529921a8fSScott Krugerthisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
4629921a8fSScott Krugermaintdir=os.path.join(os.path.join(os.path.dirname(thisscriptdir),'bin'),'maint')
4729921a8fSScott Krugersys.path.insert(0,maintdir)
4829921a8fSScott Kruger
4929921a8fSScott Kruger# These are special keys describing build
5029921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split()
5129921a8fSScott Kruger
52*44776d8cSScott Krugeracceptedkeys="test nsize requires command suffix args separate_testvars filter filter_output localrunfiles comments TODO SKIP output_file".split()
53*44776d8cSScott Krugerappendlist="args requires comments".split()
5468a9e459SScott Kruger
5568a9e459SScott Krugerimport re
5668a9e459SScott Kruger
57*44776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]):
5829921a8fSScott Kruger  """
5929921a8fSScott Kruger  Go through and remove a level of indentation
6029921a8fSScott Kruger  Also strip of trailing whitespace
6129921a8fSScott Kruger  """
6229921a8fSScott Kruger  # The first entry should be test: but it might be indented.
6329921a8fSScott Kruger  ext=os.path.splitext(srcfile)[1]
64*44776d8cSScott Kruger  stripstr=" "
658ccd5183SScott Kruger  for lline in block.split("\n"):
668ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
6729921a8fSScott Kruger    if not line.strip(): continue
68c4b80baaSScott Kruger    if line.strip().startswith('#'): continue
69*44776d8cSScott Kruger    if entireBlock:
70*44776d8cSScott Kruger      var=line.split(":")[0].strip()
71*44776d8cSScott Kruger      if not var=='test':
72*44776d8cSScott Kruger        raise Exception("Formatting error in finding test in file: "+srcfile+"\n")
7329921a8fSScott Kruger    nspace=len(line)-len(line.lstrip(stripstr))
7429921a8fSScott Kruger    newline=line[nspace:]
7529921a8fSScott Kruger    break
7629921a8fSScott Kruger
7729921a8fSScott Kruger  # Strip off any indentation for the whole string and any trailing
7829921a8fSScott Kruger  # whitespace for convenience
7929921a8fSScott Kruger  newTestStr="\n"
80*44776d8cSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
81*44776d8cSScott Kruger  firstPass=True
828ccd5183SScott Kruger  for lline in block.split("\n"):
83*44776d8cSScott Kruger    if len(fileNums)>0: lineNum+=1
848ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
8529921a8fSScott Kruger    if not line.strip(): continue
86c4b80baaSScott Kruger    if line.strip().startswith('#'):
87c4b80baaSScott Kruger      newTestStr+=line+'\n'
88c4b80baaSScott Kruger    else:
8929921a8fSScott Kruger      newline=line[nspace:]
90c4b80baaSScott Kruger      newTestStr+=newline.rstrip()+"\n"
91*44776d8cSScott Kruger    # Do some basic indentation checks
92*44776d8cSScott Kruger    if entireBlock:
93*44776d8cSScott Kruger      # Don't need to check comment lines
94*44776d8cSScott Kruger      if line.strip().startswith('#'): continue
95*44776d8cSScott Kruger      if not newline.startswith(" "):
96*44776d8cSScott Kruger        var=newline.split(":")[0].strip()
97*44776d8cSScott Kruger        if not var=='test':
98*44776d8cSScott Kruger          err="Formatting error in file "+srcfile+" at line: " +line+"\n"
99*44776d8cSScott Kruger          if len(fileNums)>0:
100*44776d8cSScott Kruger            raise Exception(err+"Check indentation at line number: "+str(lineNum))
101*44776d8cSScott Kruger          else:
102*44776d8cSScott Kruger            raise Exception(err)
103*44776d8cSScott Kruger      else:
104*44776d8cSScott Kruger        var=line.split(":")[0].strip()
105*44776d8cSScott Kruger        if var=='test':
106*44776d8cSScott Kruger          subnspace=len(line)-len(line.lstrip(stripstr))
107*44776d8cSScott Kruger          if firstPass:
108*44776d8cSScott Kruger            firstsubnspace=subnspace
109*44776d8cSScott Kruger            firstPass=False
110*44776d8cSScott Kruger          else:
111*44776d8cSScott Kruger            if firstsubnspace!=subnspace:
112*44776d8cSScott Kruger              err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n"
113*44776d8cSScott Kruger              if len(fileNums)>0:
114*44776d8cSScott Kruger                raise Exception(err+"Check indentation at line number: "+str(lineNum))
115*44776d8cSScott Kruger              else:
116*44776d8cSScott Kruger                raise Exception(err)
117*44776d8cSScott Kruger
11829921a8fSScott Kruger
11929921a8fSScott Kruger  return newTestStr
12029921a8fSScott Kruger
121*44776d8cSScott Krugerdef _getNewArgs(kvar,val,argStr):
122*44776d8cSScott Kruger  """
123*44776d8cSScott Kruger  Given:   String containing arguments
124*44776d8cSScott Kruger  Return:  String without the value in it
125*44776d8cSScott Kruger  """
126*44776d8cSScott Kruger  return newTestStr
127*44776d8cSScott Kruger
128*44776d8cSScott Krugerdef _getVarVals(findvar,testDict):
129*44776d8cSScott Kruger  """
130*44776d8cSScott Kruger  Given: variable that is either nsize or in args
131*44776d8cSScott Kruger  Return:  Values to loop over
132*44776d8cSScott Kruger  """
133*44776d8cSScott Kruger  vals=None
134*44776d8cSScott Kruger  newargs=''
135*44776d8cSScott Kruger  if findvar=='nsize':
136*44776d8cSScott Kruger    vals=testDict[findvar]
137*44776d8cSScott Kruger  else:
138*44776d8cSScott Kruger    varlist=[]
139*44776d8cSScott Kruger    for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
140*44776d8cSScott Kruger      if not varset.strip(): continue
141*44776d8cSScott Kruger      if len(re.findall('{{(.*?)}}',varset))>0:
142*44776d8cSScott Kruger        # Assuming only one for loop per var specification
143*44776d8cSScott Kruger        keyvar=varset.split("{{")[0].strip()
144*44776d8cSScott Kruger        if keyvar!=findvar:
145*44776d8cSScott Kruger          newargs+="-"+varset+" "
146*44776d8cSScott Kruger          continue
147*44776d8cSScott Kruger        vals=re.findall('{{(.*?)}}',varset)[0]
148*44776d8cSScott Kruger
149*44776d8cSScott Kruger  if not vals: raise StandardError("Could not find separate_testvar: "+findvar)
150*44776d8cSScott Kruger  return vals,newargs
151*44776d8cSScott Kruger
152*44776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts):
153*44776d8cSScott Kruger  """
154*44776d8cSScott Kruger  Given: testname, sdict with separate_testvars
155*44776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
156*44776d8cSScott Kruger  """
157*44776d8cSScott Kruger  testnames=[]; sdicts=[]
158*44776d8cSScott Kruger  for i in range(len(intests)):
159*44776d8cSScott Kruger    testname=intests[i]; sdict=indicts[i]; i+=1
160*44776d8cSScott Kruger    if sdict.has_key('separate_testvars'):
161*44776d8cSScott Kruger      for kvar in sdict['separate_testvars'].split():
162*44776d8cSScott Kruger        kvals,newargs=_getVarVals(kvar,sdict)
163*44776d8cSScott Kruger        # No errors means we are good to go
164*44776d8cSScott Kruger        for val in kvals.split():
165*44776d8cSScott Kruger          kvardict=sdict.copy()
166*44776d8cSScott Kruger          del kvardict['separate_testvars']
167*44776d8cSScott Kruger          gensuffix="_"+kvar+"-"+val
168*44776d8cSScott Kruger          newtestnm=testname+gensuffix
169*44776d8cSScott Kruger          kvardict['suffix']=sdict['suffix']+gensuffix
170*44776d8cSScott Kruger          if kvar=='nsize':
171*44776d8cSScott Kruger            kvardict[kvar]=val
172*44776d8cSScott Kruger          else:
173*44776d8cSScott Kruger            kvardict['args']=newargs+"-"+kvar+" "+val
174*44776d8cSScott Kruger          testnames.append(newtestnm)
175*44776d8cSScott Kruger          sdicts.append(kvardict)
176*44776d8cSScott Kruger    else:
177*44776d8cSScott Kruger      testnames.append(testname)
178*44776d8cSScott Kruger      sdicts.append(sdict)
179*44776d8cSScott Kruger  return testnames,sdicts
180*44776d8cSScott Kruger
181*44776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts):
182*44776d8cSScott Kruger  """
183*44776d8cSScott Kruger  Given: testname, sdict with separate_testvars
184*44776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
185*44776d8cSScott Kruger  """
186*44776d8cSScott Kruger  tnms=[]; sdcts=[]
187*44776d8cSScott Kruger  for i in range(len(testnames)):
188*44776d8cSScott Kruger    testname=testnames[i]
189*44776d8cSScott Kruger    rmsubtests=[]; keepSubtests=False
190*44776d8cSScott Kruger    if sdicts[i].has_key('subtests'):
191*44776d8cSScott Kruger      for stest in sdicts[i]["subtests"]:
192*44776d8cSScott Kruger        if sdicts[i][stest].has_key('suffix'):
193*44776d8cSScott Kruger          rmsubtests.append(stest)
194*44776d8cSScott Kruger          gensuffix="_"+sdicts[i][stest]['suffix']
195*44776d8cSScott Kruger          newtestnm=testname+gensuffix
196*44776d8cSScott Kruger          tnms.append(newtestnm)
197*44776d8cSScott Kruger          newsdict=sdicts[i].copy()
198*44776d8cSScott Kruger          del newsdict['subtests']
199*44776d8cSScott Kruger          # Have to hand update
200*44776d8cSScott Kruger          # Append
201*44776d8cSScott Kruger          for kup in appendlist:
202*44776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
203*44776d8cSScott Kruger              if sdicts[i].has_key(kup):
204*44776d8cSScott Kruger                newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup]
205*44776d8cSScott Kruger              else:
206*44776d8cSScott Kruger                newsdict[kup]=sdicts[i][stest][kup]
207*44776d8cSScott Kruger          # Promote
208*44776d8cSScott Kruger          for kup in acceptedkeys:
209*44776d8cSScott Kruger            if kup in appendlist: continue
210*44776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
211*44776d8cSScott Kruger              newsdict[kup]=sdicts[i][stest][kup]
212*44776d8cSScott Kruger          # Cleanup
213*44776d8cSScott Kruger          for st in sdicts[i]["subtests"]: del newsdict[st]
214*44776d8cSScott Kruger          sdcts.append(newsdict)
215*44776d8cSScott Kruger        else:
216*44776d8cSScott Kruger          keepSubtests=True
217*44776d8cSScott Kruger    else:
218*44776d8cSScott Kruger      tnms.append(testnames[i])
219*44776d8cSScott Kruger      sdcts.append(sdicts[i])
220*44776d8cSScott Kruger    # Prune the tests to prepare for keeping
221*44776d8cSScott Kruger    for rmtest in rmsubtests:
222*44776d8cSScott Kruger      sdicts[i]['subtests'].remove(rmtest)
223*44776d8cSScott Kruger      del sdicts[i][rmtest]
224*44776d8cSScott Kruger    # If we are keeping any tests, then append
225*44776d8cSScott Kruger    if keepSubtests:
226*44776d8cSScott Kruger      tnms.append(testnames[i])
227*44776d8cSScott Kruger      sdcts.append(sdicts[i])
228*44776d8cSScott Kruger    i+=1
229*44776d8cSScott Kruger  return tnms,sdcts
230*44776d8cSScott Kruger
231*44776d8cSScott Krugerdef splitTests(testname,sdict):
232*44776d8cSScott Kruger  """
233*44776d8cSScott Kruger  Given: testname and YAML-generated dictionary
234*44776d8cSScott Kruger  Return: list of names and dictionaries corresponding to each test
235*44776d8cSScott Kruger          given that the YAML language allows for multiple tests
236*44776d8cSScott Kruger  """
237*44776d8cSScott Kruger
238*44776d8cSScott Kruger  # Order: Parent sep_tv, subtests suffix, subtests sep_tv
239*44776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars([testname],[sdict])
240*44776d8cSScott Kruger  testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts)
241*44776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts)
242*44776d8cSScott Kruger
243*44776d8cSScott Kruger  # Because I am altering the list, I do this in passes.  Inelegant
244*44776d8cSScott Kruger
245*44776d8cSScott Kruger  return testnames, sdicts
246*44776d8cSScott Kruger
24729921a8fSScott Krugerdef parseTest(testStr,srcfile):
24829921a8fSScott Kruger  """
24929921a8fSScott Kruger  This parses an individual test
25029921a8fSScott Kruger  YAML is hierarchial so should use a state machine in the general case,
25153f2a965SBarry Smith  but in practice we only support two levels of test:
25229921a8fSScott Kruger  """
25329921a8fSScott Kruger  basename=os.path.basename(srcfile)
25429921a8fSScott Kruger  # Handle the new at the begininng
25529921a8fSScott Kruger  bn=re.sub("new_","",basename)
25629921a8fSScott Kruger  # This is the default
25729921a8fSScott Kruger  testname="run"+os.path.splitext(bn)[0]
25829921a8fSScott Kruger
25929921a8fSScott Kruger  # Tests that have default everything (so empty effectively)
26029921a8fSScott Kruger  if len(testStr)==0: return testname, {}
26129921a8fSScott Kruger
26229921a8fSScott Kruger  striptest=_stripIndent(testStr,srcfile)
26329921a8fSScott Kruger
26429921a8fSScott Kruger  # go through and parse
26529921a8fSScott Kruger  subtestnum=0
26629921a8fSScott Kruger  subdict={}
26768a9e459SScott Kruger  comments=[]
26868a9e459SScott Kruger  indentlevel=0
26968a9e459SScott Kruger  for ln in striptest.split("\n"):
270c4b80baaSScott Kruger    line=ln.split('#')[0].rstrip()
27168a9e459SScott Kruger    comment=("" if len(ln.split("#"))==1 else " ".join(ln.split("#")[1:]).strip())
27268a9e459SScott Kruger    if comment: comments.append(comment)
27329921a8fSScott Kruger    if not line.strip(): continue
274*44776d8cSScott Kruger    lsplit=line.split(':')
275*44776d8cSScott Kruger    if len(lsplit)==0: raise Exception("Missing : in line: "+line)
276*44776d8cSScott Kruger    indentcount=lsplit[0].count(" ")
277*44776d8cSScott Kruger    var=lsplit[0].strip()
278*44776d8cSScott Kruger    val=lsplit[1].strip()
279*44776d8cSScott Kruger    if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from:  "+line)
28029921a8fSScott Kruger    # Start by seeing if we are in a subtest
28129921a8fSScott Kruger    if line.startswith(" "):
282c0658d2aSScott Kruger      subdict[subtestname][var]=val
28368a9e459SScott Kruger      if not indentlevel: indentlevel=indentcount
28468a9e459SScott Kruger      #if indentlevel!=indentcount: print "Error in indentation:", ln
28529921a8fSScott Kruger    # Determine subtest name and make dict
28629921a8fSScott Kruger    elif var=="test":
28729921a8fSScott Kruger      subtestname="test"+str(subtestnum)
28829921a8fSScott Kruger      subdict[subtestname]={}
28929921a8fSScott Kruger      if not subdict.has_key("subtests"): subdict["subtests"]=[]
29029921a8fSScott Kruger      subdict["subtests"].append(subtestname)
29129921a8fSScott Kruger      subtestnum=subtestnum+1
29268a9e459SScott Kruger    # The rest are easy
29329921a8fSScott Kruger    else:
294*44776d8cSScott Kruger      # For convenience, it is sometimes convenient to list twice
295*44776d8cSScott Kruger      if subdict.has_key(var):
296*44776d8cSScott Kruger        if var in appendlist:
297*44776d8cSScott Kruger          subdict[var]+=" "+val
298*44776d8cSScott Kruger        else:
299*44776d8cSScott Kruger          raise Exception(var+" entered twice: "+line)
300*44776d8cSScott Kruger      else:
301c0658d2aSScott Kruger        subdict[var]=val
30229921a8fSScott Kruger      if var=="suffix":
30329921a8fSScott Kruger        if len(val)>0:
30429921a8fSScott Kruger          testname=testname+"_"+val
30529921a8fSScott Kruger
30668a9e459SScott Kruger  if len(comments): subdict['comments']="\n".join(comments).lstrip("\n")
307*44776d8cSScott Kruger  # A test block can create multiple tests.  This does
308*44776d8cSScott Kruger  # that logic
309*44776d8cSScott Kruger  testnames,subdicts=splitTests(testname,subdict)
310*44776d8cSScott Kruger  return testnames,subdicts
31129921a8fSScott Kruger
312*44776d8cSScott Krugerdef parseTests(testStr,srcfile,fileNums):
31329921a8fSScott Kruger  """
31429921a8fSScott Kruger  Parse the yaml string describing tests and return
31529921a8fSScott Kruger  a dictionary with the info in the form of:
31629921a8fSScott Kruger    testDict[test][subtest]
31729921a8fSScott Kruger  This is an inelegant parser as we do not wish to
31829921a8fSScott Kruger  introduce a new dependency by bringing in pyyaml.
31929921a8fSScott Kruger  The advantage is that validation can be done as
32029921a8fSScott Kruger  it is parsed (e.g., 'test' is the only top-level node)
32129921a8fSScott Kruger  """
32229921a8fSScott Kruger
32329921a8fSScott Kruger  testDict={}
32429921a8fSScott Kruger
32529921a8fSScott Kruger  # The first entry should be test: but it might be indented.
326*44776d8cSScott Kruger  newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums)
32729921a8fSScott Kruger
32829921a8fSScott Kruger  # Now go through each test.  First elem in split is blank
329c4b80baaSScott Kruger  for test in newTestStr.split("\ntest:")[1:]:
330*44776d8cSScott Kruger    testnames,subdicts=parseTest(test,srcfile)
331*44776d8cSScott Kruger    for i in range(len(testnames)):
332*44776d8cSScott Kruger      if testDict.has_key(testnames[i]):
333*44776d8cSScott Kruger        raise Error("Multiple test names specified: "+testname+" in file: "+srcfile)
334*44776d8cSScott Kruger      testDict[testnames[i]]=subdicts[i]
33529921a8fSScott Kruger
33629921a8fSScott Kruger  return testDict
33729921a8fSScott Kruger
33829921a8fSScott Krugerdef parseTestFile(srcfile):
33929921a8fSScott Kruger  """
34029921a8fSScott Kruger  Parse single example files and return dictionary of the form:
34129921a8fSScott Kruger    testDict[srcfile][test][subtest]
34229921a8fSScott Kruger  """
34329921a8fSScott Kruger  debug=False
34429921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
34529921a8fSScott Kruger  basedir=os.path.dirname(os.path.realpath(srcfile))
34629921a8fSScott Kruger  basename=os.path.basename(srcfile)
34729921a8fSScott Kruger  os.chdir(basedir)
34829921a8fSScott Kruger
34929921a8fSScott Kruger  testDict={}
35029921a8fSScott Kruger  sh=open(srcfile,"r"); fileStr=sh.read(); sh.close()
35129921a8fSScott Kruger
35229921a8fSScott Kruger  ## Start with doing the tests
35329921a8fSScott Kruger  #
35429921a8fSScott Kruger  fsplit=fileStr.split("/*TEST\n")[1:]
35529921a8fSScott Kruger  if len(fsplit)==0:
35629921a8fSScott Kruger    if debug: print "No test found in: "+srcfile
35729921a8fSScott Kruger    return {}
358*44776d8cSScott Kruger  fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1
35929921a8fSScott Kruger  # Allow for multiple "/*TEST" blocks even though it really should be
36029921a8fSScott Kruger  # on
36129921a8fSScott Kruger  srcTests=[]
36229921a8fSScott Kruger  for t in fsplit: srcTests.append(t.split("TEST*/")[0])
36329921a8fSScott Kruger  testString=" ".join(srcTests)
36429921a8fSScott Kruger  if len(testString.strip())==0:
36529921a8fSScott Kruger    print "No test found in: "+srcfile
36629921a8fSScott Kruger    return {}
367*44776d8cSScott Kruger  flen=len(testString.split("\n"))
368*44776d8cSScott Kruger  fend=fstart+flen-1
369*44776d8cSScott Kruger  fileNums=range(fstart,fend)
370*44776d8cSScott Kruger  testDict[basename]=parseTests(testString,srcfile,fileNums)
37129921a8fSScott Kruger
37229921a8fSScott Kruger  ## Check and see if we have build reuqirements
37329921a8fSScott Kruger  #
37429921a8fSScott Kruger  if "/*T\n" in fileStr or "/*T " in fileStr:
37529921a8fSScott Kruger    # The file info is already here and need to append
37629921a8fSScott Kruger    Part1=fileStr.split("T*/")[0]
37729921a8fSScott Kruger    fileInfo=Part1.split("/*T")[1]
37829921a8fSScott Kruger    for bkey in buildkeys:
37929921a8fSScott Kruger      if bkey+":" in fileInfo:
38029921a8fSScott Kruger        testDict[basename][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip()
38129921a8fSScott Kruger
38229921a8fSScott Kruger  os.chdir(curdir)
38329921a8fSScott Kruger  return testDict
38429921a8fSScott Kruger
38529921a8fSScott Krugerdef parseTestDir(directory):
38629921a8fSScott Kruger  """
38729921a8fSScott Kruger  Parse single example files and return dictionary of the form:
38829921a8fSScott Kruger    testDict[srcfile][test][subtest]
38929921a8fSScott Kruger  """
39029921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
39129921a8fSScott Kruger  basedir=os.path.realpath(directory)
39229921a8fSScott Kruger  os.chdir(basedir)
39329921a8fSScott Kruger
39429921a8fSScott Kruger  tDict={}
39529921a8fSScott Kruger  for test_file in glob.glob("new_ex*.*"):
39629921a8fSScott Kruger    tDict.update(parseTestFile(test_file))
39729921a8fSScott Kruger
39829921a8fSScott Kruger  os.chdir(curdir)
39929921a8fSScott Kruger  return tDict
40029921a8fSScott Kruger
40129921a8fSScott Krugerdef printExParseDict(rDict):
40229921a8fSScott Kruger  """
40329921a8fSScott Kruger  This is useful for debugging
40429921a8fSScott Kruger  """
40529921a8fSScott Kruger  indent="   "
40629921a8fSScott Kruger  for sfile in rDict:
407*44776d8cSScott Kruger    print sfile
408*44776d8cSScott Kruger    sortkeys=rDict[sfile].keys()
409*44776d8cSScott Kruger    sortkeys.sort()
410*44776d8cSScott Kruger    for runex in sortkeys:
41129921a8fSScott Kruger      print indent+runex
41229921a8fSScott Kruger      if type(rDict[sfile][runex])==types.StringType:
41329921a8fSScott Kruger        print indent*2+rDict[sfile][runex]
41429921a8fSScott Kruger      else:
41529921a8fSScott Kruger        for var in rDict[sfile][runex]:
416*44776d8cSScott Kruger          if var.startswith("test"): continue
417*44776d8cSScott Kruger          print indent*2+var+": "+str(rDict[sfile][runex][var])
418*44776d8cSScott Kruger        if rDict[sfile][runex].has_key('subtests'):
419*44776d8cSScott Kruger          for var in rDict[sfile][runex]['subtests']:
42029921a8fSScott Kruger            print indent*2+var
42129921a8fSScott Kruger            for var2 in rDict[sfile][runex][var]:
42229921a8fSScott Kruger              print indent*3+var2+": "+str(rDict[sfile][runex][var][var2])
423*44776d8cSScott Kruger      print "\n"
42429921a8fSScott Kruger  return
42529921a8fSScott Kruger
42629921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0):
42729921a8fSScott Kruger
42829921a8fSScott Kruger    if directory:
42929921a8fSScott Kruger      tDict=parseTestDir(directory)
43029921a8fSScott Kruger    else:
43129921a8fSScott Kruger      tDict=parseTestFile(test_file)
43229921a8fSScott Kruger    if verbosity>0: printExParseDict(tDict)
43329921a8fSScott Kruger
43429921a8fSScott Kruger    return
43529921a8fSScott Kruger
43629921a8fSScott Krugerif __name__ == '__main__':
43729921a8fSScott Kruger    import optparse
43829921a8fSScott Kruger    parser = optparse.OptionParser()
43929921a8fSScott Kruger    parser.add_option('-d', '--directory', dest='directory',
44029921a8fSScott Kruger                      default="", help='Directory containing files to parse')
44129921a8fSScott Kruger    parser.add_option('-t', '--test_file', dest='test_file',
44229921a8fSScott Kruger                      default="", help='Test file, e.g., ex1.c, to parse')
44329921a8fSScott Kruger    parser.add_option('-v', '--verbosity', dest='verbosity',
44429921a8fSScott Kruger                      help='Verbosity of output by level: 1, 2, or 3', default=0)
44529921a8fSScott Kruger    opts, extra_args = parser.parse_args()
44629921a8fSScott Kruger
44729921a8fSScott Kruger    if extra_args:
44829921a8fSScott Kruger        import sys
44929921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
45029921a8fSScott Kruger        exit(1)
45129921a8fSScott Kruger    if not opts.test_file and not opts.directory:
45229921a8fSScott Kruger      print "test file or directory is required"
45329921a8fSScott Kruger      parser.print_usage()
45429921a8fSScott Kruger      sys.exit()
45529921a8fSScott Kruger
45629921a8fSScott Kruger    # Need verbosity to be an integer
45729921a8fSScott Kruger    try:
45829921a8fSScott Kruger      verbosity=int(opts.verbosity)
45929921a8fSScott Kruger    except:
46029921a8fSScott Kruger      raise Exception("Error: Verbosity must be integer")
46129921a8fSScott Kruger
46229921a8fSScott Kruger    main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity)
463