xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/glob.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Filename globbing utility."""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerimport contextlib
4*cda5da8dSAndroid Build Coastguard Workerimport os
5*cda5da8dSAndroid Build Coastguard Workerimport re
6*cda5da8dSAndroid Build Coastguard Workerimport fnmatch
7*cda5da8dSAndroid Build Coastguard Workerimport itertools
8*cda5da8dSAndroid Build Coastguard Workerimport stat
9*cda5da8dSAndroid Build Coastguard Workerimport sys
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker__all__ = ["glob", "iglob", "escape"]
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Workerdef glob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
14*cda5da8dSAndroid Build Coastguard Worker        include_hidden=False):
15*cda5da8dSAndroid Build Coastguard Worker    """Return a list of paths matching a pathname pattern.
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker    The pattern may contain simple shell-style wildcards a la
18*cda5da8dSAndroid Build Coastguard Worker    fnmatch. Unlike fnmatch, filenames starting with a
19*cda5da8dSAndroid Build Coastguard Worker    dot are special cases that are not matched by '*' and '?'
20*cda5da8dSAndroid Build Coastguard Worker    patterns by default.
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker    If `include_hidden` is true, the patterns '*', '?', '**'  will match hidden
23*cda5da8dSAndroid Build Coastguard Worker    directories.
24*cda5da8dSAndroid Build Coastguard Worker
25*cda5da8dSAndroid Build Coastguard Worker    If `recursive` is true, the pattern '**' will match any files and
26*cda5da8dSAndroid Build Coastguard Worker    zero or more directories and subdirectories.
27*cda5da8dSAndroid Build Coastguard Worker    """
28*cda5da8dSAndroid Build Coastguard Worker    return list(iglob(pathname, root_dir=root_dir, dir_fd=dir_fd, recursive=recursive,
29*cda5da8dSAndroid Build Coastguard Worker                      include_hidden=include_hidden))
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Workerdef iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
32*cda5da8dSAndroid Build Coastguard Worker          include_hidden=False):
33*cda5da8dSAndroid Build Coastguard Worker    """Return an iterator which yields the paths matching a pathname pattern.
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker    The pattern may contain simple shell-style wildcards a la
36*cda5da8dSAndroid Build Coastguard Worker    fnmatch. However, unlike fnmatch, filenames starting with a
37*cda5da8dSAndroid Build Coastguard Worker    dot are special cases that are not matched by '*' and '?'
38*cda5da8dSAndroid Build Coastguard Worker    patterns.
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker    If recursive is true, the pattern '**' will match any files and
41*cda5da8dSAndroid Build Coastguard Worker    zero or more directories and subdirectories.
42*cda5da8dSAndroid Build Coastguard Worker    """
43*cda5da8dSAndroid Build Coastguard Worker    sys.audit("glob.glob", pathname, recursive)
44*cda5da8dSAndroid Build Coastguard Worker    sys.audit("glob.glob/2", pathname, recursive, root_dir, dir_fd)
45*cda5da8dSAndroid Build Coastguard Worker    if root_dir is not None:
46*cda5da8dSAndroid Build Coastguard Worker        root_dir = os.fspath(root_dir)
47*cda5da8dSAndroid Build Coastguard Worker    else:
48*cda5da8dSAndroid Build Coastguard Worker        root_dir = pathname[:0]
49*cda5da8dSAndroid Build Coastguard Worker    it = _iglob(pathname, root_dir, dir_fd, recursive, False,
50*cda5da8dSAndroid Build Coastguard Worker                include_hidden=include_hidden)
51*cda5da8dSAndroid Build Coastguard Worker    if not pathname or recursive and _isrecursive(pathname[:2]):
52*cda5da8dSAndroid Build Coastguard Worker        try:
53*cda5da8dSAndroid Build Coastguard Worker            s = next(it)  # skip empty string
54*cda5da8dSAndroid Build Coastguard Worker            if s:
55*cda5da8dSAndroid Build Coastguard Worker                it = itertools.chain((s,), it)
56*cda5da8dSAndroid Build Coastguard Worker        except StopIteration:
57*cda5da8dSAndroid Build Coastguard Worker            pass
58*cda5da8dSAndroid Build Coastguard Worker    return it
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Workerdef _iglob(pathname, root_dir, dir_fd, recursive, dironly,
61*cda5da8dSAndroid Build Coastguard Worker           include_hidden=False):
62*cda5da8dSAndroid Build Coastguard Worker    dirname, basename = os.path.split(pathname)
63*cda5da8dSAndroid Build Coastguard Worker    if not has_magic(pathname):
64*cda5da8dSAndroid Build Coastguard Worker        assert not dironly
65*cda5da8dSAndroid Build Coastguard Worker        if basename:
66*cda5da8dSAndroid Build Coastguard Worker            if _lexists(_join(root_dir, pathname), dir_fd):
67*cda5da8dSAndroid Build Coastguard Worker                yield pathname
68*cda5da8dSAndroid Build Coastguard Worker        else:
69*cda5da8dSAndroid Build Coastguard Worker            # Patterns ending with a slash should match only directories
70*cda5da8dSAndroid Build Coastguard Worker            if _isdir(_join(root_dir, dirname), dir_fd):
71*cda5da8dSAndroid Build Coastguard Worker                yield pathname
72*cda5da8dSAndroid Build Coastguard Worker        return
73*cda5da8dSAndroid Build Coastguard Worker    if not dirname:
74*cda5da8dSAndroid Build Coastguard Worker        if recursive and _isrecursive(basename):
75*cda5da8dSAndroid Build Coastguard Worker            yield from _glob2(root_dir, basename, dir_fd, dironly,
76*cda5da8dSAndroid Build Coastguard Worker                             include_hidden=include_hidden)
77*cda5da8dSAndroid Build Coastguard Worker        else:
78*cda5da8dSAndroid Build Coastguard Worker            yield from _glob1(root_dir, basename, dir_fd, dironly,
79*cda5da8dSAndroid Build Coastguard Worker                              include_hidden=include_hidden)
80*cda5da8dSAndroid Build Coastguard Worker        return
81*cda5da8dSAndroid Build Coastguard Worker    # `os.path.split()` returns the argument itself as a dirname if it is a
82*cda5da8dSAndroid Build Coastguard Worker    # drive or UNC path.  Prevent an infinite recursion if a drive or UNC path
83*cda5da8dSAndroid Build Coastguard Worker    # contains magic characters (i.e. r'\\?\C:').
84*cda5da8dSAndroid Build Coastguard Worker    if dirname != pathname and has_magic(dirname):
85*cda5da8dSAndroid Build Coastguard Worker        dirs = _iglob(dirname, root_dir, dir_fd, recursive, True,
86*cda5da8dSAndroid Build Coastguard Worker                      include_hidden=include_hidden)
87*cda5da8dSAndroid Build Coastguard Worker    else:
88*cda5da8dSAndroid Build Coastguard Worker        dirs = [dirname]
89*cda5da8dSAndroid Build Coastguard Worker    if has_magic(basename):
90*cda5da8dSAndroid Build Coastguard Worker        if recursive and _isrecursive(basename):
91*cda5da8dSAndroid Build Coastguard Worker            glob_in_dir = _glob2
92*cda5da8dSAndroid Build Coastguard Worker        else:
93*cda5da8dSAndroid Build Coastguard Worker            glob_in_dir = _glob1
94*cda5da8dSAndroid Build Coastguard Worker    else:
95*cda5da8dSAndroid Build Coastguard Worker        glob_in_dir = _glob0
96*cda5da8dSAndroid Build Coastguard Worker    for dirname in dirs:
97*cda5da8dSAndroid Build Coastguard Worker        for name in glob_in_dir(_join(root_dir, dirname), basename, dir_fd, dironly,
98*cda5da8dSAndroid Build Coastguard Worker                               include_hidden=include_hidden):
99*cda5da8dSAndroid Build Coastguard Worker            yield os.path.join(dirname, name)
100*cda5da8dSAndroid Build Coastguard Worker
101*cda5da8dSAndroid Build Coastguard Worker# These 2 helper functions non-recursively glob inside a literal directory.
102*cda5da8dSAndroid Build Coastguard Worker# They return a list of basenames.  _glob1 accepts a pattern while _glob0
103*cda5da8dSAndroid Build Coastguard Worker# takes a literal basename (so it only has to check for its existence).
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Workerdef _glob1(dirname, pattern, dir_fd, dironly, include_hidden=False):
106*cda5da8dSAndroid Build Coastguard Worker    names = _listdir(dirname, dir_fd, dironly)
107*cda5da8dSAndroid Build Coastguard Worker    if include_hidden or not _ishidden(pattern):
108*cda5da8dSAndroid Build Coastguard Worker        names = (x for x in names if include_hidden or not _ishidden(x))
109*cda5da8dSAndroid Build Coastguard Worker    return fnmatch.filter(names, pattern)
110*cda5da8dSAndroid Build Coastguard Worker
111*cda5da8dSAndroid Build Coastguard Workerdef _glob0(dirname, basename, dir_fd, dironly, include_hidden=False):
112*cda5da8dSAndroid Build Coastguard Worker    if basename:
113*cda5da8dSAndroid Build Coastguard Worker        if _lexists(_join(dirname, basename), dir_fd):
114*cda5da8dSAndroid Build Coastguard Worker            return [basename]
115*cda5da8dSAndroid Build Coastguard Worker    else:
116*cda5da8dSAndroid Build Coastguard Worker        # `os.path.split()` returns an empty basename for paths ending with a
117*cda5da8dSAndroid Build Coastguard Worker        # directory separator.  'q*x/' should match only directories.
118*cda5da8dSAndroid Build Coastguard Worker        if _isdir(dirname, dir_fd):
119*cda5da8dSAndroid Build Coastguard Worker            return [basename]
120*cda5da8dSAndroid Build Coastguard Worker    return []
121*cda5da8dSAndroid Build Coastguard Worker
122*cda5da8dSAndroid Build Coastguard Worker# Following functions are not public but can be used by third-party code.
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Workerdef glob0(dirname, pattern):
125*cda5da8dSAndroid Build Coastguard Worker    return _glob0(dirname, pattern, None, False)
126*cda5da8dSAndroid Build Coastguard Worker
127*cda5da8dSAndroid Build Coastguard Workerdef glob1(dirname, pattern):
128*cda5da8dSAndroid Build Coastguard Worker    return _glob1(dirname, pattern, None, False)
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Worker# This helper function recursively yields relative pathnames inside a literal
131*cda5da8dSAndroid Build Coastguard Worker# directory.
132*cda5da8dSAndroid Build Coastguard Worker
133*cda5da8dSAndroid Build Coastguard Workerdef _glob2(dirname, pattern, dir_fd, dironly, include_hidden=False):
134*cda5da8dSAndroid Build Coastguard Worker    assert _isrecursive(pattern)
135*cda5da8dSAndroid Build Coastguard Worker    yield pattern[:0]
136*cda5da8dSAndroid Build Coastguard Worker    yield from _rlistdir(dirname, dir_fd, dironly,
137*cda5da8dSAndroid Build Coastguard Worker                         include_hidden=include_hidden)
138*cda5da8dSAndroid Build Coastguard Worker
139*cda5da8dSAndroid Build Coastguard Worker# If dironly is false, yields all file names inside a directory.
140*cda5da8dSAndroid Build Coastguard Worker# If dironly is true, yields only directory names.
141*cda5da8dSAndroid Build Coastguard Workerdef _iterdir(dirname, dir_fd, dironly):
142*cda5da8dSAndroid Build Coastguard Worker    try:
143*cda5da8dSAndroid Build Coastguard Worker        fd = None
144*cda5da8dSAndroid Build Coastguard Worker        fsencode = None
145*cda5da8dSAndroid Build Coastguard Worker        if dir_fd is not None:
146*cda5da8dSAndroid Build Coastguard Worker            if dirname:
147*cda5da8dSAndroid Build Coastguard Worker                fd = arg = os.open(dirname, _dir_open_flags, dir_fd=dir_fd)
148*cda5da8dSAndroid Build Coastguard Worker            else:
149*cda5da8dSAndroid Build Coastguard Worker                arg = dir_fd
150*cda5da8dSAndroid Build Coastguard Worker            if isinstance(dirname, bytes):
151*cda5da8dSAndroid Build Coastguard Worker                fsencode = os.fsencode
152*cda5da8dSAndroid Build Coastguard Worker        elif dirname:
153*cda5da8dSAndroid Build Coastguard Worker            arg = dirname
154*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(dirname, bytes):
155*cda5da8dSAndroid Build Coastguard Worker            arg = bytes(os.curdir, 'ASCII')
156*cda5da8dSAndroid Build Coastguard Worker        else:
157*cda5da8dSAndroid Build Coastguard Worker            arg = os.curdir
158*cda5da8dSAndroid Build Coastguard Worker        try:
159*cda5da8dSAndroid Build Coastguard Worker            with os.scandir(arg) as it:
160*cda5da8dSAndroid Build Coastguard Worker                for entry in it:
161*cda5da8dSAndroid Build Coastguard Worker                    try:
162*cda5da8dSAndroid Build Coastguard Worker                        if not dironly or entry.is_dir():
163*cda5da8dSAndroid Build Coastguard Worker                            if fsencode is not None:
164*cda5da8dSAndroid Build Coastguard Worker                                yield fsencode(entry.name)
165*cda5da8dSAndroid Build Coastguard Worker                            else:
166*cda5da8dSAndroid Build Coastguard Worker                                yield entry.name
167*cda5da8dSAndroid Build Coastguard Worker                    except OSError:
168*cda5da8dSAndroid Build Coastguard Worker                        pass
169*cda5da8dSAndroid Build Coastguard Worker        finally:
170*cda5da8dSAndroid Build Coastguard Worker            if fd is not None:
171*cda5da8dSAndroid Build Coastguard Worker                os.close(fd)
172*cda5da8dSAndroid Build Coastguard Worker    except OSError:
173*cda5da8dSAndroid Build Coastguard Worker        return
174*cda5da8dSAndroid Build Coastguard Worker
175*cda5da8dSAndroid Build Coastguard Workerdef _listdir(dirname, dir_fd, dironly):
176*cda5da8dSAndroid Build Coastguard Worker    with contextlib.closing(_iterdir(dirname, dir_fd, dironly)) as it:
177*cda5da8dSAndroid Build Coastguard Worker        return list(it)
178*cda5da8dSAndroid Build Coastguard Worker
179*cda5da8dSAndroid Build Coastguard Worker# Recursively yields relative pathnames inside a literal directory.
180*cda5da8dSAndroid Build Coastguard Workerdef _rlistdir(dirname, dir_fd, dironly, include_hidden=False):
181*cda5da8dSAndroid Build Coastguard Worker    names = _listdir(dirname, dir_fd, dironly)
182*cda5da8dSAndroid Build Coastguard Worker    for x in names:
183*cda5da8dSAndroid Build Coastguard Worker        if include_hidden or not _ishidden(x):
184*cda5da8dSAndroid Build Coastguard Worker            yield x
185*cda5da8dSAndroid Build Coastguard Worker            path = _join(dirname, x) if dirname else x
186*cda5da8dSAndroid Build Coastguard Worker            for y in _rlistdir(path, dir_fd, dironly,
187*cda5da8dSAndroid Build Coastguard Worker                               include_hidden=include_hidden):
188*cda5da8dSAndroid Build Coastguard Worker                yield _join(x, y)
189*cda5da8dSAndroid Build Coastguard Worker
190*cda5da8dSAndroid Build Coastguard Worker
191*cda5da8dSAndroid Build Coastguard Workerdef _lexists(pathname, dir_fd):
192*cda5da8dSAndroid Build Coastguard Worker    # Same as os.path.lexists(), but with dir_fd
193*cda5da8dSAndroid Build Coastguard Worker    if dir_fd is None:
194*cda5da8dSAndroid Build Coastguard Worker        return os.path.lexists(pathname)
195*cda5da8dSAndroid Build Coastguard Worker    try:
196*cda5da8dSAndroid Build Coastguard Worker        os.lstat(pathname, dir_fd=dir_fd)
197*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError):
198*cda5da8dSAndroid Build Coastguard Worker        return False
199*cda5da8dSAndroid Build Coastguard Worker    else:
200*cda5da8dSAndroid Build Coastguard Worker        return True
201*cda5da8dSAndroid Build Coastguard Worker
202*cda5da8dSAndroid Build Coastguard Workerdef _isdir(pathname, dir_fd):
203*cda5da8dSAndroid Build Coastguard Worker    # Same as os.path.isdir(), but with dir_fd
204*cda5da8dSAndroid Build Coastguard Worker    if dir_fd is None:
205*cda5da8dSAndroid Build Coastguard Worker        return os.path.isdir(pathname)
206*cda5da8dSAndroid Build Coastguard Worker    try:
207*cda5da8dSAndroid Build Coastguard Worker        st = os.stat(pathname, dir_fd=dir_fd)
208*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError):
209*cda5da8dSAndroid Build Coastguard Worker        return False
210*cda5da8dSAndroid Build Coastguard Worker    else:
211*cda5da8dSAndroid Build Coastguard Worker        return stat.S_ISDIR(st.st_mode)
212*cda5da8dSAndroid Build Coastguard Worker
213*cda5da8dSAndroid Build Coastguard Workerdef _join(dirname, basename):
214*cda5da8dSAndroid Build Coastguard Worker    # It is common if dirname or basename is empty
215*cda5da8dSAndroid Build Coastguard Worker    if not dirname or not basename:
216*cda5da8dSAndroid Build Coastguard Worker        return dirname or basename
217*cda5da8dSAndroid Build Coastguard Worker    return os.path.join(dirname, basename)
218*cda5da8dSAndroid Build Coastguard Worker
219*cda5da8dSAndroid Build Coastguard Workermagic_check = re.compile('([*?[])')
220*cda5da8dSAndroid Build Coastguard Workermagic_check_bytes = re.compile(b'([*?[])')
221*cda5da8dSAndroid Build Coastguard Worker
222*cda5da8dSAndroid Build Coastguard Workerdef has_magic(s):
223*cda5da8dSAndroid Build Coastguard Worker    if isinstance(s, bytes):
224*cda5da8dSAndroid Build Coastguard Worker        match = magic_check_bytes.search(s)
225*cda5da8dSAndroid Build Coastguard Worker    else:
226*cda5da8dSAndroid Build Coastguard Worker        match = magic_check.search(s)
227*cda5da8dSAndroid Build Coastguard Worker    return match is not None
228*cda5da8dSAndroid Build Coastguard Worker
229*cda5da8dSAndroid Build Coastguard Workerdef _ishidden(path):
230*cda5da8dSAndroid Build Coastguard Worker    return path[0] in ('.', b'.'[0])
231*cda5da8dSAndroid Build Coastguard Worker
232*cda5da8dSAndroid Build Coastguard Workerdef _isrecursive(pattern):
233*cda5da8dSAndroid Build Coastguard Worker    if isinstance(pattern, bytes):
234*cda5da8dSAndroid Build Coastguard Worker        return pattern == b'**'
235*cda5da8dSAndroid Build Coastguard Worker    else:
236*cda5da8dSAndroid Build Coastguard Worker        return pattern == '**'
237*cda5da8dSAndroid Build Coastguard Worker
238*cda5da8dSAndroid Build Coastguard Workerdef escape(pathname):
239*cda5da8dSAndroid Build Coastguard Worker    """Escape all special characters.
240*cda5da8dSAndroid Build Coastguard Worker    """
241*cda5da8dSAndroid Build Coastguard Worker    # Escaping is done by wrapping any of "*?[" between square brackets.
242*cda5da8dSAndroid Build Coastguard Worker    # Metacharacters do not work in the drive part and shouldn't be escaped.
243*cda5da8dSAndroid Build Coastguard Worker    drive, pathname = os.path.splitdrive(pathname)
244*cda5da8dSAndroid Build Coastguard Worker    if isinstance(pathname, bytes):
245*cda5da8dSAndroid Build Coastguard Worker        pathname = magic_check_bytes.sub(br'[\1]', pathname)
246*cda5da8dSAndroid Build Coastguard Worker    else:
247*cda5da8dSAndroid Build Coastguard Worker        pathname = magic_check.sub(r'[\1]', pathname)
248*cda5da8dSAndroid Build Coastguard Worker    return drive + pathname
249*cda5da8dSAndroid Build Coastguard Worker
250*cda5da8dSAndroid Build Coastguard Worker
251*cda5da8dSAndroid Build Coastguard Worker_dir_open_flags = os.O_RDONLY | getattr(os, 'O_DIRECTORY', 0)
252