xref: /petsc/config/query_tests.py (revision 3be2e2fd51614bfbd789968ca6fbd36d439d7250)
1df3bd252SSatish Balay#!/usr/bin/env python3
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
4285bc9deeSScott Krugerdef isFile(maybeFile):
4385bc9deeSScott Kruger  ext=os.path.splitext(maybeFile)[1]
4485bc9deeSScott Kruger  if not ext: return False
4585bc9deeSScott Kruger  if ext not in ['.c','.cxx','.cpp','F90','F','cu']: return False
4685bc9deeSScott Kruger  return True
4785bc9deeSScott Kruger
4885bc9deeSScott Krugerdef pathToLabel(path):
4985bc9deeSScott Kruger  """
5085bc9deeSScott Kruger  Because the scripts have a non-unique naming, the pretty-printing
5185bc9deeSScott Kruger  needs to convey the srcdir and srcfile.  There are two ways of doing this.
5285bc9deeSScott Kruger  """
5385bc9deeSScott Kruger  # Strip off any top-level directories or spaces
5485bc9deeSScott Kruger  path=path.strip().replace(pdir,'')
5585bc9deeSScott Kruger  path=path.replace('src/','')
5685bc9deeSScott Kruger  if isFile(path):
5785bc9deeSScott Kruger    prefix=os.path.dirname(path).replace("/","_")
5885bc9deeSScott Kruger    suffix=os.path.splitext(os.path.basename(path))[0]
5985bc9deeSScott Kruger    label=prefix+"-"+suffix+'_*'
6085bc9deeSScott Kruger  else:
6185bc9deeSScott Kruger    path=path.rstrip('/')
629ea87190SJacob Faibussowitsch    label=path.replace("/","_").replace('tests_','tests-').replace('tutorials_','tutorials-')
6385bc9deeSScott Kruger  return label
6485bc9deeSScott Kruger
6585bc9deeSScott Krugerdef get_value(varset):
6685bc9deeSScott Kruger  """
6785bc9deeSScott Kruger  Searching args is a bit funky:
6885bc9deeSScott Kruger  Consider
6985bc9deeSScott Kruger      args:  -ksp_monitor_short -pc_type ml -ksp_max_it 3
7085bc9deeSScott Kruger  Search terms are:
7185bc9deeSScott Kruger    ksp_monitor, 'pc_type ml', ksp_max_it
7285bc9deeSScott Kruger  Also ignore all loops
7385bc9deeSScott Kruger    -pc_fieldsplit_diag_use_amat {{0 1}}
7485bc9deeSScott Kruger  Gives: pc_fieldsplit_diag_use_amat as the search term
7585bc9deeSScott Kruger  Also ignore -f ...  (use matrices from file) because I'll assume
7685bc9deeSScott Kruger   that this kind of information isn't needed for testing.  If it's
7785bc9deeSScott Kruger   a separate search than just grep it
7885bc9deeSScott Kruger  """
7985bc9deeSScott Kruger  if varset.startswith('-f '): return None
8085bc9deeSScott Kruger
8185bc9deeSScott Kruger  # First  remove loops
8285bc9deeSScott Kruger  value=re.sub('{{.*}}','',varset)
8385bc9deeSScott Kruger  # Next remove -
8485bc9deeSScott Kruger  value=varset.lstrip("-")
8585bc9deeSScott Kruger  # Get rid of numbers
8685bc9deeSScott Kruger  value=re.sub(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",'',value)
8785bc9deeSScott Kruger  # return without spaces
8885bc9deeSScott Kruger  return value.strip()
8985bc9deeSScott Kruger
9085bc9deeSScott Krugerdef query(invDict,fields,labels):
916f5e9bd5SScott Kruger    """
926f5e9bd5SScott Kruger    Search the keys using fnmatch to find matching names and return list with
936f5e9bd5SScott Kruger    the results
946f5e9bd5SScott Kruger    """
95d5b43468SJose E. Roman    setlist=[]  # setlist is a list of lists that set operations will operate on
9685bc9deeSScott Kruger    llist=labels.replace('|',',').split(',')
9785bc9deeSScott Kruger    i=-1
9885bc9deeSScott Kruger    for field in fields.replace('|',',').split(','):
9985bc9deeSScott Kruger        i+=1
10085bc9deeSScott Kruger        label=llist[i]
10185bc9deeSScott Kruger        if field == 'name':
10285bc9deeSScott Kruger            if '/' in label:
10385bc9deeSScott Kruger              label=pathToLabel(label)
104f538e455SScott Kruger            elif label.startswith('src'):
105f538e455SScott Kruger                  label=label.lstrip('src').lstrip('*')
10685bc9deeSScott Kruger            setlist.append(fnmatch.filter(invDict['name'],label))
10785bc9deeSScott Kruger            continue
1085b6dee57SScott Kruger
10985bc9deeSScott Kruger        foundLabel=False   # easy to do if you misspell argument search
110ca84c248SScott Kruger        label=label.lower()
11185bc9deeSScott Kruger        for key in invDict[field]:
112ca84c248SScott Kruger            if fnmatch.filter([key.lower()],label):
11385bc9deeSScott Kruger              foundLabel=True
1146f5e9bd5SScott Kruger              # Do not return values with not unless label itself has not
1156f5e9bd5SScott Kruger              if label.startswith('!') and not key.startswith('!'): continue
1166f5e9bd5SScott Kruger              if not label.startswith('!') and key.startswith('!'): continue
11785bc9deeSScott Kruger              setlist.append(invDict[field][key])
11885bc9deeSScott Kruger        if not foundLabel:
11985bc9deeSScott Kruger          setlist.append([])
1206f5e9bd5SScott Kruger
12185bc9deeSScott Kruger    # Now process the union and intersection operators based on setlist
12285bc9deeSScott Kruger    allresults=[]
12385bc9deeSScott Kruger    # Union
12485bc9deeSScott Kruger    i=-1
12585bc9deeSScott Kruger    for ufield in fields.split(','):
12685bc9deeSScott Kruger       i+=1
12785bc9deeSScott Kruger       if '|' in ufield:
12885bc9deeSScott Kruger         # Intersection
12985bc9deeSScott Kruger         label=llist[i]
13085bc9deeSScott Kruger         results=set(setlist[i])
13185bc9deeSScott Kruger         for field in ufield.split('|')[1:]:
13285bc9deeSScott Kruger             i+=1
13385bc9deeSScott Kruger             label=llist[i]
13485bc9deeSScott Kruger             results=results.intersection(set(setlist[i]))
13585bc9deeSScott Kruger         allresults+=list(results)
13685bc9deeSScott Kruger       else:
13785bc9deeSScott Kruger         allresults+=setlist[i]
1386f5e9bd5SScott Kruger
13985bc9deeSScott Kruger    # remove duplicate entries and sort to give consistent results
14085bc9deeSScott Kruger    uniqlist=list(set(allresults))
14185bc9deeSScott Kruger    uniqlist.sort()
14285bc9deeSScott Kruger    return  uniqlist
14385bc9deeSScott Kruger
14485bc9deeSScott Krugerdef get_inverse_dictionary(dataDict,fields,srcdir):
1456f5e9bd5SScott Kruger    """
1466f5e9bd5SScott Kruger    Create a dictionary with the values of field as the keys, and the name of
1476f5e9bd5SScott Kruger    the tests as the results.
1486f5e9bd5SScott Kruger    """
1496f5e9bd5SScott Kruger    invDict={}
15085bc9deeSScott Kruger    # Comma-delimited lists denote union
15185bc9deeSScott Kruger    for field in fields.replace('|',',').split(','):
15285bc9deeSScott Kruger        if field not in invDict:
15385bc9deeSScott Kruger            if field == 'name':
15485bc9deeSScott Kruger                 invDict[field]=[]   # List for ease
15585bc9deeSScott Kruger            else:
15685bc9deeSScott Kruger                 invDict[field]={}
1576f5e9bd5SScott Kruger        for root in dataDict:
1586f5e9bd5SScott Kruger          for exfile in dataDict[root]:
1596f5e9bd5SScott Kruger            for test in dataDict[root][exfile]:
160aec279ffSScott Kruger              if test in testparse.buildkeys: continue
1616f5e9bd5SScott Kruger              defroot = testparse.getDefaultOutputFileRoot(test)
16285bc9deeSScott Kruger              fname=nameSpace(defroot,os.path.relpath(root,srcdir))
1635b6dee57SScott Kruger              if field == 'name':
16485bc9deeSScott Kruger                  invDict['name'].append(fname)
1655b6dee57SScott Kruger                  continue
1665b6dee57SScott Kruger              if field not in dataDict[root][exfile][test]: continue
1676f5e9bd5SScott Kruger              values=dataDict[root][exfile][test][field]
1686f5e9bd5SScott Kruger
16985bc9deeSScott Kruger              if not field == 'args' and not field == 'diff_args':
1706f5e9bd5SScott Kruger                for val in values.split():
17185bc9deeSScott Kruger                    if val in invDict[field]:
17285bc9deeSScott Kruger                        invDict[field][val].append(fname)
1736f5e9bd5SScott Kruger                    else:
17485bc9deeSScott Kruger                        invDict[field][val] = [fname]
17585bc9deeSScott Kruger              else:
17685bc9deeSScott Kruger                # Args are funky.
177*3be2e2fdSJose E. Roman                for varset in re.split(r'(^|\W)-(?=[a-zA-Z])',values):
17885bc9deeSScott Kruger                  val=get_value(varset)
17985bc9deeSScott Kruger                  if not val: continue
18085bc9deeSScott Kruger                  if val in invDict[field]:
18185bc9deeSScott Kruger                    invDict[field][val].append(fname)
18285bc9deeSScott Kruger                  else:
18385bc9deeSScott Kruger                    invDict[field][val] = [fname]
18485bc9deeSScott Kruger        # remove duplicate entries (multiple test/file)
18585bc9deeSScott Kruger        if not field == 'name':
18685bc9deeSScott Kruger          for val in invDict[field]:
18785bc9deeSScott Kruger            invDict[field][val]=list(set(invDict[field][val]))
18885bc9deeSScott Kruger
1896f5e9bd5SScott Kruger    return invDict
1906f5e9bd5SScott Kruger
1914e028dedSScott Krugerdef get_gmakegentest_data(testdir,petsc_dir,petsc_arch):
1926f5e9bd5SScott Kruger    """
1936f5e9bd5SScott Kruger     Write out the dataDict into a pickle file
1946f5e9bd5SScott Kruger    """
1956f5e9bd5SScott Kruger    # This needs to be consistent with gmakegentest.py of course
1964e028dedSScott Kruger    pkl_file=os.path.join(testdir,'datatest.pkl')
1974e028dedSScott Kruger    # If it doesn't exist, then we need to regenerate
1984e028dedSScott Kruger    if not os.path.exists(pkl_file):
1994e028dedSScott Kruger      startdir=os.path.abspath(os.curdir)
2004e028dedSScott Kruger      os.chdir(petsc_dir)
2014e028dedSScott Kruger      args='--petsc-dir='+petsc_dir+' --petsc-arch='+petsc_arch+' --testdir='+testdir
2024e028dedSScott Kruger      buf = os.popen('config/gmakegentest.py '+args).read()
2034e028dedSScott Kruger      os.chdir(startdir)
2044e028dedSScott Kruger
2054e028dedSScott Kruger    fd = open(pkl_file, 'rb')
2066f5e9bd5SScott Kruger    dataDict=pickle.load(fd)
2076f5e9bd5SScott Kruger    fd.close()
2086f5e9bd5SScott Kruger    return dataDict
2096f5e9bd5SScott Kruger
2106f5e9bd5SScott Krugerdef walktree(top):
2116f5e9bd5SScott Kruger    """
2126f5e9bd5SScott Kruger    Walk a directory tree, starting from 'top'
2136f5e9bd5SScott Kruger    """
2146f5e9bd5SScott Kruger    verbose = False
2156f5e9bd5SScott Kruger    dataDict = {}
2166f5e9bd5SScott Kruger    alldatafiles = []
2176f5e9bd5SScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
2186f5e9bd5SScott Kruger        if root == 'output': continue
2196f5e9bd5SScott Kruger        if '.dSYM' in root: continue
2206f5e9bd5SScott Kruger        if verbose: print(root)
2216f5e9bd5SScott Kruger
2226f5e9bd5SScott Kruger        dataDict[root] = {}
2236f5e9bd5SScott Kruger
2246f5e9bd5SScott Kruger        for exfile in files:
2256f5e9bd5SScott Kruger            # Ignore emacs files
2266f5e9bd5SScott Kruger            if exfile.startswith("#") or exfile.startswith(".#"): continue
2276f5e9bd5SScott Kruger            ext=os.path.splitext(exfile)[1]
2286f5e9bd5SScott Kruger            if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue
2296f5e9bd5SScott Kruger
2306f5e9bd5SScott Kruger            # Convenience
2316f5e9bd5SScott Kruger            fullex = os.path.join(root, exfile)
2326f5e9bd5SScott Kruger            if verbose: print('   --> '+fullex)
2336f5e9bd5SScott Kruger            dataDict[root].update(testparse.parseTestFile(fullex, 0))
2346f5e9bd5SScott Kruger
2356f5e9bd5SScott Kruger    return dataDict
2366f5e9bd5SScott Kruger
23785bc9deeSScott Krugerdef do_query(use_source, startdir, srcdir, testdir, petsc_dir, petsc_arch,
23885bc9deeSScott Kruger             fields, labels, searchin):
2396f5e9bd5SScott Kruger    """
2406f5e9bd5SScott Kruger    Do the actual query
2416f5e9bd5SScott Kruger    This part of the code is placed here instead of main()
2426f5e9bd5SScott Kruger    to show how one could translate this into ipython/jupyer notebook
2436f5e9bd5SScott Kruger    commands for more advanced queries
2446f5e9bd5SScott Kruger    """
2456f5e9bd5SScott Kruger    # Get dictionary
2466f5e9bd5SScott Kruger    if use_source:
2476f5e9bd5SScott Kruger        dataDict=walktree(startdir)
2486f5e9bd5SScott Kruger    else:
2494e028dedSScott Kruger        dataDict=get_gmakegentest_data(testdir, petsc_dir, petsc_arch)
2506f5e9bd5SScott Kruger
2516f5e9bd5SScott Kruger    # Get inverse dictionary for searching
25285bc9deeSScott Kruger    invDict=get_inverse_dictionary(dataDict, fields, srcdir)
2536f5e9bd5SScott Kruger
2546f5e9bd5SScott Kruger    # Now do query
25585bc9deeSScott Kruger    resList=query(invDict, fields, labels)
25685bc9deeSScott Kruger
25785bc9deeSScott Kruger    # Filter results using searchin
25885bc9deeSScott Kruger    newresList=[]
25985bc9deeSScott Kruger    if searchin.strip():
260be89fe9eSScott Kruger        if not searchin.startswith('!'):
26185bc9deeSScott Kruger            for key in resList:
26285bc9deeSScott Kruger                if fnmatch.filter([key],searchin):
26385bc9deeSScott Kruger                  newresList.append(key)
264be89fe9eSScott Kruger        else:
265be89fe9eSScott Kruger            for key in resList:
266be89fe9eSScott Kruger                if not fnmatch.filter([key],searchin[1:]):
267be89fe9eSScott Kruger                  newresList.append(key)
26885bc9deeSScott Kruger        resList=newresList
2696f5e9bd5SScott Kruger
2706f5e9bd5SScott Kruger    # Print in flat list suitable for use by gmakefile.test
2716f5e9bd5SScott Kruger    print(' '.join(resList))
2726f5e9bd5SScott Kruger
2736f5e9bd5SScott Kruger    return
2746f5e9bd5SScott Kruger
2759ea87190SJacob Faibussowitschdef expand_path_like(petscdir,petscarch,pathlike):
2769ea87190SJacob Faibussowitsch    def remove_prefix(text,prefix):
2779ea87190SJacob Faibussowitsch        return text[text.startswith(prefix) and len(prefix):]
2789ea87190SJacob Faibussowitsch
2799ea87190SJacob Faibussowitsch    # expand user second, as expandvars may insert a '~'
2809ea87190SJacob Faibussowitsch    string = os.path.expanduser(os.path.expandvars(pathlike))
2819ea87190SJacob Faibussowitsch    # if the dirname check succeeds then likely we have a glob expression
2829ea87190SJacob Faibussowitsch    pardir = os.path.dirname(string)
2839ea87190SJacob Faibussowitsch    if os.path.exists(pardir):
2849ea87190SJacob Faibussowitsch        suffix   = string.replace(pardir,'') # get whatever is left over
2859ea87190SJacob Faibussowitsch        pathlike = remove_prefix(os.path.relpath(os.path.abspath(pardir),petscdir),'.'+os.path.sep)
2869ea87190SJacob Faibussowitsch        if petscarch == '':
2879ea87190SJacob Faibussowitsch            pathlike = pathlike.replace(os.path.sep.join(('share','petsc','examples'))+'/','')
2889ea87190SJacob Faibussowitsch        pathlike += suffix
2899ea87190SJacob Faibussowitsch    return pathlike
2909ea87190SJacob Faibussowitsch
2916f5e9bd5SScott Krugerdef main():
2926f5e9bd5SScott Kruger    parser = optparse.OptionParser(usage="%prog [options] field match_pattern")
2936f5e9bd5SScott Kruger    parser.add_option('-s', '--startdir', dest='startdir',
2946f5e9bd5SScott Kruger                      help='Where to start the recursion if not srcdir',
2956f5e9bd5SScott Kruger                      default='')
296aec279ffSScott Kruger    parser.add_option('-p', '--petsc-dir', dest='petsc_dir',
297aec279ffSScott Kruger                      help='Set PETSC_DIR different from environment',
2986f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_DIR'))
2996f5e9bd5SScott Kruger    parser.add_option('-a', '--petsc-arch', dest='petsc_arch',
3006f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
3016f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_ARCH'))
3026f5e9bd5SScott Kruger    parser.add_option('--srcdir', dest='srcdir',
3036f5e9bd5SScott Kruger                      help='Set location of sources different from PETSC_DIR/src.  Must be full path.',
3046f5e9bd5SScott Kruger                      default='src')
3056f5e9bd5SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',
3066f5e9bd5SScott Kruger                      help='Test directory if not PETSC_ARCH/tests.  Must be full path',
3076f5e9bd5SScott Kruger                      default='tests')
3086f5e9bd5SScott Kruger    parser.add_option('-u', '--use-source', action="store_false",
3096f5e9bd5SScott Kruger                      dest='use_source',
3106f5e9bd5SScott Kruger                      help='Query all sources rather than those configured in PETSC_ARCH')
31185bc9deeSScott Kruger    parser.add_option('-i', '--searchin', dest='searchin',
31285bc9deeSScott Kruger                      help='Filter results from the arguments',
31385bc9deeSScott Kruger                      default='')
3146f5e9bd5SScott Kruger
3156f5e9bd5SScott Kruger    opts, args = parser.parse_args()
3166f5e9bd5SScott Kruger
3176f5e9bd5SScott Kruger    # Argument Sanity checks
3186f5e9bd5SScott Kruger    if len(args) != 2:
3196f5e9bd5SScott Kruger        parser.print_usage()
3206f5e9bd5SScott Kruger        print('Arguments: ')
3216f5e9bd5SScott Kruger        print('  field:          Field to search for; e.g., requires')
3225b6dee57SScott Kruger        print('                  To just match names, use "name"')
3236f5e9bd5SScott Kruger        print('  match_pattern:  Matching pattern for field; e.g., cuda')
3246f5e9bd5SScott Kruger        return
3256f5e9bd5SScott Kruger
3263c5439e2SJacob Faibussowitsch    def shell_unquote(string):
3273c5439e2SJacob Faibussowitsch      """
3283c5439e2SJacob Faibussowitsch      Remove quotes from STRING. Useful in the case where you need to bury escaped quotes in a query
3293c5439e2SJacob Faibussowitsch      string in order to escape shell characters. For example:
3303c5439e2SJacob Faibussowitsch
3313c5439e2SJacob Faibussowitsch      $ make test query='foo,bar' queryval='requires|name'
3323c5439e2SJacob Faibussowitsch      /usr/bin/bash: line 1: name: command not found
3333c5439e2SJacob Faibussowitsch
3343c5439e2SJacob Faibussowitsch      While the original shell does not see the pipe character, the actual query is done via a second
3353c5439e2SJacob Faibussowitsch      shell, which is (literally) passed '$(queryval)', i.e. 'queryval='requires|name'' when expanded.
3363c5439e2SJacob Faibussowitsch      Note the fact that the expansion cancels out the quoting!!!
3373c5439e2SJacob Faibussowitsch
3383c5439e2SJacob Faibussowitsch      You can fix this by doing:
3393c5439e2SJacob Faibussowitsch
3403c5439e2SJacob Faibussowitsch      $ make test query='foo,bar' queryval='"requires|name"'
3413c5439e2SJacob Faibussowitsch
3423c5439e2SJacob Faibussowitsch      However this then shows up here as labels = 'queryval="requires|name"'. So we need to remove the
3433c5439e2SJacob Faibussowitsch      '"'. Applying shlex.split() on this returns:
3443c5439e2SJacob Faibussowitsch
3453c5439e2SJacob Faibussowitsch      >>> shlex.split('queryval="requires|name"')
3463c5439e2SJacob Faibussowitsch      ['queryval=requires|name']
3473c5439e2SJacob Faibussowitsch
3483c5439e2SJacob Faibussowitsch      And voila. Note also that:
3493c5439e2SJacob Faibussowitsch
3503c5439e2SJacob Faibussowitsch      >>> shlex.split('queryval=requires|name')
3513c5439e2SJacob Faibussowitsch      ['queryval=requires|name']
3523c5439e2SJacob Faibussowitsch      """
3533c5439e2SJacob Faibussowitsch      import shlex
3543c5439e2SJacob Faibussowitsch
3553c5439e2SJacob Faibussowitsch      if string:
3563c5439e2SJacob Faibussowitsch        ret = shlex.split(string)
3573c5439e2SJacob Faibussowitsch        assert len(ret) == 1, "Dont know what to do if shlex.split() produces more than 1 value?"
3583c5439e2SJacob Faibussowitsch        string = ret[0]
3593c5439e2SJacob Faibussowitsch      return string
3603c5439e2SJacob Faibussowitsch
361168c8686SJacob Faibussowitsch    def alternate_command_preprocess(string):
362168c8686SJacob Faibussowitsch      """
363168c8686SJacob Faibussowitsch      Replace the alternate versions in STRING with the regular variants
364168c8686SJacob Faibussowitsch      """
365168c8686SJacob Faibussowitsch      return string.replace('%OR%', '|').replace('%AND%', ',').replace('%NEG%', '!')
366168c8686SJacob Faibussowitsch
3676f5e9bd5SScott Kruger    # Process arguments and options -- mostly just paths here
368168c8686SJacob Faibussowitsch    field=alternate_command_preprocess(shell_unquote(args[0]))
369168c8686SJacob Faibussowitsch    match=alternate_command_preprocess(shell_unquote(args[1]))
37085bc9deeSScott Kruger    searchin=opts.searchin
3716f5e9bd5SScott Kruger
3726f5e9bd5SScott Kruger    petsc_dir = opts.petsc_dir
3736f5e9bd5SScott Kruger    petsc_arch = opts.petsc_arch
3746f5e9bd5SScott Kruger    petsc_full_arch = os.path.join(petsc_dir, petsc_arch)
3756f5e9bd5SScott Kruger
37658780e5dSStefano Zampini    if petsc_arch == '':
37758780e5dSStefano Zampini        petsc_full_src = os.path.join(petsc_dir, 'share', 'petsc', 'examples', 'src')
37858780e5dSStefano Zampini    else:
3796f5e9bd5SScott Kruger      if opts.srcdir == 'src':
3806f5e9bd5SScott Kruger        petsc_full_src = os.path.join(petsc_dir, 'src')
3816f5e9bd5SScott Kruger      else:
3826f5e9bd5SScott Kruger        petsc_full_src = opts.srcdir
3836f5e9bd5SScott Kruger    if opts.testdir == 'tests':
3846f5e9bd5SScott Kruger      petsc_full_test = os.path.join(petsc_full_arch, 'tests')
3856f5e9bd5SScott Kruger    else:
3866f5e9bd5SScott Kruger      petsc_full_test = opts.testdir
3876f5e9bd5SScott Kruger    if opts.startdir:
3886f5e9bd5SScott Kruger      startdir=opts.startdir=petsc_full_src
3896f5e9bd5SScott Kruger    else:
3906f5e9bd5SScott Kruger      startdir=petsc_full_src
3916f5e9bd5SScott Kruger
3926f5e9bd5SScott Kruger    # Options Sanity checks
3936f5e9bd5SScott Kruger    if not os.path.isdir(petsc_dir):
3946f5e9bd5SScott Kruger        print("PETSC_DIR must be a directory")
3956f5e9bd5SScott Kruger        return
3966f5e9bd5SScott Kruger
3976f5e9bd5SScott Kruger    if not opts.use_source:
3986f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_arch):
3996f5e9bd5SScott Kruger            print("PETSC_DIR/PETSC_ARCH must be a directory")
4006f5e9bd5SScott Kruger            return
4016f5e9bd5SScott Kruger        elif not os.path.isdir(petsc_full_test):
4026f5e9bd5SScott Kruger            print("Testdir must be a directory"+petsc_full_test)
4036f5e9bd5SScott Kruger            return
4046f5e9bd5SScott Kruger    else:
4056f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_src):
4066f5e9bd5SScott Kruger            print("Source directory must be a directory"+petsc_full_src)
4076f5e9bd5SScott Kruger            return
4086f5e9bd5SScott Kruger
4099ea87190SJacob Faibussowitsch    match = expand_path_like(petsc_dir,petsc_arch,match)
4109ea87190SJacob Faibussowitsch
4116f5e9bd5SScott Kruger    # Do the actual query
4124e028dedSScott Kruger    do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test,
41385bc9deeSScott Kruger             petsc_dir, petsc_arch, field, match, searchin)
4146f5e9bd5SScott Kruger
4156f5e9bd5SScott Kruger    return
4166f5e9bd5SScott Kruger
4176f5e9bd5SScott Kruger
4186f5e9bd5SScott Krugerif __name__ == "__main__":
4196f5e9bd5SScott Kruger        main()
420