xref: /petsc/config/query_tests.py (revision 84533492958d91be3ed11cc87e27dc7439057aaa)
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()))
12*84533492SBarry Smithpetscdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(thisfile)))))
13*84533492SBarry Smithsys.path.insert(0, os.path.join(petscdir, 'config'))
146f5e9bd5SScott Kruger
156f5e9bd5SScott Krugerimport testparse
166f5e9bd5SScott Krugerfrom gmakegentest import nameSpace
176f5e9bd5SScott Kruger
186f5e9bd5SScott Kruger
196f5e9bd5SScott Kruger"""
20*84533492SBarry Smith   This is used by gmakefile.test for the following searches
21*84533492SBarry Smith
22*84533492SBarry Smith  - make test search=X (or s=X)
23*84533492SBarry Smith  - make test query=X (or q=X) queryval=Y (or qv=Y)
24*84533492SBarry Smith
256f5e9bd5SScott Kruger
266f5e9bd5SScott Kruger  Which tests to query?  Two options:
276f5e9bd5SScott Kruger      1. Query only the tests that are run for a given configuration.
286f5e9bd5SScott Kruger      2. Query all of the test files in the source directory
296f5e9bd5SScott Kruger  For #1:
306f5e9bd5SScott Kruger     Use dataDict as written out by gmakegentest.py in $PETSC_ARCH/$TESTBASE
316f5e9bd5SScott Kruger  For #2:
326f5e9bd5SScott Kruger     Walk the entire tree parsing the files as we go along using testparse.
336f5e9bd5SScott Kruger     The tree walker is simpler than what is in gmakegentest.py
346f5e9bd5SScott Kruger
356f5e9bd5SScott Kruger  The dataDict follows that generated by testparse.  gmakegentest.py does
366f5e9bd5SScott Kruger  further manipulations of the dataDict to handle things like for loops
376f5e9bd5SScott Kruger  so if using #2, those modifications are not included.
386f5e9bd5SScott Kruger
396f5e9bd5SScott Kruger  Querying:
406f5e9bd5SScott Kruger      The dataDict dictionary is then "inverted" to create a dictionary with the
416f5e9bd5SScott Kruger      range of field values as keys and list test names as the values.  This
426f5e9bd5SScott Kruger      allows fast searching
436f5e9bd5SScott Kruger
446f5e9bd5SScott Kruger"""
456f5e9bd5SScott Kruger
4685bc9deeSScott Krugerdef isFile(maybeFile):
4785bc9deeSScott Kruger  ext=os.path.splitext(maybeFile)[1]
4885bc9deeSScott Kruger  if not ext: return False
4985bc9deeSScott Kruger  if ext not in ['.c','.cxx','.cpp','F90','F','cu']: return False
5085bc9deeSScott Kruger  return True
5185bc9deeSScott Kruger
5285bc9deeSScott Krugerdef pathToLabel(path):
5385bc9deeSScott Kruger  """
5485bc9deeSScott Kruger  Because the scripts have a non-unique naming, the pretty-printing
5585bc9deeSScott Kruger  needs to convey the srcdir and srcfile.  There are two ways of doing this.
5685bc9deeSScott Kruger  """
5785bc9deeSScott Kruger  # Strip off any top-level directories or spaces
58*84533492SBarry Smith  path=path.strip().replace(petscdir,'')
5985bc9deeSScott Kruger  path=path.replace('src/','')
6085bc9deeSScott Kruger  if isFile(path):
6185bc9deeSScott Kruger    prefix=os.path.dirname(path).replace("/","_")
6285bc9deeSScott Kruger    suffix=os.path.splitext(os.path.basename(path))[0]
6385bc9deeSScott Kruger    label=prefix+"-"+suffix+'_*'
6485bc9deeSScott Kruger  else:
6585bc9deeSScott Kruger    path=path.rstrip('/')
669ea87190SJacob Faibussowitsch    label=path.replace("/","_").replace('tests_','tests-').replace('tutorials_','tutorials-')
6785bc9deeSScott Kruger  return label
6885bc9deeSScott Kruger
6985bc9deeSScott Krugerdef get_value(varset):
7085bc9deeSScott Kruger  """
7185bc9deeSScott Kruger  Searching args is a bit funky:
7285bc9deeSScott Kruger  Consider
7385bc9deeSScott Kruger      args: -ksp_monitor_short -pc_type ml -ksp_max_it 3
7485bc9deeSScott Kruger  Search terms are:
7585bc9deeSScott Kruger    ksp_monitor, 'pc_type ml', ksp_max_it
7685bc9deeSScott Kruger  Also ignore all loops
7785bc9deeSScott Kruger    -pc_fieldsplit_diag_use_amat {{0 1}}
7885bc9deeSScott Kruger  Gives: pc_fieldsplit_diag_use_amat as the search term
7985bc9deeSScott Kruger  Also ignore -f ...  (use matrices from file) because I'll assume
8085bc9deeSScott Kruger   that this kind of information isn't needed for testing.  If it's
8185bc9deeSScott Kruger   a separate search than just grep it
8285bc9deeSScott Kruger  """
8385bc9deeSScott Kruger  if varset.startswith('-f '): return None
8485bc9deeSScott Kruger
8585bc9deeSScott Kruger  # First  remove loops
8685bc9deeSScott Kruger  value=re.sub('{{.*}}','',varset)
8785bc9deeSScott Kruger  # Next remove -
8885bc9deeSScott Kruger  value=varset.lstrip("-")
8985bc9deeSScott Kruger  # Get rid of numbers
9085bc9deeSScott Kruger  value=re.sub(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",'',value)
9185bc9deeSScott Kruger  # return without spaces
9285bc9deeSScott Kruger  return value.strip()
9385bc9deeSScott Kruger
9485bc9deeSScott Krugerdef query(invDict,fields,labels):
956f5e9bd5SScott Kruger    """
966f5e9bd5SScott Kruger    Search the keys using fnmatch to find matching names and return list with
976f5e9bd5SScott Kruger    the results
986f5e9bd5SScott Kruger    """
99d5b43468SJose E. Roman    setlist=[]  # setlist is a list of lists that set operations will operate on
10085bc9deeSScott Kruger    llist=labels.replace('|',',').split(',')
10185bc9deeSScott Kruger    i=-1
10285bc9deeSScott Kruger    for field in fields.replace('|',',').split(','):
10385bc9deeSScott Kruger        i+=1
10485bc9deeSScott Kruger        label=llist[i]
10585bc9deeSScott Kruger        if field == 'name':
10685bc9deeSScott Kruger            if '/' in label:
10785bc9deeSScott Kruger              label=pathToLabel(label)
108f538e455SScott Kruger            elif label.startswith('src'):
109f538e455SScott Kruger                  label=label.lstrip('src').lstrip('*')
11085bc9deeSScott Kruger            setlist.append(fnmatch.filter(invDict['name'],label))
11185bc9deeSScott Kruger            continue
1125b6dee57SScott Kruger
11385bc9deeSScott Kruger        foundLabel=False   # easy to do if you misspell argument search
114ca84c248SScott Kruger        label=label.lower()
11585bc9deeSScott Kruger        for key in invDict[field]:
116ca84c248SScott Kruger            if fnmatch.filter([key.lower()],label):
11785bc9deeSScott Kruger              foundLabel=True
1186f5e9bd5SScott Kruger              # Do not return values with not unless label itself has not
1196f5e9bd5SScott Kruger              if label.startswith('!') and not key.startswith('!'): continue
1206f5e9bd5SScott Kruger              if not label.startswith('!') and key.startswith('!'): continue
12185bc9deeSScott Kruger              setlist.append(invDict[field][key])
12285bc9deeSScott Kruger        if not foundLabel:
12385bc9deeSScott Kruger          setlist.append([])
1246f5e9bd5SScott Kruger
12585bc9deeSScott Kruger    # Now process the union and intersection operators based on setlist
12685bc9deeSScott Kruger    allresults=[]
12785bc9deeSScott Kruger    # Union
12885bc9deeSScott Kruger    i=-1
12985bc9deeSScott Kruger    for ufield in fields.split(','):
13085bc9deeSScott Kruger       i+=1
13185bc9deeSScott Kruger       if '|' in ufield:
13285bc9deeSScott Kruger         # Intersection
13385bc9deeSScott Kruger         label=llist[i]
13485bc9deeSScott Kruger         results=set(setlist[i])
13585bc9deeSScott Kruger         for field in ufield.split('|')[1:]:
13685bc9deeSScott Kruger             i+=1
13785bc9deeSScott Kruger             label=llist[i]
13885bc9deeSScott Kruger             results=results.intersection(set(setlist[i]))
13985bc9deeSScott Kruger         allresults+=list(results)
14085bc9deeSScott Kruger       else:
14185bc9deeSScott Kruger         allresults+=setlist[i]
1426f5e9bd5SScott Kruger
14385bc9deeSScott Kruger    # remove duplicate entries and sort to give consistent results
14485bc9deeSScott Kruger    uniqlist=list(set(allresults))
14585bc9deeSScott Kruger    uniqlist.sort()
14685bc9deeSScott Kruger    return  uniqlist
14785bc9deeSScott Kruger
14885bc9deeSScott Krugerdef get_inverse_dictionary(dataDict,fields,srcdir):
1496f5e9bd5SScott Kruger    """
1506f5e9bd5SScott Kruger    Create a dictionary with the values of field as the keys, and the name of
1516f5e9bd5SScott Kruger    the tests as the results.
1526f5e9bd5SScott Kruger    """
1536f5e9bd5SScott Kruger    invDict={}
15485bc9deeSScott Kruger    # Comma-delimited lists denote union
15585bc9deeSScott Kruger    for field in fields.replace('|',',').split(','):
15685bc9deeSScott Kruger        if field not in invDict:
15785bc9deeSScott Kruger            if field == 'name':
15885bc9deeSScott Kruger                 invDict[field]=[]   # List for ease
15985bc9deeSScott Kruger            else:
16085bc9deeSScott Kruger                 invDict[field]={}
1616f5e9bd5SScott Kruger        for root in dataDict:
1626f5e9bd5SScott Kruger          for exfile in dataDict[root]:
1636f5e9bd5SScott Kruger            for test in dataDict[root][exfile]:
164aec279ffSScott Kruger              if test in testparse.buildkeys: continue
1656f5e9bd5SScott Kruger              defroot = testparse.getDefaultOutputFileRoot(test)
16685bc9deeSScott Kruger              fname=nameSpace(defroot,os.path.relpath(root,srcdir))
1675b6dee57SScott Kruger              if field == 'name':
16885bc9deeSScott Kruger                  invDict['name'].append(fname)
1695b6dee57SScott Kruger                  continue
1705b6dee57SScott Kruger              if field not in dataDict[root][exfile][test]: continue
1716f5e9bd5SScott Kruger              values=dataDict[root][exfile][test][field]
1726f5e9bd5SScott Kruger
17385bc9deeSScott Kruger              if not field == 'args' and not field == 'diff_args':
1746f5e9bd5SScott Kruger                for val in values.split():
17585bc9deeSScott Kruger                    if val in invDict[field]:
17685bc9deeSScott Kruger                        invDict[field][val].append(fname)
1776f5e9bd5SScott Kruger                    else:
17885bc9deeSScott Kruger                        invDict[field][val] = [fname]
17985bc9deeSScott Kruger              else:
18085bc9deeSScott Kruger                # Args are funky.
1813be2e2fdSJose E. Roman                for varset in re.split(r'(^|\W)-(?=[a-zA-Z])',values):
18285bc9deeSScott Kruger                  val=get_value(varset)
18385bc9deeSScott Kruger                  if not val: continue
18485bc9deeSScott Kruger                  if val in invDict[field]:
18585bc9deeSScott Kruger                    invDict[field][val].append(fname)
18685bc9deeSScott Kruger                  else:
18785bc9deeSScott Kruger                    invDict[field][val] = [fname]
18885bc9deeSScott Kruger        # remove duplicate entries (multiple test/file)
18985bc9deeSScott Kruger        if not field == 'name':
19085bc9deeSScott Kruger          for val in invDict[field]:
19185bc9deeSScott Kruger            invDict[field][val]=list(set(invDict[field][val]))
19285bc9deeSScott Kruger
1936f5e9bd5SScott Kruger    return invDict
1946f5e9bd5SScott Kruger
1954e028dedSScott Krugerdef get_gmakegentest_data(testdir,petsc_dir,petsc_arch):
1966f5e9bd5SScott Kruger    """
1976f5e9bd5SScott Kruger     Write out the dataDict into a pickle file
1986f5e9bd5SScott Kruger    """
1996f5e9bd5SScott Kruger    # This needs to be consistent with gmakegentest.py of course
2004e028dedSScott Kruger    pkl_file=os.path.join(testdir,'datatest.pkl')
2014e028dedSScott Kruger    # If it doesn't exist, then we need to regenerate
2024e028dedSScott Kruger    if not os.path.exists(pkl_file):
2034e028dedSScott Kruger      startdir=os.path.abspath(os.curdir)
2044e028dedSScott Kruger      os.chdir(petsc_dir)
2054e028dedSScott Kruger      args='--petsc-dir='+petsc_dir+' --petsc-arch='+petsc_arch+' --testdir='+testdir
2064e028dedSScott Kruger      buf = os.popen('config/gmakegentest.py '+args).read()
2074e028dedSScott Kruger      os.chdir(startdir)
2084e028dedSScott Kruger
2094e028dedSScott Kruger    fd = open(pkl_file, 'rb')
2106f5e9bd5SScott Kruger    dataDict=pickle.load(fd)
2116f5e9bd5SScott Kruger    fd.close()
2126f5e9bd5SScott Kruger    return dataDict
2136f5e9bd5SScott Kruger
2146f5e9bd5SScott Krugerdef walktree(top):
2156f5e9bd5SScott Kruger    """
2166f5e9bd5SScott Kruger    Walk a directory tree, starting from 'top'
2176f5e9bd5SScott Kruger    """
2186f5e9bd5SScott Kruger    verbose = False
2196f5e9bd5SScott Kruger    dataDict = {}
2206f5e9bd5SScott Kruger    alldatafiles = []
2216f5e9bd5SScott Kruger    for root, dirs, files in os.walk(top, topdown=False):
2226f5e9bd5SScott Kruger        if root == 'output': continue
2236f5e9bd5SScott Kruger        if '.dSYM' in root: continue
2246f5e9bd5SScott Kruger        if verbose: print(root)
2256f5e9bd5SScott Kruger
2266f5e9bd5SScott Kruger        dataDict[root] = {}
2276f5e9bd5SScott Kruger
2286f5e9bd5SScott Kruger        for exfile in files:
2296f5e9bd5SScott Kruger            # Ignore emacs files
2306f5e9bd5SScott Kruger            if exfile.startswith("#") or exfile.startswith(".#"): continue
2316f5e9bd5SScott Kruger            ext=os.path.splitext(exfile)[1]
2326f5e9bd5SScott Kruger            if ext[1:] not in ['c','cxx','cpp','cu','F90','F']: continue
2336f5e9bd5SScott Kruger
2346f5e9bd5SScott Kruger            # Convenience
2356f5e9bd5SScott Kruger            fullex = os.path.join(root, exfile)
2366f5e9bd5SScott Kruger            if verbose: print('   --> '+fullex)
2376f5e9bd5SScott Kruger            dataDict[root].update(testparse.parseTestFile(fullex, 0))
2386f5e9bd5SScott Kruger
2396f5e9bd5SScott Kruger    return dataDict
2406f5e9bd5SScott Kruger
24185bc9deeSScott Krugerdef do_query(use_source, startdir, srcdir, testdir, petsc_dir, petsc_arch,
24285bc9deeSScott Kruger             fields, labels, searchin):
2436f5e9bd5SScott Kruger    """
2446f5e9bd5SScott Kruger    Do the actual query
2456f5e9bd5SScott Kruger    This part of the code is placed here instead of main()
2466f5e9bd5SScott Kruger    to show how one could translate this into ipython/jupyer notebook
2476f5e9bd5SScott Kruger    commands for more advanced queries
2486f5e9bd5SScott Kruger    """
2496f5e9bd5SScott Kruger    # Get dictionary
2506f5e9bd5SScott Kruger    if use_source:
2516f5e9bd5SScott Kruger        dataDict=walktree(startdir)
2526f5e9bd5SScott Kruger    else:
2534e028dedSScott Kruger        dataDict=get_gmakegentest_data(testdir, petsc_dir, petsc_arch)
2546f5e9bd5SScott Kruger
2556f5e9bd5SScott Kruger    # Get inverse dictionary for searching
25685bc9deeSScott Kruger    invDict=get_inverse_dictionary(dataDict, fields, srcdir)
2576f5e9bd5SScott Kruger
2586f5e9bd5SScott Kruger    # Now do query
25985bc9deeSScott Kruger    resList=query(invDict, fields, labels)
26085bc9deeSScott Kruger
26185bc9deeSScott Kruger    # Filter results using searchin
26285bc9deeSScott Kruger    newresList=[]
26385bc9deeSScott Kruger    if searchin.strip():
264be89fe9eSScott Kruger        if not searchin.startswith('!'):
26585bc9deeSScott Kruger            for key in resList:
26685bc9deeSScott Kruger                if fnmatch.filter([key],searchin):
26785bc9deeSScott Kruger                  newresList.append(key)
268be89fe9eSScott Kruger        else:
269be89fe9eSScott Kruger            for key in resList:
270be89fe9eSScott Kruger                if not fnmatch.filter([key],searchin[1:]):
271be89fe9eSScott Kruger                  newresList.append(key)
27285bc9deeSScott Kruger        resList=newresList
2736f5e9bd5SScott Kruger
2746f5e9bd5SScott Kruger    # Print in flat list suitable for use by gmakefile.test
2756f5e9bd5SScott Kruger    print(' '.join(resList))
2766f5e9bd5SScott Kruger
2776f5e9bd5SScott Kruger    return
2786f5e9bd5SScott Kruger
2799ea87190SJacob Faibussowitschdef expand_path_like(petscdir,petscarch,pathlike):
2809ea87190SJacob Faibussowitsch    def remove_prefix(text,prefix):
2819ea87190SJacob Faibussowitsch        return text[text.startswith(prefix) and len(prefix):]
2829ea87190SJacob Faibussowitsch
2839ea87190SJacob Faibussowitsch    # expand user second, as expandvars may insert a '~'
2849ea87190SJacob Faibussowitsch    string = os.path.expanduser(os.path.expandvars(pathlike))
2859ea87190SJacob Faibussowitsch    # if the dirname check succeeds then likely we have a glob expression
2869ea87190SJacob Faibussowitsch    pardir = os.path.dirname(string)
2879ea87190SJacob Faibussowitsch    if os.path.exists(pardir):
2889ea87190SJacob Faibussowitsch        suffix   = string.replace(pardir,'') # get whatever is left over
2899ea87190SJacob Faibussowitsch        pathlike = remove_prefix(os.path.relpath(os.path.abspath(pardir),petscdir),'.'+os.path.sep)
2909ea87190SJacob Faibussowitsch        if petscarch == '':
2919ea87190SJacob Faibussowitsch            pathlike = pathlike.replace(os.path.sep.join(('share','petsc','examples'))+'/','')
2929ea87190SJacob Faibussowitsch        pathlike += suffix
293*84533492SBarry Smith    pathlike = pathlike.replace('diff-','')
2949ea87190SJacob Faibussowitsch    return pathlike
2959ea87190SJacob Faibussowitsch
2966f5e9bd5SScott Krugerdef main():
2976f5e9bd5SScott Kruger    parser = optparse.OptionParser(usage="%prog [options] field match_pattern")
2986f5e9bd5SScott Kruger    parser.add_option('-s', '--startdir', dest='startdir',
2996f5e9bd5SScott Kruger                      help='Where to start the recursion if not srcdir',
3006f5e9bd5SScott Kruger                      default='')
301aec279ffSScott Kruger    parser.add_option('-p', '--petsc-dir', dest='petsc_dir',
302aec279ffSScott Kruger                      help='Set PETSC_DIR different from environment',
3036f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_DIR'))
3046f5e9bd5SScott Kruger    parser.add_option('-a', '--petsc-arch', dest='petsc_arch',
3056f5e9bd5SScott Kruger                      help='Set PETSC_ARCH different from environment',
3066f5e9bd5SScott Kruger                      default=os.environ.get('PETSC_ARCH'))
3076f5e9bd5SScott Kruger    parser.add_option('--srcdir', dest='srcdir',
3086f5e9bd5SScott Kruger                      help='Set location of sources different from PETSC_DIR/src.  Must be full path.',
3096f5e9bd5SScott Kruger                      default='src')
3106f5e9bd5SScott Kruger    parser.add_option('-t', '--testdir', dest='testdir',
3116f5e9bd5SScott Kruger                      help='Test directory if not PETSC_ARCH/tests.  Must be full path',
3126f5e9bd5SScott Kruger                      default='tests')
3136f5e9bd5SScott Kruger    parser.add_option('-u', '--use-source', action="store_false",
3146f5e9bd5SScott Kruger                      dest='use_source',
3156f5e9bd5SScott Kruger                      help='Query all sources rather than those configured in PETSC_ARCH')
31685bc9deeSScott Kruger    parser.add_option('-i', '--searchin', dest='searchin',
31785bc9deeSScott Kruger                      help='Filter results from the arguments',
31885bc9deeSScott Kruger                      default='')
3196f5e9bd5SScott Kruger
3206f5e9bd5SScott Kruger    opts, args = parser.parse_args()
3216f5e9bd5SScott Kruger
3226f5e9bd5SScott Kruger    # Argument Sanity checks
3236f5e9bd5SScott Kruger    if len(args) != 2:
3246f5e9bd5SScott Kruger        parser.print_usage()
3256f5e9bd5SScott Kruger        print('Arguments: ')
3266f5e9bd5SScott Kruger        print('  field:          Field to search for; e.g., requires')
3275b6dee57SScott Kruger        print('                  To just match names, use "name"')
3286f5e9bd5SScott Kruger        print('  match_pattern:  Matching pattern for field; e.g., cuda')
3296f5e9bd5SScott Kruger        return
3306f5e9bd5SScott Kruger
3313c5439e2SJacob Faibussowitsch    def shell_unquote(string):
3323c5439e2SJacob Faibussowitsch      """
3333c5439e2SJacob Faibussowitsch      Remove quotes from STRING. Useful in the case where you need to bury escaped quotes in a query
3343c5439e2SJacob Faibussowitsch      string in order to escape shell characters. For example:
3353c5439e2SJacob Faibussowitsch
3363c5439e2SJacob Faibussowitsch      $ make test query='foo,bar' queryval='requires|name'
3373c5439e2SJacob Faibussowitsch      /usr/bin/bash: line 1: name: command not found
3383c5439e2SJacob Faibussowitsch
3393c5439e2SJacob Faibussowitsch      While the original shell does not see the pipe character, the actual query is done via a second
3403c5439e2SJacob Faibussowitsch      shell, which is (literally) passed '$(queryval)', i.e. 'queryval='requires|name'' when expanded.
3413c5439e2SJacob Faibussowitsch      Note the fact that the expansion cancels out the quoting!!!
3423c5439e2SJacob Faibussowitsch
3433c5439e2SJacob Faibussowitsch      You can fix this by doing:
3443c5439e2SJacob Faibussowitsch
3453c5439e2SJacob Faibussowitsch      $ make test query='foo,bar' queryval='"requires|name"'
3463c5439e2SJacob Faibussowitsch
3473c5439e2SJacob Faibussowitsch      However this then shows up here as labels = 'queryval="requires|name"'. So we need to remove the
3483c5439e2SJacob Faibussowitsch      '"'. Applying shlex.split() on this returns:
3493c5439e2SJacob Faibussowitsch
3503c5439e2SJacob Faibussowitsch      >>> shlex.split('queryval="requires|name"')
3513c5439e2SJacob Faibussowitsch      ['queryval=requires|name']
3523c5439e2SJacob Faibussowitsch
3533c5439e2SJacob Faibussowitsch      And voila. Note also that:
3543c5439e2SJacob Faibussowitsch
3553c5439e2SJacob Faibussowitsch      >>> shlex.split('queryval=requires|name')
3563c5439e2SJacob Faibussowitsch      ['queryval=requires|name']
3573c5439e2SJacob Faibussowitsch      """
3583c5439e2SJacob Faibussowitsch      import shlex
3593c5439e2SJacob Faibussowitsch
3603c5439e2SJacob Faibussowitsch      if string:
3613c5439e2SJacob Faibussowitsch        ret = shlex.split(string)
3623c5439e2SJacob Faibussowitsch        assert len(ret) == 1, "Dont know what to do if shlex.split() produces more than 1 value?"
3633c5439e2SJacob Faibussowitsch        string = ret[0]
3643c5439e2SJacob Faibussowitsch      return string
3653c5439e2SJacob Faibussowitsch
366168c8686SJacob Faibussowitsch    def alternate_command_preprocess(string):
367168c8686SJacob Faibussowitsch      """
368168c8686SJacob Faibussowitsch      Replace the alternate versions in STRING with the regular variants
369168c8686SJacob Faibussowitsch      """
370168c8686SJacob Faibussowitsch      return string.replace('%OR%', '|').replace('%AND%', ',').replace('%NEG%', '!')
371168c8686SJacob Faibussowitsch
3726f5e9bd5SScott Kruger    # Process arguments and options -- mostly just paths here
373168c8686SJacob Faibussowitsch    field=alternate_command_preprocess(shell_unquote(args[0]))
374*84533492SBarry Smith    labels=alternate_command_preprocess(shell_unquote(args[1]))
37585bc9deeSScott Kruger    searchin=opts.searchin
3766f5e9bd5SScott Kruger
3776f5e9bd5SScott Kruger    petsc_dir = opts.petsc_dir
3786f5e9bd5SScott Kruger    petsc_arch = opts.petsc_arch
3796f5e9bd5SScott Kruger    petsc_full_arch = os.path.join(petsc_dir, petsc_arch)
3806f5e9bd5SScott Kruger
38158780e5dSStefano Zampini    if petsc_arch == '':
38258780e5dSStefano Zampini        petsc_full_src = os.path.join(petsc_dir, 'share', 'petsc', 'examples', 'src')
38358780e5dSStefano Zampini    else:
3846f5e9bd5SScott Kruger      if opts.srcdir == 'src':
3856f5e9bd5SScott Kruger        petsc_full_src = os.path.join(petsc_dir, 'src')
3866f5e9bd5SScott Kruger      else:
3876f5e9bd5SScott Kruger        petsc_full_src = opts.srcdir
3886f5e9bd5SScott Kruger    if opts.testdir == 'tests':
3896f5e9bd5SScott Kruger      petsc_full_test = os.path.join(petsc_full_arch, 'tests')
3906f5e9bd5SScott Kruger    else:
3916f5e9bd5SScott Kruger      petsc_full_test = opts.testdir
3926f5e9bd5SScott Kruger    if opts.startdir:
3936f5e9bd5SScott Kruger      startdir=opts.startdir=petsc_full_src
3946f5e9bd5SScott Kruger    else:
3956f5e9bd5SScott Kruger      startdir=petsc_full_src
3966f5e9bd5SScott Kruger
3976f5e9bd5SScott Kruger    # Options Sanity checks
3986f5e9bd5SScott Kruger    if not os.path.isdir(petsc_dir):
3996f5e9bd5SScott Kruger        print("PETSC_DIR must be a directory")
4006f5e9bd5SScott Kruger        return
4016f5e9bd5SScott Kruger
4026f5e9bd5SScott Kruger    if not opts.use_source:
4036f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_arch):
4046f5e9bd5SScott Kruger            print("PETSC_DIR/PETSC_ARCH must be a directory")
4056f5e9bd5SScott Kruger            return
4066f5e9bd5SScott Kruger        elif not os.path.isdir(petsc_full_test):
4076f5e9bd5SScott Kruger            print("Testdir must be a directory"+petsc_full_test)
4086f5e9bd5SScott Kruger            return
4096f5e9bd5SScott Kruger    else:
4106f5e9bd5SScott Kruger        if not os.path.isdir(petsc_full_src):
4116f5e9bd5SScott Kruger            print("Source directory must be a directory"+petsc_full_src)
4126f5e9bd5SScott Kruger            return
4136f5e9bd5SScott Kruger
414*84533492SBarry Smith    labels = expand_path_like(petsc_dir,petsc_arch,labels)
4159ea87190SJacob Faibussowitsch
4166f5e9bd5SScott Kruger    # Do the actual query
4174e028dedSScott Kruger    do_query(opts.use_source, startdir, petsc_full_src, petsc_full_test,
418*84533492SBarry Smith             petsc_dir, petsc_arch, field, labels, searchin)
4196f5e9bd5SScott Kruger
4206f5e9bd5SScott Kruger    return
4216f5e9bd5SScott Kruger
4226f5e9bd5SScott Krugerif __name__ == "__main__":
4236f5e9bd5SScott Kruger        main()
424