16f5e9bd5SScott Kruger#!/usr/bin/env python 26f5e9bd5SScott Krugerimport fnmatch 36f5e9bd5SScott Krugerimport glob 46f5e9bd5SScott Krugerimport inspect 56f5e9bd5SScott Krugerimport os 66f5e9bd5SScott Krugerimport optparse 76f5e9bd5SScott Krugerimport pickle 86f5e9bd5SScott Krugerimport re 96f5e9bd5SScott Krugerimport sys 106f5e9bd5SScott Kruger 116f5e9bd5SScott Krugerthisfile = os.path.abspath(inspect.getfile(inspect.currentframe())) 126f5e9bd5SScott Krugerpdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(thisfile))))) 136f5e9bd5SScott Krugersys.path.insert(0, os.path.join(pdir, 'config')) 146f5e9bd5SScott Kruger 156f5e9bd5SScott Krugerimport testparse 166f5e9bd5SScott Krugerfrom gmakegentest import nameSpace 176f5e9bd5SScott Kruger 186f5e9bd5SScott Kruger 196f5e9bd5SScott Kruger""" 206f5e9bd5SScott Kruger Tool for querying the tests. 216f5e9bd5SScott Kruger 226f5e9bd5SScott Kruger Which tests to query? Two options: 236f5e9bd5SScott Kruger 1. Query only the tests that are run for a given configuration. 246f5e9bd5SScott Kruger 2. Query all of the test files in the source directory 256f5e9bd5SScott Kruger For #1: 266f5e9bd5SScott Kruger Use dataDict as written out by gmakegentest.py in $PETSC_ARCH/$TESTBASE 276f5e9bd5SScott Kruger For #2: 286f5e9bd5SScott Kruger Walk the entire tree parsing the files as we go along using testparse. 296f5e9bd5SScott Kruger The tree walker is simpler than what is in gmakegentest.py 306f5e9bd5SScott Kruger 316f5e9bd5SScott Kruger The dataDict follows that generated by testparse. gmakegentest.py does 326f5e9bd5SScott Kruger further manipulations of the dataDict to handle things like for loops 336f5e9bd5SScott Kruger so if using #2, those modifications are not included. 346f5e9bd5SScott Kruger 356f5e9bd5SScott Kruger Querying: 366f5e9bd5SScott Kruger The dataDict dictionary is then "inverted" to create a dictionary with the 376f5e9bd5SScott Kruger range of field values as keys and list test names as the values. This 386f5e9bd5SScott Kruger allows fast searching 396f5e9bd5SScott Kruger 406f5e9bd5SScott Kruger""" 416f5e9bd5SScott Kruger 426f5e9bd5SScott Krugerdef query(invDict,label): 436f5e9bd5SScott Kruger """ 446f5e9bd5SScott Kruger Search the keys using fnmatch to find matching names and return list with 456f5e9bd5SScott Kruger the results 466f5e9bd5SScott Kruger """ 476f5e9bd5SScott Kruger results=[] 485b6dee57SScott Kruger if 'name' in invDict: 495b6dee57SScott Kruger return fnmatch.filter(invDict['name'],label) 505b6dee57SScott Kruger 516f5e9bd5SScott Kruger for key in invDict: 526f5e9bd5SScott Kruger if fnmatch.filter([key],label): 536f5e9bd5SScott Kruger # Do not return values with not unless label itself has not 546f5e9bd5SScott Kruger if label.startswith('!') and not key.startswith('!'): continue 556f5e9bd5SScott Kruger if not label.startswith('!') and key.startswith('!'): continue 566f5e9bd5SScott Kruger results += invDict[key] 576f5e9bd5SScott Kruger 586f5e9bd5SScott Kruger return results 596f5e9bd5SScott Kruger 606f5e9bd5SScott Krugerdef get_inverse_dictionary(dataDict,field,srcdir): 616f5e9bd5SScott Kruger """ 626f5e9bd5SScott Kruger Create a dictionary with the values of field as the keys, and the name of 636f5e9bd5SScott Kruger the tests as the results. 646f5e9bd5SScott Kruger """ 656f5e9bd5SScott Kruger invDict={} 665b6dee57SScott Kruger if field == 'name': invDict['name']=[] 676f5e9bd5SScott Kruger for root in dataDict: 686f5e9bd5SScott Kruger for exfile in dataDict[root]: 696f5e9bd5SScott Kruger for test in dataDict[root][exfile]: 70aec279ffSScott Kruger if test in testparse.buildkeys: continue 716f5e9bd5SScott Kruger defroot = testparse.getDefaultOutputFileRoot(test) 726f5e9bd5SScott Kruger name=nameSpace(defroot,os.path.relpath(root,srcdir)) 735b6dee57SScott Kruger if field == 'name': 745b6dee57SScott Kruger invDict['name'].append(name) 755b6dee57SScott Kruger continue 765b6dee57SScott Kruger if field not in dataDict[root][exfile][test]: continue 776f5e9bd5SScott Kruger values=dataDict[root][exfile][test][field] 786f5e9bd5SScott Kruger 796f5e9bd5SScott Kruger for val in values.split(): 806f5e9bd5SScott Kruger if val in invDict: 816f5e9bd5SScott Kruger invDict[val].append(name) 826f5e9bd5SScott Kruger else: 836f5e9bd5SScott Kruger invDict[val] = [name] 846f5e9bd5SScott Kruger return invDict 856f5e9bd5SScott Kruger 86*4e028dedSScott Krugerdef get_gmakegentest_data(testdir,petsc_dir,petsc_arch): 876f5e9bd5SScott Kruger """ 886f5e9bd5SScott Kruger Write out the dataDict into a pickle file 896f5e9bd5SScott Kruger """ 906f5e9bd5SScott Kruger # This needs to be consistent with gmakegentest.py of course 91*4e028dedSScott Kruger pkl_file=os.path.join(testdir,'datatest.pkl') 92*4e028dedSScott Kruger # If it doesn't exist, then we need to regenerate 93*4e028dedSScott Kruger if not os.path.exists(pkl_file): 94*4e028dedSScott Kruger startdir=os.path.abspath(os.curdir) 95*4e028dedSScott Kruger os.chdir(petsc_dir) 96*4e028dedSScott Kruger args='--petsc-dir='+petsc_dir+' --petsc-arch='+petsc_arch+' --testdir='+testdir 97*4e028dedSScott Kruger buf = os.popen('config/gmakegentest.py '+args).read() 98*4e028dedSScott Kruger os.chdir(startdir) 99*4e028dedSScott Kruger 100*4e028dedSScott Kruger fd = open(pkl_file, 'rb') 1016f5e9bd5SScott Kruger dataDict=pickle.load(fd) 1026f5e9bd5SScott Kruger fd.close() 1036f5e9bd5SScott Kruger return dataDict 1046f5e9bd5SScott Kruger 1056f5e9bd5SScott Krugerdef walktree(top): 1066f5e9bd5SScott Kruger """ 1076f5e9bd5SScott Kruger Walk a directory tree, starting from 'top' 1086f5e9bd5SScott Kruger """ 1096f5e9bd5SScott Kruger verbose = False 1106f5e9bd5SScott Kruger dataDict = {} 1116f5e9bd5SScott Kruger alldatafiles = [] 1126f5e9bd5SScott Kruger for root, dirs, files in os.walk(top, topdown=False): 1136f5e9bd5SScott Kruger if "examples" not in root: continue 1146f5e9bd5SScott Kruger if root == 'output': continue 1156f5e9bd5SScott Kruger if '.dSYM' in root: continue 1166f5e9bd5SScott Kruger if verbose: print(root) 1176f5e9bd5SScott Kruger 1186f5e9bd5SScott Kruger dataDict[root] = {} 1196f5e9bd5SScott Kruger 1206f5e9bd5SScott Kruger for exfile in files: 1216f5e9bd5SScott Kruger # Ignore emacs files 1226f5e9bd5SScott Kruger if exfile.startswith("#") or exfile.startswith(".#"): continue 1236f5e9bd5SScott Kruger ext=os.path.splitext(exfile)[1] 1246f5e9bd5SScott Kruger if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue 1256f5e9bd5SScott Kruger 1266f5e9bd5SScott Kruger # Convenience 1276f5e9bd5SScott Kruger fullex = os.path.join(root, exfile) 1286f5e9bd5SScott Kruger if verbose: print(' --> '+fullex) 1296f5e9bd5SScott Kruger dataDict[root].update(testparse.parseTestFile(fullex, 0)) 1306f5e9bd5SScott Kruger 1316f5e9bd5SScott Kruger return dataDict 1326f5e9bd5SScott Kruger 133*4e028dedSScott Krugerdef do_query(use_source, startdir, srcdir, testdir, petsc_dir, petsc_arch, field, label): 1346f5e9bd5SScott Kruger """ 1356f5e9bd5SScott Kruger Do the actual query 1366f5e9bd5SScott Kruger This part of the code is placed here instead of main() 1376f5e9bd5SScott Kruger to show how one could translate this into ipython/jupyer notebook 1386f5e9bd5SScott Kruger commands for more advanced queries 1396f5e9bd5SScott Kruger """ 1406f5e9bd5SScott Kruger # Get dictionary 1416f5e9bd5SScott Kruger if use_source: 1426f5e9bd5SScott Kruger dataDict=walktree(startdir) 1436f5e9bd5SScott Kruger else: 144*4e028dedSScott Kruger dataDict=get_gmakegentest_data(testdir, petsc_dir, petsc_arch) 1456f5e9bd5SScott Kruger 1466f5e9bd5SScott Kruger # Get inverse dictionary for searching 1476f5e9bd5SScott Kruger invDict=get_inverse_dictionary(dataDict, field, srcdir) 1485b6dee57SScott Kruger #print(invDict) 1496f5e9bd5SScott Kruger 1506f5e9bd5SScott Kruger # Now do query 1516f5e9bd5SScott Kruger resList=query(invDict, label) 1526f5e9bd5SScott Kruger 1536f5e9bd5SScott Kruger # Print in flat list suitable for use by gmakefile.test 1546f5e9bd5SScott Kruger print(' '.join(resList)) 1556f5e9bd5SScott Kruger 1566f5e9bd5SScott Kruger return 1576f5e9bd5SScott Kruger 1586f5e9bd5SScott Krugerdef main(): 1596f5e9bd5SScott Kruger parser = optparse.OptionParser(usage="%prog [options] field match_pattern") 1606f5e9bd5SScott Kruger parser.add_option('-s', '--startdir', dest='startdir', 1616f5e9bd5SScott Kruger help='Where to start the recursion if not srcdir', 1626f5e9bd5SScott Kruger default='') 163aec279ffSScott Kruger parser.add_option('-p', '--petsc-dir', dest='petsc_dir', 164aec279ffSScott Kruger help='Set PETSC_DIR different from environment', 1656f5e9bd5SScott Kruger default=os.environ.get('PETSC_DIR')) 1666f5e9bd5SScott Kruger parser.add_option('-a', '--petsc-arch', dest='petsc_arch', 1676f5e9bd5SScott Kruger help='Set PETSC_ARCH different from environment', 1686f5e9bd5SScott Kruger default=os.environ.get('PETSC_ARCH')) 1696f5e9bd5SScott Kruger parser.add_option('--srcdir', dest='srcdir', 1706f5e9bd5SScott Kruger help='Set location of sources different from PETSC_DIR/src. Must be full path.', 1716f5e9bd5SScott Kruger default='src') 1726f5e9bd5SScott Kruger parser.add_option('-t', '--testdir', dest='testdir', 1736f5e9bd5SScott Kruger help='Test directory if not PETSC_ARCH/tests. Must be full path', 1746f5e9bd5SScott Kruger default='tests') 1756f5e9bd5SScott Kruger parser.add_option('-u', '--use-source', action="store_false", 1766f5e9bd5SScott Kruger dest='use_source', 1776f5e9bd5SScott Kruger help='Query all sources rather than those configured in PETSC_ARCH') 1786f5e9bd5SScott Kruger 1796f5e9bd5SScott Kruger opts, args = parser.parse_args() 1806f5e9bd5SScott Kruger 1816f5e9bd5SScott Kruger # Argument Sanity checks 1826f5e9bd5SScott Kruger if len(args) != 2: 1836f5e9bd5SScott Kruger parser.print_usage() 1846f5e9bd5SScott Kruger print('Arguments: ') 1856f5e9bd5SScott Kruger print(' field: Field to search for; e.g., requires') 1865b6dee57SScott Kruger print(' To just match names, use "name"') 1876f5e9bd5SScott Kruger print(' match_pattern: Matching pattern for field; e.g., cuda') 1886f5e9bd5SScott Kruger return 1896f5e9bd5SScott Kruger 1906f5e9bd5SScott Kruger # Process arguments and options -- mostly just paths here 1916f5e9bd5SScott Kruger field=args[0] 1926f5e9bd5SScott Kruger match=args[1] 1936f5e9bd5SScott Kruger 1946f5e9bd5SScott Kruger petsc_dir = opts.petsc_dir 1956f5e9bd5SScott Kruger petsc_arch = opts.petsc_arch 1966f5e9bd5SScott Kruger petsc_full_arch = os.path.join(petsc_dir, petsc_arch) 1976f5e9bd5SScott Kruger 1986f5e9bd5SScott Kruger if opts.srcdir == 'src': 1996f5e9bd5SScott Kruger petsc_full_src = os.path.join(petsc_dir, 'src') 2006f5e9bd5SScott Kruger else: 2016f5e9bd5SScott Kruger petsc_full_src = opts.srcdir 2026f5e9bd5SScott Kruger if opts.testdir == 'tests': 2036f5e9bd5SScott Kruger petsc_full_test = os.path.join(petsc_full_arch, 'tests') 2046f5e9bd5SScott Kruger else: 2056f5e9bd5SScott Kruger petsc_full_test = opts.testdir 2066f5e9bd5SScott Kruger if opts.startdir: 2076f5e9bd5SScott Kruger startdir=opts.startdir=petsc_full_src 2086f5e9bd5SScott Kruger else: 2096f5e9bd5SScott Kruger startdir=petsc_full_src 2106f5e9bd5SScott Kruger 2116f5e9bd5SScott Kruger # Options Sanity checks 2126f5e9bd5SScott Kruger if not os.path.isdir(petsc_dir): 2136f5e9bd5SScott Kruger print("PETSC_DIR must be a directory") 2146f5e9bd5SScott Kruger return 2156f5e9bd5SScott Kruger 2166f5e9bd5SScott Kruger if not opts.use_source: 2176f5e9bd5SScott Kruger if not os.path.isdir(petsc_full_arch): 2186f5e9bd5SScott Kruger print("PETSC_DIR/PETSC_ARCH must be a directory") 2196f5e9bd5SScott Kruger return 2206f5e9bd5SScott Kruger elif not os.path.isdir(petsc_full_test): 2216f5e9bd5SScott Kruger print("Testdir must be a directory"+petsc_full_test) 2226f5e9bd5SScott Kruger return 2236f5e9bd5SScott Kruger else: 2246f5e9bd5SScott Kruger if not os.path.isdir(petsc_full_src): 2256f5e9bd5SScott Kruger print("Source directory must be a directory"+petsc_full_src) 2266f5e9bd5SScott Kruger return 2276f5e9bd5SScott Kruger 2286f5e9bd5SScott Kruger # Do the actual query 229*4e028dedSScott Kruger do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test, 230*4e028dedSScott Kruger petsc_dir, petsc_arch, field, match) 2316f5e9bd5SScott Kruger 2326f5e9bd5SScott Kruger return 2336f5e9bd5SScott Kruger 2346f5e9bd5SScott Kruger 2356f5e9bd5SScott Krugerif __name__ == "__main__": 2366f5e9bd5SScott Kruger main() 237