xref: /petsc/config/query_tests.py (revision 6f5e9bd57b38f022b0f369f1410d1b0511a5a792)
1*6f5e9bd5SScott Kruger#!/usr/bin/env python
2*6f5e9bd5SScott Krugerimport fnmatch
3*6f5e9bd5SScott Krugerimport glob
4*6f5e9bd5SScott Krugerimport inspect
5*6f5e9bd5SScott Krugerimport os
6*6f5e9bd5SScott Krugerimport optparse
7*6f5e9bd5SScott Krugerimport pickle
8*6f5e9bd5SScott Krugerimport re
9*6f5e9bd5SScott Krugerimport sys
10*6f5e9bd5SScott Kruger
11*6f5e9bd5SScott Krugerthisfile = os.path.abspath(inspect.getfile(inspect.currentframe()))
12*6f5e9bd5SScott Krugerpdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(thisfile)))))
13*6f5e9bd5SScott Krugersys.path.insert(0, os.path.join(pdir, 'config'))
14*6f5e9bd5SScott Kruger
15*6f5e9bd5SScott Krugerimport testparse
16*6f5e9bd5SScott Krugerfrom gmakegentest import nameSpace
17*6f5e9bd5SScott Kruger
18*6f5e9bd5SScott Kruger
19*6f5e9bd5SScott Kruger"""
20*6f5e9bd5SScott Kruger  Tool for querying the tests.
21*6f5e9bd5SScott Kruger
22*6f5e9bd5SScott Kruger  Which tests to query?  Two options:
23*6f5e9bd5SScott Kruger      1. Query only the tests that are run for a given configuration.
24*6f5e9bd5SScott Kruger      2. Query all of the test files in the source directory
25*6f5e9bd5SScott Kruger  For #1:
26*6f5e9bd5SScott Kruger     Use dataDict as written out by gmakegentest.py in $PETSC_ARCH/$TESTBASE
27*6f5e9bd5SScott Kruger  For #2:
28*6f5e9bd5SScott Kruger     Walk the entire tree parsing the files as we go along using testparse.
29*6f5e9bd5SScott Kruger     The tree walker is simpler than what is in gmakegentest.py
30*6f5e9bd5SScott Kruger
31*6f5e9bd5SScott Kruger  The dataDict follows that generated by testparse.  gmakegentest.py does
32*6f5e9bd5SScott Kruger  further manipulations of the dataDict to handle things like for loops
33*6f5e9bd5SScott Kruger  so if using #2, those modifications are not included.
34*6f5e9bd5SScott Kruger
35*6f5e9bd5SScott Kruger  Querying:
36*6f5e9bd5SScott Kruger      The dataDict dictionary is then "inverted" to create a dictionary with the
37*6f5e9bd5SScott Kruger      range of field values as keys and list test names as the values.  This
38*6f5e9bd5SScott Kruger      allows fast searching
39*6f5e9bd5SScott Kruger
40*6f5e9bd5SScott Kruger"""
41*6f5e9bd5SScott Kruger
42*6f5e9bd5SScott Krugerdef query(invDict,label):
43*6f5e9bd5SScott Kruger    """
44*6f5e9bd5SScott Kruger    Search the keys using fnmatch to find matching names and return list with
45*6f5e9bd5SScott Kruger    the results
46*6f5e9bd5SScott Kruger    """
47*6f5e9bd5SScott Kruger    results=[]
48*6f5e9bd5SScott Kruger    for key in invDict:
49*6f5e9bd5SScott Kruger        if fnmatch.filter([key],label):
50*6f5e9bd5SScott Kruger            # Do not return values with not unless label itself has not
51*6f5e9bd5SScott Kruger            if label.startswith('!') and not key.startswith('!'): continue
52*6f5e9bd5SScott Kruger            if not label.startswith('!') and key.startswith('!'): continue
53*6f5e9bd5SScott Kruger            results += invDict[key]
54*6f5e9bd5SScott Kruger
55*6f5e9bd5SScott Kruger    return results
56*6f5e9bd5SScott Kruger
57*6f5e9bd5SScott Krugerdef get_inverse_dictionary(dataDict,field,srcdir):
58*6f5e9bd5SScott Kruger    """
59*6f5e9bd5SScott Kruger    Create a dictionary with the values of field as the keys, and the name of
60*6f5e9bd5SScott Kruger    the tests as the results.
61*6f5e9bd5SScott Kruger    """
62*6f5e9bd5SScott Kruger    invDict={}
63*6f5e9bd5SScott Kruger    for root in dataDict:
64*6f5e9bd5SScott Kruger      for exfile in dataDict[root]:
65*6f5e9bd5SScott Kruger        for test in dataDict[root][exfile]:
66*6f5e9bd5SScott Kruger          if field not in dataDict[root][exfile][test]: continue
67*6f5e9bd5SScott Kruger          defroot = testparse.getDefaultOutputFileRoot(test)
68*6f5e9bd5SScott Kruger          name=nameSpace(defroot,os.path.relpath(root,srcdir))
69*6f5e9bd5SScott Kruger          values=dataDict[root][exfile][test][field]
70*6f5e9bd5SScott Kruger
71*6f5e9bd5SScott Kruger          for val in values.split():
72*6f5e9bd5SScott Kruger              if val in invDict:
73*6f5e9bd5SScott Kruger                  invDict[val].append(name)
74*6f5e9bd5SScott Kruger              else:
75*6f5e9bd5SScott Kruger                  invDict[val] = [name]
76*6f5e9bd5SScott Kruger    return invDict
77*6f5e9bd5SScott Kruger
78*6f5e9bd5SScott Krugerdef get_gmakegentest_data(testdir):
79*6f5e9bd5SScott Kruger    """
80*6f5e9bd5SScott Kruger     Write out the dataDict into a pickle file
81*6f5e9bd5SScott Kruger    """
82*6f5e9bd5SScott Kruger    # This needs to be consistent with gmakegentest.py of course
83*6f5e9bd5SScott Kruger    fd = open(os.path.join(testdir,'datatest.pkl'), 'rb')
84*6f5e9bd5SScott Kruger    dataDict=pickle.load(fd)
85*6f5e9bd5SScott Kruger    fd.close()
86*6f5e9bd5SScott Kruger    return dataDict
87*6f5e9bd5SScott Kruger
88*6f5e9bd5SScott Krugerdef walktree(top):
89*6f5e9bd5SScott Kruger    """
90*6f5e9bd5SScott Kruger    Walk a directory tree, starting from 'top'
91*6f5e9bd5SScott Kruger    """
92*6f5e9bd5SScott Kruger    verbose = False
93*6f5e9bd5SScott Kruger    dataDict = {}
94*6f5e9bd5SScott Kruger    alldatafiles = []
95*6f5e9bd5SScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
96*6f5e9bd5SScott Kruger        if "examples" not in root: continue
97*6f5e9bd5SScott Kruger        if root == 'output': continue
98*6f5e9bd5SScott Kruger        if '.dSYM' in root: continue
99*6f5e9bd5SScott Kruger        if verbose: print(root)
100*6f5e9bd5SScott Kruger
101*6f5e9bd5SScott Kruger        dataDict[root] = {}
102*6f5e9bd5SScott Kruger
103*6f5e9bd5SScott Kruger        for exfile in files:
104*6f5e9bd5SScott Kruger            # Ignore emacs files
105*6f5e9bd5SScott Kruger            if exfile.startswith("#") or exfile.startswith(".#"): continue
106*6f5e9bd5SScott Kruger            ext=os.path.splitext(exfile)[1]
107*6f5e9bd5SScott Kruger            if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue
108*6f5e9bd5SScott Kruger
109*6f5e9bd5SScott Kruger            # Convenience
110*6f5e9bd5SScott Kruger            fullex = os.path.join(root, exfile)
111*6f5e9bd5SScott Kruger            if verbose: print('   --> '+fullex)
112*6f5e9bd5SScott Kruger            dataDict[root].update(testparse.parseTestFile(fullex, 0))
113*6f5e9bd5SScott Kruger
114*6f5e9bd5SScott Kruger    return dataDict
115*6f5e9bd5SScott Kruger
116*6f5e9bd5SScott Krugerdef do_query(use_source, startdir, srcdir, testdir, field, label):
117*6f5e9bd5SScott Kruger    """
118*6f5e9bd5SScott Kruger    Do the actual query
119*6f5e9bd5SScott Kruger    This part of the code is placed here instead of main()
120*6f5e9bd5SScott Kruger    to show how one could translate this into ipython/jupyer notebook
121*6f5e9bd5SScott Kruger    commands for more advanced queries
122*6f5e9bd5SScott Kruger    """
123*6f5e9bd5SScott Kruger    # Get dictionary
124*6f5e9bd5SScott Kruger    if use_source:
125*6f5e9bd5SScott Kruger        dataDict=walktree(startdir)
126*6f5e9bd5SScott Kruger    else:
127*6f5e9bd5SScott Kruger        dataDict=get_gmakegentest_data(testdir)
128*6f5e9bd5SScott Kruger
129*6f5e9bd5SScott Kruger    # Get inverse dictionary for searching
130*6f5e9bd5SScott Kruger    invDict=get_inverse_dictionary(dataDict, field, srcdir)
131*6f5e9bd5SScott Kruger
132*6f5e9bd5SScott Kruger    # Now do query
133*6f5e9bd5SScott Kruger    resList=query(invDict, label)
134*6f5e9bd5SScott Kruger
135*6f5e9bd5SScott Kruger    # Print in flat list suitable for use by gmakefile.test
136*6f5e9bd5SScott Kruger    print(' '.join(resList))
137*6f5e9bd5SScott Kruger
138*6f5e9bd5SScott Kruger    return
139*6f5e9bd5SScott Kruger
140*6f5e9bd5SScott Krugerdef main():
141*6f5e9bd5SScott Kruger    parser = optparse.OptionParser(usage="%prog [options] field match_pattern")
142*6f5e9bd5SScott Kruger    parser.add_option('-s', '--startdir', dest='startdir',
143*6f5e9bd5SScott Kruger                      help='Where to start the recursion if not srcdir',
144*6f5e9bd5SScott Kruger                      default='')
145*6f5e9bd5SScott Kruger    parser.add_option('-p', '--petsc_dir', dest='petsc_dir',
146*6f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
147*6f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_DIR'))
148*6f5e9bd5SScott Kruger    parser.add_option('-a', '--petsc-arch', dest='petsc_arch',
149*6f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
150*6f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_ARCH'))
151*6f5e9bd5SScott Kruger    parser.add_option('--srcdir', dest='srcdir',
152*6f5e9bd5SScott Kruger                      help='Set location of sources different from PETSC_DIR/src.  Must be full path.',
153*6f5e9bd5SScott Kruger                      default='src')
154*6f5e9bd5SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',
155*6f5e9bd5SScott Kruger                      help='Test directory if not PETSC_ARCH/tests.  Must be full path',
156*6f5e9bd5SScott Kruger                      default='tests')
157*6f5e9bd5SScott Kruger    parser.add_option('-u', '--use-source', action="store_false",
158*6f5e9bd5SScott Kruger                      dest='use_source',
159*6f5e9bd5SScott Kruger                      help='Query all sources rather than those configured in PETSC_ARCH')
160*6f5e9bd5SScott Kruger
161*6f5e9bd5SScott Kruger    opts, args = parser.parse_args()
162*6f5e9bd5SScott Kruger
163*6f5e9bd5SScott Kruger    # Argument Sanity checks
164*6f5e9bd5SScott Kruger    if len(args) != 2:
165*6f5e9bd5SScott Kruger        parser.print_usage()
166*6f5e9bd5SScott Kruger        print('Arguments: ')
167*6f5e9bd5SScott Kruger        print('  field:          Field to search for; e.g., requires')
168*6f5e9bd5SScott Kruger        print('  match_pattern:  Matching pattern for field; e.g., cuda')
169*6f5e9bd5SScott Kruger        return
170*6f5e9bd5SScott Kruger
171*6f5e9bd5SScott Kruger    # Process arguments and options -- mostly just paths here
172*6f5e9bd5SScott Kruger    field=args[0]
173*6f5e9bd5SScott Kruger    match=args[1]
174*6f5e9bd5SScott Kruger
175*6f5e9bd5SScott Kruger    petsc_dir = opts.petsc_dir
176*6f5e9bd5SScott Kruger    petsc_arch = opts.petsc_arch
177*6f5e9bd5SScott Kruger    petsc_full_arch = os.path.join(petsc_dir, petsc_arch)
178*6f5e9bd5SScott Kruger
179*6f5e9bd5SScott Kruger    if opts.srcdir == 'src':
180*6f5e9bd5SScott Kruger      petsc_full_src = os.path.join(petsc_dir, 'src')
181*6f5e9bd5SScott Kruger    else:
182*6f5e9bd5SScott Kruger      petsc_full_src = opts.srcdir
183*6f5e9bd5SScott Kruger    if opts.testdir == 'tests':
184*6f5e9bd5SScott Kruger      petsc_full_test = os.path.join(petsc_full_arch, 'tests')
185*6f5e9bd5SScott Kruger    else:
186*6f5e9bd5SScott Kruger      petsc_full_test = opts.testdir
187*6f5e9bd5SScott Kruger    if opts.startdir:
188*6f5e9bd5SScott Kruger      startdir=opts.startdir=petsc_full_src
189*6f5e9bd5SScott Kruger    else:
190*6f5e9bd5SScott Kruger      startdir=petsc_full_src
191*6f5e9bd5SScott Kruger
192*6f5e9bd5SScott Kruger    # Options Sanity checks
193*6f5e9bd5SScott Kruger    if not os.path.isdir(petsc_dir):
194*6f5e9bd5SScott Kruger        print("PETSC_DIR must be a directory")
195*6f5e9bd5SScott Kruger        return
196*6f5e9bd5SScott Kruger
197*6f5e9bd5SScott Kruger    if not opts.use_source:
198*6f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_arch):
199*6f5e9bd5SScott Kruger            print("PETSC_DIR/PETSC_ARCH must be a directory")
200*6f5e9bd5SScott Kruger            return
201*6f5e9bd5SScott Kruger        elif not os.path.isdir(petsc_full_test):
202*6f5e9bd5SScott Kruger            print("Testdir must be a directory"+petsc_full_test)
203*6f5e9bd5SScott Kruger            return
204*6f5e9bd5SScott Kruger    else:
205*6f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_src):
206*6f5e9bd5SScott Kruger            print("Source directory must be a directory"+petsc_full_src)
207*6f5e9bd5SScott Kruger            return
208*6f5e9bd5SScott Kruger
209*6f5e9bd5SScott Kruger    # Do the actual query
210*6f5e9bd5SScott Kruger    do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test, field, match)
211*6f5e9bd5SScott Kruger
212*6f5e9bd5SScott Kruger    return
213*6f5e9bd5SScott Kruger
214*6f5e9bd5SScott Kruger
215*6f5e9bd5SScott Krugerif __name__ == "__main__":
216*6f5e9bd5SScott Kruger        main()
217