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