diff options
author | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2022-09-23 22:12:35 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-12-12 20:28:25 +0000 |
commit | 6f7bbce507942f5160b42962b226af9566c08d4b (patch) | |
tree | e6485ef1705961d5f96e0ff575f006d19cbf0a71 | |
parent | ed4854591045d79bfe5c0b8ba282df62715bdf49 (diff) | |
download | mongo-6f7bbce507942f5160b42962b226af9566c08d4b.tar.gz |
SERVER-69944 Switch to use Python's built-in recursive glob support.
When splitting a path of the form "a/*/b/**", globstar.iglob() would
previously have attempted to walk "a/*" as a literal directory instead
of expanding the glob pattern into a list of directories and walking
each of them.
-rw-r--r-- | buildscripts/resmokelib/utils/globstar.py | 157 |
1 files changed, 3 insertions, 154 deletions
diff --git a/buildscripts/resmokelib/utils/globstar.py b/buildscripts/resmokelib/utils/globstar.py index 5857870e627..6153349b6af 100644 --- a/buildscripts/resmokelib/utils/globstar.py +++ b/buildscripts/resmokelib/utils/globstar.py @@ -1,11 +1,9 @@ """Filename globbing utility.""" import glob as _glob -import os import os.path import re -_GLOBSTAR = "**" _CONTAINS_GLOB_PATTERN = re.compile("[*?[]") @@ -35,155 +33,6 @@ def iglob(globbed_pathname): expanded to match zero or more subdirectories. """ - parts = _split_path(globbed_pathname) - parts = _canonicalize(parts) - - index = _find_globstar(parts) - if index == -1: - for pathname in _glob.iglob(globbed_pathname): - # Normalize 'pathname' so exact string comparison can be used later. - yield os.path.normpath(pathname) - return - - # **, **/, or **/a - if index == 0: - expand = _expand_curdir - - # a/** or a/**/ or a/**/b - else: - expand = _expand - - prefix_parts = parts[:index] - suffix_parts = parts[index + 1:] - - prefix = os.path.join(*prefix_parts) if prefix_parts else os.curdir - suffix = os.path.join(*suffix_parts) if suffix_parts else "" - - for (kind, path) in expand(prefix): - if not suffix_parts: - yield path - - # Avoid following symlinks to avoid an infinite loop - elif suffix_parts and kind == "dir" and not os.path.islink(path): - path = os.path.join(path, suffix) - for pathname in iglob(path): - yield pathname - - -def _split_path(pathname): - """Return 'pathname' as a list of path components.""" - - parts = [] - - while True: - (dirname, basename) = os.path.split(pathname) - parts.append(basename) - if pathname == dirname: - parts.append(dirname) - break - if not dirname: - break - pathname = dirname - - parts.reverse() - return parts - - -def _canonicalize(parts): - """Return a copy of 'parts' with consecutive "**"s coalesced. - - Raise a ValueError for unsupported uses of "**". - """ - - res = [] - - prev_was_globstar = False - for part in parts: - if part == _GLOBSTAR: - # Skip consecutive **'s - if not prev_was_globstar: - prev_was_globstar = True - res.append(part) - elif _GLOBSTAR in part: # a/b**/c or a/**b/c - raise ValueError("Can only specify glob patterns of the form a/**/b") - else: - prev_was_globstar = False - res.append(part) - - return res - - -def _find_globstar(parts): - """Return the index of the first occurrence of "**" in 'parts'. - - Return -1 if "**" is not found in the list. - """ - - for (idx, part) in enumerate(parts): - if part == _GLOBSTAR: - return idx - return -1 - - -def _list_dir(pathname): - """Return a pair of subdirectory names and filenames contained within the 'pathname' directory. - - If 'pathname' does not exist, then None is returned. - """ - - try: - (_root, dirs, files) = next(os.walk(pathname)) - return (dirs, files) - except StopIteration: - return None # 'pathname' directory does not exist - - -def _expand(pathname): - """Emit tuples of the form ("dir", dirname) and ("file", filename). - - The result is for all directories and files contained within the 'pathname' directory. - """ - - res = _list_dir(pathname) - if res is None: - return - - (dirs, files) = res - - # Zero expansion - if os.path.basename(pathname): - yield ("dir", os.path.join(pathname, "")) - - for fname in files: - path = os.path.join(pathname, fname) - yield ("file", path) - - for dname in dirs: - path = os.path.join(pathname, dname) - for xpath in _expand(path): - yield xpath - - -def _expand_curdir(pathname): - """Emit tuples of the form ("dir", dirname) and ("file", filename). - - The result is for all directories and files contained within the 'pathname' directory. - - The returned pathnames omit a "./" prefix. - """ - - res = _list_dir(pathname) - if res is None: - return - - (dirs, files) = res - - # Zero expansion - yield ("dir", "") - - for fname in files: - yield ("file", fname) - - for dname in dirs: - for xdir in _expand(dname): - yield xdir + for pathname in _glob.iglob(globbed_pathname, recursive=True): + # Normalize 'pathname' so exact string comparison can be used later. + yield os.path.normpath(pathname) |