xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/posixpath.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Common operations on Posix pathnames.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerInstead of importing this module directly, import os and refer to
4*cda5da8dSAndroid Build Coastguard Workerthis module as os.path.  The "os.path" name is an alias for this
5*cda5da8dSAndroid Build Coastguard Workermodule on Posix systems; on other systems (e.g. Windows),
6*cda5da8dSAndroid Build Coastguard Workeros.path provides the same operations in a manner specific to that
7*cda5da8dSAndroid Build Coastguard Workerplatform, and is an alias to another module (e.g. ntpath).
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard WorkerSome of this can actually be useful on non-Posix systems too, e.g.
10*cda5da8dSAndroid Build Coastguard Workerfor manipulation of the pathname component of URLs.
11*cda5da8dSAndroid Build Coastguard Worker"""
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Worker# Strings representing various path-related bits and pieces.
14*cda5da8dSAndroid Build Coastguard Worker# These are primarily for export; internally, they are hardcoded.
15*cda5da8dSAndroid Build Coastguard Worker# Should be set before imports for resolving cyclic dependency.
16*cda5da8dSAndroid Build Coastguard Workercurdir = '.'
17*cda5da8dSAndroid Build Coastguard Workerpardir = '..'
18*cda5da8dSAndroid Build Coastguard Workerextsep = '.'
19*cda5da8dSAndroid Build Coastguard Workersep = '/'
20*cda5da8dSAndroid Build Coastguard Workerpathsep = ':'
21*cda5da8dSAndroid Build Coastguard Workerdefpath = '/bin:/usr/bin'
22*cda5da8dSAndroid Build Coastguard Workeraltsep = None
23*cda5da8dSAndroid Build Coastguard Workerdevnull = '/dev/null'
24*cda5da8dSAndroid Build Coastguard Worker
25*cda5da8dSAndroid Build Coastguard Workerimport os
26*cda5da8dSAndroid Build Coastguard Workerimport sys
27*cda5da8dSAndroid Build Coastguard Workerimport stat
28*cda5da8dSAndroid Build Coastguard Workerimport genericpath
29*cda5da8dSAndroid Build Coastguard Workerfrom genericpath import *
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
32*cda5da8dSAndroid Build Coastguard Worker           "basename","dirname","commonprefix","getsize","getmtime",
33*cda5da8dSAndroid Build Coastguard Worker           "getatime","getctime","islink","exists","lexists","isdir","isfile",
34*cda5da8dSAndroid Build Coastguard Worker           "ismount", "expanduser","expandvars","normpath","abspath",
35*cda5da8dSAndroid Build Coastguard Worker           "samefile","sameopenfile","samestat",
36*cda5da8dSAndroid Build Coastguard Worker           "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
37*cda5da8dSAndroid Build Coastguard Worker           "devnull","realpath","supports_unicode_filenames","relpath",
38*cda5da8dSAndroid Build Coastguard Worker           "commonpath"]
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker
41*cda5da8dSAndroid Build Coastguard Workerdef _get_sep(path):
42*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
43*cda5da8dSAndroid Build Coastguard Worker        return b'/'
44*cda5da8dSAndroid Build Coastguard Worker    else:
45*cda5da8dSAndroid Build Coastguard Worker        return '/'
46*cda5da8dSAndroid Build Coastguard Worker
47*cda5da8dSAndroid Build Coastguard Worker# Normalize the case of a pathname.  Trivial in Posix, string.lower on Mac.
48*cda5da8dSAndroid Build Coastguard Worker# On MS-DOS this may also turn slashes into backslashes; however, other
49*cda5da8dSAndroid Build Coastguard Worker# normalizations (such as optimizing '../' away) are not allowed
50*cda5da8dSAndroid Build Coastguard Worker# (another function should be defined to do that).
51*cda5da8dSAndroid Build Coastguard Worker
52*cda5da8dSAndroid Build Coastguard Workerdef normcase(s):
53*cda5da8dSAndroid Build Coastguard Worker    """Normalize case of pathname.  Has no effect under Posix"""
54*cda5da8dSAndroid Build Coastguard Worker    return os.fspath(s)
55*cda5da8dSAndroid Build Coastguard Worker
56*cda5da8dSAndroid Build Coastguard Worker
57*cda5da8dSAndroid Build Coastguard Worker# Return whether a path is absolute.
58*cda5da8dSAndroid Build Coastguard Worker# Trivial in Posix, harder on the Mac or MS-DOS.
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Workerdef isabs(s):
61*cda5da8dSAndroid Build Coastguard Worker    """Test whether a path is absolute"""
62*cda5da8dSAndroid Build Coastguard Worker    s = os.fspath(s)
63*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(s)
64*cda5da8dSAndroid Build Coastguard Worker    return s.startswith(sep)
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Worker
67*cda5da8dSAndroid Build Coastguard Worker# Join pathnames.
68*cda5da8dSAndroid Build Coastguard Worker# Ignore the previous parts if a part is absolute.
69*cda5da8dSAndroid Build Coastguard Worker# Insert a '/' unless the first part is empty or already ends in '/'.
70*cda5da8dSAndroid Build Coastguard Worker
71*cda5da8dSAndroid Build Coastguard Workerdef join(a, *p):
72*cda5da8dSAndroid Build Coastguard Worker    """Join two or more pathname components, inserting '/' as needed.
73*cda5da8dSAndroid Build Coastguard Worker    If any component is an absolute path, all previous path components
74*cda5da8dSAndroid Build Coastguard Worker    will be discarded.  An empty last part will result in a path that
75*cda5da8dSAndroid Build Coastguard Worker    ends with a separator."""
76*cda5da8dSAndroid Build Coastguard Worker    a = os.fspath(a)
77*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(a)
78*cda5da8dSAndroid Build Coastguard Worker    path = a
79*cda5da8dSAndroid Build Coastguard Worker    try:
80*cda5da8dSAndroid Build Coastguard Worker        if not p:
81*cda5da8dSAndroid Build Coastguard Worker            path[:0] + sep  #23780: Ensure compatible data type even if p is null.
82*cda5da8dSAndroid Build Coastguard Worker        for b in map(os.fspath, p):
83*cda5da8dSAndroid Build Coastguard Worker            if b.startswith(sep):
84*cda5da8dSAndroid Build Coastguard Worker                path = b
85*cda5da8dSAndroid Build Coastguard Worker            elif not path or path.endswith(sep):
86*cda5da8dSAndroid Build Coastguard Worker                path += b
87*cda5da8dSAndroid Build Coastguard Worker            else:
88*cda5da8dSAndroid Build Coastguard Worker                path += sep + b
89*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError, BytesWarning):
90*cda5da8dSAndroid Build Coastguard Worker        genericpath._check_arg_types('join', a, *p)
91*cda5da8dSAndroid Build Coastguard Worker        raise
92*cda5da8dSAndroid Build Coastguard Worker    return path
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Worker
95*cda5da8dSAndroid Build Coastguard Worker# Split a path in head (everything up to the last '/') and tail (the
96*cda5da8dSAndroid Build Coastguard Worker# rest).  If the path ends in '/', tail will be empty.  If there is no
97*cda5da8dSAndroid Build Coastguard Worker# '/' in the path, head  will be empty.
98*cda5da8dSAndroid Build Coastguard Worker# Trailing '/'es are stripped from head unless it is the root.
99*cda5da8dSAndroid Build Coastguard Worker
100*cda5da8dSAndroid Build Coastguard Workerdef split(p):
101*cda5da8dSAndroid Build Coastguard Worker    """Split a pathname.  Returns tuple "(head, tail)" where "tail" is
102*cda5da8dSAndroid Build Coastguard Worker    everything after the final slash.  Either part may be empty."""
103*cda5da8dSAndroid Build Coastguard Worker    p = os.fspath(p)
104*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(p)
105*cda5da8dSAndroid Build Coastguard Worker    i = p.rfind(sep) + 1
106*cda5da8dSAndroid Build Coastguard Worker    head, tail = p[:i], p[i:]
107*cda5da8dSAndroid Build Coastguard Worker    if head and head != sep*len(head):
108*cda5da8dSAndroid Build Coastguard Worker        head = head.rstrip(sep)
109*cda5da8dSAndroid Build Coastguard Worker    return head, tail
110*cda5da8dSAndroid Build Coastguard Worker
111*cda5da8dSAndroid Build Coastguard Worker
112*cda5da8dSAndroid Build Coastguard Worker# Split a path in root and extension.
113*cda5da8dSAndroid Build Coastguard Worker# The extension is everything starting at the last dot in the last
114*cda5da8dSAndroid Build Coastguard Worker# pathname component; the root is everything before that.
115*cda5da8dSAndroid Build Coastguard Worker# It is always true that root + ext == p.
116*cda5da8dSAndroid Build Coastguard Worker
117*cda5da8dSAndroid Build Coastguard Workerdef splitext(p):
118*cda5da8dSAndroid Build Coastguard Worker    p = os.fspath(p)
119*cda5da8dSAndroid Build Coastguard Worker    if isinstance(p, bytes):
120*cda5da8dSAndroid Build Coastguard Worker        sep = b'/'
121*cda5da8dSAndroid Build Coastguard Worker        extsep = b'.'
122*cda5da8dSAndroid Build Coastguard Worker    else:
123*cda5da8dSAndroid Build Coastguard Worker        sep = '/'
124*cda5da8dSAndroid Build Coastguard Worker        extsep = '.'
125*cda5da8dSAndroid Build Coastguard Worker    return genericpath._splitext(p, sep, None, extsep)
126*cda5da8dSAndroid Build Coastguard Workersplitext.__doc__ = genericpath._splitext.__doc__
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker# Split a pathname into a drive specification and the rest of the
129*cda5da8dSAndroid Build Coastguard Worker# path.  Useful on DOS/Windows/NT; on Unix, the drive is always empty.
130*cda5da8dSAndroid Build Coastguard Worker
131*cda5da8dSAndroid Build Coastguard Workerdef splitdrive(p):
132*cda5da8dSAndroid Build Coastguard Worker    """Split a pathname into drive and path. On Posix, drive is always
133*cda5da8dSAndroid Build Coastguard Worker    empty."""
134*cda5da8dSAndroid Build Coastguard Worker    p = os.fspath(p)
135*cda5da8dSAndroid Build Coastguard Worker    return p[:0], p
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker
138*cda5da8dSAndroid Build Coastguard Worker# Return the tail (basename) part of a path, same as split(path)[1].
139*cda5da8dSAndroid Build Coastguard Worker
140*cda5da8dSAndroid Build Coastguard Workerdef basename(p):
141*cda5da8dSAndroid Build Coastguard Worker    """Returns the final component of a pathname"""
142*cda5da8dSAndroid Build Coastguard Worker    p = os.fspath(p)
143*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(p)
144*cda5da8dSAndroid Build Coastguard Worker    i = p.rfind(sep) + 1
145*cda5da8dSAndroid Build Coastguard Worker    return p[i:]
146*cda5da8dSAndroid Build Coastguard Worker
147*cda5da8dSAndroid Build Coastguard Worker
148*cda5da8dSAndroid Build Coastguard Worker# Return the head (dirname) part of a path, same as split(path)[0].
149*cda5da8dSAndroid Build Coastguard Worker
150*cda5da8dSAndroid Build Coastguard Workerdef dirname(p):
151*cda5da8dSAndroid Build Coastguard Worker    """Returns the directory component of a pathname"""
152*cda5da8dSAndroid Build Coastguard Worker    p = os.fspath(p)
153*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(p)
154*cda5da8dSAndroid Build Coastguard Worker    i = p.rfind(sep) + 1
155*cda5da8dSAndroid Build Coastguard Worker    head = p[:i]
156*cda5da8dSAndroid Build Coastguard Worker    if head and head != sep*len(head):
157*cda5da8dSAndroid Build Coastguard Worker        head = head.rstrip(sep)
158*cda5da8dSAndroid Build Coastguard Worker    return head
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Worker# Is a path a symbolic link?
162*cda5da8dSAndroid Build Coastguard Worker# This will always return false on systems where os.lstat doesn't exist.
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Workerdef islink(path):
165*cda5da8dSAndroid Build Coastguard Worker    """Test whether a path is a symbolic link"""
166*cda5da8dSAndroid Build Coastguard Worker    try:
167*cda5da8dSAndroid Build Coastguard Worker        st = os.lstat(path)
168*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError, AttributeError):
169*cda5da8dSAndroid Build Coastguard Worker        return False
170*cda5da8dSAndroid Build Coastguard Worker    return stat.S_ISLNK(st.st_mode)
171*cda5da8dSAndroid Build Coastguard Worker
172*cda5da8dSAndroid Build Coastguard Worker# Being true for dangling symbolic links is also useful.
173*cda5da8dSAndroid Build Coastguard Worker
174*cda5da8dSAndroid Build Coastguard Workerdef lexists(path):
175*cda5da8dSAndroid Build Coastguard Worker    """Test whether a path exists.  Returns True for broken symbolic links"""
176*cda5da8dSAndroid Build Coastguard Worker    try:
177*cda5da8dSAndroid Build Coastguard Worker        os.lstat(path)
178*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError):
179*cda5da8dSAndroid Build Coastguard Worker        return False
180*cda5da8dSAndroid Build Coastguard Worker    return True
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker
183*cda5da8dSAndroid Build Coastguard Worker# Is a path a mount point?
184*cda5da8dSAndroid Build Coastguard Worker# (Does this work for all UNIXes?  Is it even guaranteed to work by Posix?)
185*cda5da8dSAndroid Build Coastguard Worker
186*cda5da8dSAndroid Build Coastguard Workerdef ismount(path):
187*cda5da8dSAndroid Build Coastguard Worker    """Test whether a path is a mount point"""
188*cda5da8dSAndroid Build Coastguard Worker    try:
189*cda5da8dSAndroid Build Coastguard Worker        s1 = os.lstat(path)
190*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError):
191*cda5da8dSAndroid Build Coastguard Worker        # It doesn't exist -- so not a mount point. :-)
192*cda5da8dSAndroid Build Coastguard Worker        return False
193*cda5da8dSAndroid Build Coastguard Worker    else:
194*cda5da8dSAndroid Build Coastguard Worker        # A symlink can never be a mount point
195*cda5da8dSAndroid Build Coastguard Worker        if stat.S_ISLNK(s1.st_mode):
196*cda5da8dSAndroid Build Coastguard Worker            return False
197*cda5da8dSAndroid Build Coastguard Worker
198*cda5da8dSAndroid Build Coastguard Worker    path = os.fspath(path)
199*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
200*cda5da8dSAndroid Build Coastguard Worker        parent = join(path, b'..')
201*cda5da8dSAndroid Build Coastguard Worker    else:
202*cda5da8dSAndroid Build Coastguard Worker        parent = join(path, '..')
203*cda5da8dSAndroid Build Coastguard Worker    parent = realpath(parent)
204*cda5da8dSAndroid Build Coastguard Worker    try:
205*cda5da8dSAndroid Build Coastguard Worker        s2 = os.lstat(parent)
206*cda5da8dSAndroid Build Coastguard Worker    except (OSError, ValueError):
207*cda5da8dSAndroid Build Coastguard Worker        return False
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Worker    dev1 = s1.st_dev
210*cda5da8dSAndroid Build Coastguard Worker    dev2 = s2.st_dev
211*cda5da8dSAndroid Build Coastguard Worker    if dev1 != dev2:
212*cda5da8dSAndroid Build Coastguard Worker        return True     # path/.. on a different device as path
213*cda5da8dSAndroid Build Coastguard Worker    ino1 = s1.st_ino
214*cda5da8dSAndroid Build Coastguard Worker    ino2 = s2.st_ino
215*cda5da8dSAndroid Build Coastguard Worker    if ino1 == ino2:
216*cda5da8dSAndroid Build Coastguard Worker        return True     # path/.. is the same i-node as path
217*cda5da8dSAndroid Build Coastguard Worker    return False
218*cda5da8dSAndroid Build Coastguard Worker
219*cda5da8dSAndroid Build Coastguard Worker
220*cda5da8dSAndroid Build Coastguard Worker# Expand paths beginning with '~' or '~user'.
221*cda5da8dSAndroid Build Coastguard Worker# '~' means $HOME; '~user' means that user's home directory.
222*cda5da8dSAndroid Build Coastguard Worker# If the path doesn't begin with '~', or if the user or $HOME is unknown,
223*cda5da8dSAndroid Build Coastguard Worker# the path is returned unchanged (leaving error reporting to whatever
224*cda5da8dSAndroid Build Coastguard Worker# function is called with the expanded path as argument).
225*cda5da8dSAndroid Build Coastguard Worker# See also module 'glob' for expansion of *, ? and [...] in pathnames.
226*cda5da8dSAndroid Build Coastguard Worker# (A function should also be defined to do full *sh-style environment
227*cda5da8dSAndroid Build Coastguard Worker# variable expansion.)
228*cda5da8dSAndroid Build Coastguard Worker
229*cda5da8dSAndroid Build Coastguard Workerdef expanduser(path):
230*cda5da8dSAndroid Build Coastguard Worker    """Expand ~ and ~user constructions.  If user or $HOME is unknown,
231*cda5da8dSAndroid Build Coastguard Worker    do nothing."""
232*cda5da8dSAndroid Build Coastguard Worker    path = os.fspath(path)
233*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
234*cda5da8dSAndroid Build Coastguard Worker        tilde = b'~'
235*cda5da8dSAndroid Build Coastguard Worker    else:
236*cda5da8dSAndroid Build Coastguard Worker        tilde = '~'
237*cda5da8dSAndroid Build Coastguard Worker    if not path.startswith(tilde):
238*cda5da8dSAndroid Build Coastguard Worker        return path
239*cda5da8dSAndroid Build Coastguard Worker    sep = _get_sep(path)
240*cda5da8dSAndroid Build Coastguard Worker    i = path.find(sep, 1)
241*cda5da8dSAndroid Build Coastguard Worker    if i < 0:
242*cda5da8dSAndroid Build Coastguard Worker        i = len(path)
243*cda5da8dSAndroid Build Coastguard Worker    if i == 1:
244*cda5da8dSAndroid Build Coastguard Worker        if 'HOME' not in os.environ:
245*cda5da8dSAndroid Build Coastguard Worker            try:
246*cda5da8dSAndroid Build Coastguard Worker                import pwd
247*cda5da8dSAndroid Build Coastguard Worker            except ImportError:
248*cda5da8dSAndroid Build Coastguard Worker                # pwd module unavailable, return path unchanged
249*cda5da8dSAndroid Build Coastguard Worker                return path
250*cda5da8dSAndroid Build Coastguard Worker            try:
251*cda5da8dSAndroid Build Coastguard Worker                userhome = pwd.getpwuid(os.getuid()).pw_dir
252*cda5da8dSAndroid Build Coastguard Worker            except KeyError:
253*cda5da8dSAndroid Build Coastguard Worker                # bpo-10496: if the current user identifier doesn't exist in the
254*cda5da8dSAndroid Build Coastguard Worker                # password database, return the path unchanged
255*cda5da8dSAndroid Build Coastguard Worker                return path
256*cda5da8dSAndroid Build Coastguard Worker        else:
257*cda5da8dSAndroid Build Coastguard Worker            userhome = os.environ['HOME']
258*cda5da8dSAndroid Build Coastguard Worker    else:
259*cda5da8dSAndroid Build Coastguard Worker        try:
260*cda5da8dSAndroid Build Coastguard Worker            import pwd
261*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
262*cda5da8dSAndroid Build Coastguard Worker            # pwd module unavailable, return path unchanged
263*cda5da8dSAndroid Build Coastguard Worker            return path
264*cda5da8dSAndroid Build Coastguard Worker        name = path[1:i]
265*cda5da8dSAndroid Build Coastguard Worker        if isinstance(name, bytes):
266*cda5da8dSAndroid Build Coastguard Worker            name = str(name, 'ASCII')
267*cda5da8dSAndroid Build Coastguard Worker        try:
268*cda5da8dSAndroid Build Coastguard Worker            pwent = pwd.getpwnam(name)
269*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
270*cda5da8dSAndroid Build Coastguard Worker            # bpo-10496: if the user name from the path doesn't exist in the
271*cda5da8dSAndroid Build Coastguard Worker            # password database, return the path unchanged
272*cda5da8dSAndroid Build Coastguard Worker            return path
273*cda5da8dSAndroid Build Coastguard Worker        userhome = pwent.pw_dir
274*cda5da8dSAndroid Build Coastguard Worker    # if no user home, return the path unchanged on VxWorks
275*cda5da8dSAndroid Build Coastguard Worker    if userhome is None and sys.platform == "vxworks":
276*cda5da8dSAndroid Build Coastguard Worker        return path
277*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
278*cda5da8dSAndroid Build Coastguard Worker        userhome = os.fsencode(userhome)
279*cda5da8dSAndroid Build Coastguard Worker        root = b'/'
280*cda5da8dSAndroid Build Coastguard Worker    else:
281*cda5da8dSAndroid Build Coastguard Worker        root = '/'
282*cda5da8dSAndroid Build Coastguard Worker    userhome = userhome.rstrip(root)
283*cda5da8dSAndroid Build Coastguard Worker    return (userhome + path[i:]) or root
284*cda5da8dSAndroid Build Coastguard Worker
285*cda5da8dSAndroid Build Coastguard Worker
286*cda5da8dSAndroid Build Coastguard Worker# Expand paths containing shell variable substitutions.
287*cda5da8dSAndroid Build Coastguard Worker# This expands the forms $variable and ${variable} only.
288*cda5da8dSAndroid Build Coastguard Worker# Non-existent variables are left unchanged.
289*cda5da8dSAndroid Build Coastguard Worker
290*cda5da8dSAndroid Build Coastguard Worker_varprog = None
291*cda5da8dSAndroid Build Coastguard Worker_varprogb = None
292*cda5da8dSAndroid Build Coastguard Worker
293*cda5da8dSAndroid Build Coastguard Workerdef expandvars(path):
294*cda5da8dSAndroid Build Coastguard Worker    """Expand shell variables of form $var and ${var}.  Unknown variables
295*cda5da8dSAndroid Build Coastguard Worker    are left unchanged."""
296*cda5da8dSAndroid Build Coastguard Worker    path = os.fspath(path)
297*cda5da8dSAndroid Build Coastguard Worker    global _varprog, _varprogb
298*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
299*cda5da8dSAndroid Build Coastguard Worker        if b'$' not in path:
300*cda5da8dSAndroid Build Coastguard Worker            return path
301*cda5da8dSAndroid Build Coastguard Worker        if not _varprogb:
302*cda5da8dSAndroid Build Coastguard Worker            import re
303*cda5da8dSAndroid Build Coastguard Worker            _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
304*cda5da8dSAndroid Build Coastguard Worker        search = _varprogb.search
305*cda5da8dSAndroid Build Coastguard Worker        start = b'{'
306*cda5da8dSAndroid Build Coastguard Worker        end = b'}'
307*cda5da8dSAndroid Build Coastguard Worker        environ = getattr(os, 'environb', None)
308*cda5da8dSAndroid Build Coastguard Worker    else:
309*cda5da8dSAndroid Build Coastguard Worker        if '$' not in path:
310*cda5da8dSAndroid Build Coastguard Worker            return path
311*cda5da8dSAndroid Build Coastguard Worker        if not _varprog:
312*cda5da8dSAndroid Build Coastguard Worker            import re
313*cda5da8dSAndroid Build Coastguard Worker            _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
314*cda5da8dSAndroid Build Coastguard Worker        search = _varprog.search
315*cda5da8dSAndroid Build Coastguard Worker        start = '{'
316*cda5da8dSAndroid Build Coastguard Worker        end = '}'
317*cda5da8dSAndroid Build Coastguard Worker        environ = os.environ
318*cda5da8dSAndroid Build Coastguard Worker    i = 0
319*cda5da8dSAndroid Build Coastguard Worker    while True:
320*cda5da8dSAndroid Build Coastguard Worker        m = search(path, i)
321*cda5da8dSAndroid Build Coastguard Worker        if not m:
322*cda5da8dSAndroid Build Coastguard Worker            break
323*cda5da8dSAndroid Build Coastguard Worker        i, j = m.span(0)
324*cda5da8dSAndroid Build Coastguard Worker        name = m.group(1)
325*cda5da8dSAndroid Build Coastguard Worker        if name.startswith(start) and name.endswith(end):
326*cda5da8dSAndroid Build Coastguard Worker            name = name[1:-1]
327*cda5da8dSAndroid Build Coastguard Worker        try:
328*cda5da8dSAndroid Build Coastguard Worker            if environ is None:
329*cda5da8dSAndroid Build Coastguard Worker                value = os.fsencode(os.environ[os.fsdecode(name)])
330*cda5da8dSAndroid Build Coastguard Worker            else:
331*cda5da8dSAndroid Build Coastguard Worker                value = environ[name]
332*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
333*cda5da8dSAndroid Build Coastguard Worker            i = j
334*cda5da8dSAndroid Build Coastguard Worker        else:
335*cda5da8dSAndroid Build Coastguard Worker            tail = path[j:]
336*cda5da8dSAndroid Build Coastguard Worker            path = path[:i] + value
337*cda5da8dSAndroid Build Coastguard Worker            i = len(path)
338*cda5da8dSAndroid Build Coastguard Worker            path += tail
339*cda5da8dSAndroid Build Coastguard Worker    return path
340*cda5da8dSAndroid Build Coastguard Worker
341*cda5da8dSAndroid Build Coastguard Worker
342*cda5da8dSAndroid Build Coastguard Worker# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
343*cda5da8dSAndroid Build Coastguard Worker# It should be understood that this may change the meaning of the path
344*cda5da8dSAndroid Build Coastguard Worker# if it contains symbolic links!
345*cda5da8dSAndroid Build Coastguard Worker
346*cda5da8dSAndroid Build Coastguard Workertry:
347*cda5da8dSAndroid Build Coastguard Worker    from posix import _path_normpath
348*cda5da8dSAndroid Build Coastguard Worker
349*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
350*cda5da8dSAndroid Build Coastguard Worker    def normpath(path):
351*cda5da8dSAndroid Build Coastguard Worker        """Normalize path, eliminating double slashes, etc."""
352*cda5da8dSAndroid Build Coastguard Worker        path = os.fspath(path)
353*cda5da8dSAndroid Build Coastguard Worker        if isinstance(path, bytes):
354*cda5da8dSAndroid Build Coastguard Worker            sep = b'/'
355*cda5da8dSAndroid Build Coastguard Worker            empty = b''
356*cda5da8dSAndroid Build Coastguard Worker            dot = b'.'
357*cda5da8dSAndroid Build Coastguard Worker            dotdot = b'..'
358*cda5da8dSAndroid Build Coastguard Worker        else:
359*cda5da8dSAndroid Build Coastguard Worker            sep = '/'
360*cda5da8dSAndroid Build Coastguard Worker            empty = ''
361*cda5da8dSAndroid Build Coastguard Worker            dot = '.'
362*cda5da8dSAndroid Build Coastguard Worker            dotdot = '..'
363*cda5da8dSAndroid Build Coastguard Worker        if path == empty:
364*cda5da8dSAndroid Build Coastguard Worker            return dot
365*cda5da8dSAndroid Build Coastguard Worker        initial_slashes = path.startswith(sep)
366*cda5da8dSAndroid Build Coastguard Worker        # POSIX allows one or two initial slashes, but treats three or more
367*cda5da8dSAndroid Build Coastguard Worker        # as single slash.
368*cda5da8dSAndroid Build Coastguard Worker        # (see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13)
369*cda5da8dSAndroid Build Coastguard Worker        if (initial_slashes and
370*cda5da8dSAndroid Build Coastguard Worker            path.startswith(sep*2) and not path.startswith(sep*3)):
371*cda5da8dSAndroid Build Coastguard Worker            initial_slashes = 2
372*cda5da8dSAndroid Build Coastguard Worker        comps = path.split(sep)
373*cda5da8dSAndroid Build Coastguard Worker        new_comps = []
374*cda5da8dSAndroid Build Coastguard Worker        for comp in comps:
375*cda5da8dSAndroid Build Coastguard Worker            if comp in (empty, dot):
376*cda5da8dSAndroid Build Coastguard Worker                continue
377*cda5da8dSAndroid Build Coastguard Worker            if (comp != dotdot or (not initial_slashes and not new_comps) or
378*cda5da8dSAndroid Build Coastguard Worker                 (new_comps and new_comps[-1] == dotdot)):
379*cda5da8dSAndroid Build Coastguard Worker                new_comps.append(comp)
380*cda5da8dSAndroid Build Coastguard Worker            elif new_comps:
381*cda5da8dSAndroid Build Coastguard Worker                new_comps.pop()
382*cda5da8dSAndroid Build Coastguard Worker        comps = new_comps
383*cda5da8dSAndroid Build Coastguard Worker        path = sep.join(comps)
384*cda5da8dSAndroid Build Coastguard Worker        if initial_slashes:
385*cda5da8dSAndroid Build Coastguard Worker            path = sep*initial_slashes + path
386*cda5da8dSAndroid Build Coastguard Worker        return path or dot
387*cda5da8dSAndroid Build Coastguard Worker
388*cda5da8dSAndroid Build Coastguard Workerelse:
389*cda5da8dSAndroid Build Coastguard Worker    def normpath(path):
390*cda5da8dSAndroid Build Coastguard Worker        """Normalize path, eliminating double slashes, etc."""
391*cda5da8dSAndroid Build Coastguard Worker        path = os.fspath(path)
392*cda5da8dSAndroid Build Coastguard Worker        if isinstance(path, bytes):
393*cda5da8dSAndroid Build Coastguard Worker            return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
394*cda5da8dSAndroid Build Coastguard Worker        return _path_normpath(path) or "."
395*cda5da8dSAndroid Build Coastguard Worker
396*cda5da8dSAndroid Build Coastguard Worker
397*cda5da8dSAndroid Build Coastguard Workerdef abspath(path):
398*cda5da8dSAndroid Build Coastguard Worker    """Return an absolute path."""
399*cda5da8dSAndroid Build Coastguard Worker    path = os.fspath(path)
400*cda5da8dSAndroid Build Coastguard Worker    if not isabs(path):
401*cda5da8dSAndroid Build Coastguard Worker        if isinstance(path, bytes):
402*cda5da8dSAndroid Build Coastguard Worker            cwd = os.getcwdb()
403*cda5da8dSAndroid Build Coastguard Worker        else:
404*cda5da8dSAndroid Build Coastguard Worker            cwd = os.getcwd()
405*cda5da8dSAndroid Build Coastguard Worker        path = join(cwd, path)
406*cda5da8dSAndroid Build Coastguard Worker    return normpath(path)
407*cda5da8dSAndroid Build Coastguard Worker
408*cda5da8dSAndroid Build Coastguard Worker
409*cda5da8dSAndroid Build Coastguard Worker# Return a canonical path (i.e. the absolute location of a file on the
410*cda5da8dSAndroid Build Coastguard Worker# filesystem).
411*cda5da8dSAndroid Build Coastguard Worker
412*cda5da8dSAndroid Build Coastguard Workerdef realpath(filename, *, strict=False):
413*cda5da8dSAndroid Build Coastguard Worker    """Return the canonical path of the specified filename, eliminating any
414*cda5da8dSAndroid Build Coastguard Workersymbolic links encountered in the path."""
415*cda5da8dSAndroid Build Coastguard Worker    filename = os.fspath(filename)
416*cda5da8dSAndroid Build Coastguard Worker    path, ok = _joinrealpath(filename[:0], filename, strict, {})
417*cda5da8dSAndroid Build Coastguard Worker    return abspath(path)
418*cda5da8dSAndroid Build Coastguard Worker
419*cda5da8dSAndroid Build Coastguard Worker# Join two paths, normalizing and eliminating any symbolic links
420*cda5da8dSAndroid Build Coastguard Worker# encountered in the second path.
421*cda5da8dSAndroid Build Coastguard Workerdef _joinrealpath(path, rest, strict, seen):
422*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
423*cda5da8dSAndroid Build Coastguard Worker        sep = b'/'
424*cda5da8dSAndroid Build Coastguard Worker        curdir = b'.'
425*cda5da8dSAndroid Build Coastguard Worker        pardir = b'..'
426*cda5da8dSAndroid Build Coastguard Worker    else:
427*cda5da8dSAndroid Build Coastguard Worker        sep = '/'
428*cda5da8dSAndroid Build Coastguard Worker        curdir = '.'
429*cda5da8dSAndroid Build Coastguard Worker        pardir = '..'
430*cda5da8dSAndroid Build Coastguard Worker
431*cda5da8dSAndroid Build Coastguard Worker    if isabs(rest):
432*cda5da8dSAndroid Build Coastguard Worker        rest = rest[1:]
433*cda5da8dSAndroid Build Coastguard Worker        path = sep
434*cda5da8dSAndroid Build Coastguard Worker
435*cda5da8dSAndroid Build Coastguard Worker    while rest:
436*cda5da8dSAndroid Build Coastguard Worker        name, _, rest = rest.partition(sep)
437*cda5da8dSAndroid Build Coastguard Worker        if not name or name == curdir:
438*cda5da8dSAndroid Build Coastguard Worker            # current dir
439*cda5da8dSAndroid Build Coastguard Worker            continue
440*cda5da8dSAndroid Build Coastguard Worker        if name == pardir:
441*cda5da8dSAndroid Build Coastguard Worker            # parent dir
442*cda5da8dSAndroid Build Coastguard Worker            if path:
443*cda5da8dSAndroid Build Coastguard Worker                path, name = split(path)
444*cda5da8dSAndroid Build Coastguard Worker                if name == pardir:
445*cda5da8dSAndroid Build Coastguard Worker                    path = join(path, pardir, pardir)
446*cda5da8dSAndroid Build Coastguard Worker            else:
447*cda5da8dSAndroid Build Coastguard Worker                path = pardir
448*cda5da8dSAndroid Build Coastguard Worker            continue
449*cda5da8dSAndroid Build Coastguard Worker        newpath = join(path, name)
450*cda5da8dSAndroid Build Coastguard Worker        try:
451*cda5da8dSAndroid Build Coastguard Worker            st = os.lstat(newpath)
452*cda5da8dSAndroid Build Coastguard Worker        except OSError:
453*cda5da8dSAndroid Build Coastguard Worker            if strict:
454*cda5da8dSAndroid Build Coastguard Worker                raise
455*cda5da8dSAndroid Build Coastguard Worker            is_link = False
456*cda5da8dSAndroid Build Coastguard Worker        else:
457*cda5da8dSAndroid Build Coastguard Worker            is_link = stat.S_ISLNK(st.st_mode)
458*cda5da8dSAndroid Build Coastguard Worker        if not is_link:
459*cda5da8dSAndroid Build Coastguard Worker            path = newpath
460*cda5da8dSAndroid Build Coastguard Worker            continue
461*cda5da8dSAndroid Build Coastguard Worker        # Resolve the symbolic link
462*cda5da8dSAndroid Build Coastguard Worker        if newpath in seen:
463*cda5da8dSAndroid Build Coastguard Worker            # Already seen this path
464*cda5da8dSAndroid Build Coastguard Worker            path = seen[newpath]
465*cda5da8dSAndroid Build Coastguard Worker            if path is not None:
466*cda5da8dSAndroid Build Coastguard Worker                # use cached value
467*cda5da8dSAndroid Build Coastguard Worker                continue
468*cda5da8dSAndroid Build Coastguard Worker            # The symlink is not resolved, so we must have a symlink loop.
469*cda5da8dSAndroid Build Coastguard Worker            if strict:
470*cda5da8dSAndroid Build Coastguard Worker                # Raise OSError(errno.ELOOP)
471*cda5da8dSAndroid Build Coastguard Worker                os.stat(newpath)
472*cda5da8dSAndroid Build Coastguard Worker            else:
473*cda5da8dSAndroid Build Coastguard Worker                # Return already resolved part + rest of the path unchanged.
474*cda5da8dSAndroid Build Coastguard Worker                return join(newpath, rest), False
475*cda5da8dSAndroid Build Coastguard Worker        seen[newpath] = None # not resolved symlink
476*cda5da8dSAndroid Build Coastguard Worker        path, ok = _joinrealpath(path, os.readlink(newpath), strict, seen)
477*cda5da8dSAndroid Build Coastguard Worker        if not ok:
478*cda5da8dSAndroid Build Coastguard Worker            return join(path, rest), False
479*cda5da8dSAndroid Build Coastguard Worker        seen[newpath] = path # resolved symlink
480*cda5da8dSAndroid Build Coastguard Worker
481*cda5da8dSAndroid Build Coastguard Worker    return path, True
482*cda5da8dSAndroid Build Coastguard Worker
483*cda5da8dSAndroid Build Coastguard Worker
484*cda5da8dSAndroid Build Coastguard Workersupports_unicode_filenames = (sys.platform == 'darwin')
485*cda5da8dSAndroid Build Coastguard Worker
486*cda5da8dSAndroid Build Coastguard Workerdef relpath(path, start=None):
487*cda5da8dSAndroid Build Coastguard Worker    """Return a relative version of a path"""
488*cda5da8dSAndroid Build Coastguard Worker
489*cda5da8dSAndroid Build Coastguard Worker    if not path:
490*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("no path specified")
491*cda5da8dSAndroid Build Coastguard Worker
492*cda5da8dSAndroid Build Coastguard Worker    path = os.fspath(path)
493*cda5da8dSAndroid Build Coastguard Worker    if isinstance(path, bytes):
494*cda5da8dSAndroid Build Coastguard Worker        curdir = b'.'
495*cda5da8dSAndroid Build Coastguard Worker        sep = b'/'
496*cda5da8dSAndroid Build Coastguard Worker        pardir = b'..'
497*cda5da8dSAndroid Build Coastguard Worker    else:
498*cda5da8dSAndroid Build Coastguard Worker        curdir = '.'
499*cda5da8dSAndroid Build Coastguard Worker        sep = '/'
500*cda5da8dSAndroid Build Coastguard Worker        pardir = '..'
501*cda5da8dSAndroid Build Coastguard Worker
502*cda5da8dSAndroid Build Coastguard Worker    if start is None:
503*cda5da8dSAndroid Build Coastguard Worker        start = curdir
504*cda5da8dSAndroid Build Coastguard Worker    else:
505*cda5da8dSAndroid Build Coastguard Worker        start = os.fspath(start)
506*cda5da8dSAndroid Build Coastguard Worker
507*cda5da8dSAndroid Build Coastguard Worker    try:
508*cda5da8dSAndroid Build Coastguard Worker        start_list = [x for x in abspath(start).split(sep) if x]
509*cda5da8dSAndroid Build Coastguard Worker        path_list = [x for x in abspath(path).split(sep) if x]
510*cda5da8dSAndroid Build Coastguard Worker        # Work out how much of the filepath is shared by start and path.
511*cda5da8dSAndroid Build Coastguard Worker        i = len(commonprefix([start_list, path_list]))
512*cda5da8dSAndroid Build Coastguard Worker
513*cda5da8dSAndroid Build Coastguard Worker        rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
514*cda5da8dSAndroid Build Coastguard Worker        if not rel_list:
515*cda5da8dSAndroid Build Coastguard Worker            return curdir
516*cda5da8dSAndroid Build Coastguard Worker        return join(*rel_list)
517*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
518*cda5da8dSAndroid Build Coastguard Worker        genericpath._check_arg_types('relpath', path, start)
519*cda5da8dSAndroid Build Coastguard Worker        raise
520*cda5da8dSAndroid Build Coastguard Worker
521*cda5da8dSAndroid Build Coastguard Worker
522*cda5da8dSAndroid Build Coastguard Worker# Return the longest common sub-path of the sequence of paths given as input.
523*cda5da8dSAndroid Build Coastguard Worker# The paths are not normalized before comparing them (this is the
524*cda5da8dSAndroid Build Coastguard Worker# responsibility of the caller). Any trailing separator is stripped from the
525*cda5da8dSAndroid Build Coastguard Worker# returned path.
526*cda5da8dSAndroid Build Coastguard Worker
527*cda5da8dSAndroid Build Coastguard Workerdef commonpath(paths):
528*cda5da8dSAndroid Build Coastguard Worker    """Given a sequence of path names, returns the longest common sub-path."""
529*cda5da8dSAndroid Build Coastguard Worker
530*cda5da8dSAndroid Build Coastguard Worker    if not paths:
531*cda5da8dSAndroid Build Coastguard Worker        raise ValueError('commonpath() arg is an empty sequence')
532*cda5da8dSAndroid Build Coastguard Worker
533*cda5da8dSAndroid Build Coastguard Worker    paths = tuple(map(os.fspath, paths))
534*cda5da8dSAndroid Build Coastguard Worker    if isinstance(paths[0], bytes):
535*cda5da8dSAndroid Build Coastguard Worker        sep = b'/'
536*cda5da8dSAndroid Build Coastguard Worker        curdir = b'.'
537*cda5da8dSAndroid Build Coastguard Worker    else:
538*cda5da8dSAndroid Build Coastguard Worker        sep = '/'
539*cda5da8dSAndroid Build Coastguard Worker        curdir = '.'
540*cda5da8dSAndroid Build Coastguard Worker
541*cda5da8dSAndroid Build Coastguard Worker    try:
542*cda5da8dSAndroid Build Coastguard Worker        split_paths = [path.split(sep) for path in paths]
543*cda5da8dSAndroid Build Coastguard Worker
544*cda5da8dSAndroid Build Coastguard Worker        try:
545*cda5da8dSAndroid Build Coastguard Worker            isabs, = set(p[:1] == sep for p in paths)
546*cda5da8dSAndroid Build Coastguard Worker        except ValueError:
547*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Can't mix absolute and relative paths") from None
548*cda5da8dSAndroid Build Coastguard Worker
549*cda5da8dSAndroid Build Coastguard Worker        split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
550*cda5da8dSAndroid Build Coastguard Worker        s1 = min(split_paths)
551*cda5da8dSAndroid Build Coastguard Worker        s2 = max(split_paths)
552*cda5da8dSAndroid Build Coastguard Worker        common = s1
553*cda5da8dSAndroid Build Coastguard Worker        for i, c in enumerate(s1):
554*cda5da8dSAndroid Build Coastguard Worker            if c != s2[i]:
555*cda5da8dSAndroid Build Coastguard Worker                common = s1[:i]
556*cda5da8dSAndroid Build Coastguard Worker                break
557*cda5da8dSAndroid Build Coastguard Worker
558*cda5da8dSAndroid Build Coastguard Worker        prefix = sep if isabs else sep[:0]
559*cda5da8dSAndroid Build Coastguard Worker        return prefix + sep.join(common)
560*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
561*cda5da8dSAndroid Build Coastguard Worker        genericpath._check_arg_types('commonpath', *paths)
562*cda5da8dSAndroid Build Coastguard Worker        raise
563