blob: e3145da129533dde33210f871d7103b08a5ce6a0 [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Pathname and path-related operations for the Macintosh."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +00002
Guido van Rossum5c1d2291998-03-03 21:49:01 +00003import os
Guido van Rossum217a5fa1990-12-26 15:40:07 +00004from stat import *
5
Skip Montanaro17ab1232001-01-24 06:27:27 +00006__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
7 "basename","dirname","commonprefix","getsize","getmtime",
Martin v. Löwis96a60e42002-12-31 13:11:54 +00008 "getatime","getctime", "islink","exists","isdir","isfile",
Mark Hammond8696ebc2002-10-08 02:44:31 +00009 "walk","expanduser","expandvars","normpath","abspath",
Neal Norwitz61cdac62003-01-03 18:01:57 +000010 "realpath","supports_unicode_filenames"]
Guido van Rossumb5e05e91991-01-01 18:10:40 +000011
Fred Drakeb4e460a2000-09-28 16:25:20 +000012# Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
Guido van Rossum599f2ed1992-01-14 18:28:18 +000013
Fred Drakeb4e460a2000-09-28 16:25:20 +000014def normcase(path):
15 return path.lower()
Guido van Rossum599f2ed1992-01-14 18:28:18 +000016
17
Guido van Rossum217a5fa1990-12-26 15:40:07 +000018def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000019 """Return true if a path is absolute.
20 On the Mac, relative paths begin with a colon,
21 but as a special case, paths with no colons at all are also relative.
22 Anything else is absolute (the string up to the first colon is the
23 volume name)."""
24
Fred Drake8152d322000-12-12 23:20:45 +000025 return ':' in s and s[0] != ':'
Guido van Rossum217a5fa1990-12-26 15:40:07 +000026
Guido van Rossumb5e05e91991-01-01 18:10:40 +000027
Barry Warsaw384d2491997-02-18 21:53:25 +000028def join(s, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000029 path = s
30 for t in p:
31 if (not s) or isabs(t):
32 path = t
33 continue
34 if t[:1] == ':':
35 t = t[1:]
36 if ':' not in path:
37 path = ':' + path
Fred Drake8152d322000-12-12 23:20:45 +000038 if path[-1:] != ':':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000039 path = path + ':'
40 path = path + t
41 return path
Guido van Rossum217a5fa1990-12-26 15:40:07 +000042
Guido van Rossumb5e05e91991-01-01 18:10:40 +000043
Guido van Rossumb5e05e91991-01-01 18:10:40 +000044def split(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000045 """Split a pathname into two parts: the directory leading up to the final
46 bit, and the basename (the filename, without colons, in that directory).
47 The result (s, t) is such that join(s, t) yields the original argument."""
Guido van Rossumb5e05e91991-01-01 18:10:40 +000048
Guido van Rossum54f22ed2000-02-04 15:10:34 +000049 if ':' not in s: return '', s
50 colon = 0
51 for i in range(len(s)):
Fred Drakeb4e460a2000-09-28 16:25:20 +000052 if s[i] == ':': colon = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +000053 path, file = s[:colon-1], s[colon:]
54 if path and not ':' in path:
55 path = path + ':'
56 return path, file
Guido van Rossumb5e05e91991-01-01 18:10:40 +000057
Guido van Rossuma48bf791996-07-23 02:28:32 +000058
59def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000060 """Split a path into root and extension.
61 The extension is everything starting at the last dot in the last
62 pathname component; the root is everything before that.
63 It is always true that root + ext == p."""
Guido van Rossuma48bf791996-07-23 02:28:32 +000064
Martin v. Löwisde333792002-12-12 20:30:20 +000065 i = p.rfind('.')
66 if i<=p.rfind(':'):
67 return p, ''
68 else:
69 return p[:i], p[i:]
Guido van Rossuma48bf791996-07-23 02:28:32 +000070
Guido van Rossum0ec31261995-08-10 18:09:16 +000071
72def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000073 """Split a pathname into a drive specification and the rest of the
74 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
75 empty (don't use the volume name -- it doesn't have the same
76 syntactic and semantic oddities as DOS drive letters, such as there
77 being a separate current directory per drive)."""
78
79 return '', p
Guido van Rossum0ec31261995-08-10 18:09:16 +000080
81
Guido van Rossumc629d341992-11-05 10:43:02 +000082# Short interfaces to split()
83
84def dirname(s): return split(s)[0]
85def basename(s): return split(s)[1]
86
87
Guido van Rossum217a5fa1990-12-26 15:40:07 +000088def isdir(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000089 """Return true if the pathname refers to an existing directory."""
90
91 try:
92 st = os.stat(s)
93 except os.error:
94 return 0
Raymond Hettinger32200ae2002-06-01 19:51:15 +000095 return S_ISDIR(st.st_mode)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000096
Guido van Rossumb5e05e91991-01-01 18:10:40 +000097
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +000098# Get size, mtime, atime of files.
99
100def getsize(filename):
101 """Return the size of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000102 return os.stat(filename).st_size
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000103
104def getmtime(filename):
105 """Return the last modification time of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000106 return os.stat(filename).st_mtime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000107
108def getatime(filename):
109 """Return the last access time of a file, reported by os.stat()."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000110 return os.stat(filename).st_atime
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000111
112
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000113def islink(s):
Jack Jansen992d58b2002-04-22 13:55:43 +0000114 """Return true if the pathname refers to a symbolic link."""
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000115
Jack Jansen992d58b2002-04-22 13:55:43 +0000116 try:
Anthony Baxterae7639d2002-04-23 02:38:39 +0000117 import macfs
Jack Jansen992d58b2002-04-22 13:55:43 +0000118 return macfs.ResolveAliasFile(s)[2]
119 except:
120 return False
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000121
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000122
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000123def isfile(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000124 """Return true if the pathname refers to an existing regular file."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000125
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000126 try:
127 st = os.stat(s)
128 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000129 return False
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000130 return S_ISREG(st.st_mode)
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000131
Martin v. Löwis96a60e42002-12-31 13:11:54 +0000132def getctime(filename):
133 """Return the creation time of a file, reported by os.stat()."""
134 return os.stat(filename).st_ctime
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000135
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000136def exists(s):
Tim Petersbc0e9102002-04-04 22:55:58 +0000137 """Return True if the pathname refers to an existing file or directory."""
Guido van Rossumc629d341992-11-05 10:43:02 +0000138
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000139 try:
140 st = os.stat(s)
141 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000142 return False
143 return True
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000144
Jack Jansen03c06ee2000-08-23 09:13:40 +0000145# Return the longest prefix of all list elements.
146
147def commonprefix(m):
148 "Given a list of pathnames, returns the longest common leading component"
149 if not m: return ''
150 prefix = m[0]
151 for item in m:
152 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000153 if prefix[:i+1] != item[:i+1]:
Jack Jansen03c06ee2000-08-23 09:13:40 +0000154 prefix = prefix[:i]
155 if i == 0: return ''
156 break
157 return prefix
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000158
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000159def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000160 """Dummy to retain interface-compatibility with other operating systems."""
161 return path
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000162
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000163
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000164def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000165 """Dummy to retain interface-compatibility with other operating systems."""
166 return path
Guido van Rossum0ec31261995-08-10 18:09:16 +0000167
Neal Norwitz93cf79f2002-03-31 14:06:41 +0000168class norm_error(Exception):
169 """Path cannot be normalized"""
Guido van Rossumc629d341992-11-05 10:43:02 +0000170
171def normpath(s):
Jack Jansen2fc01092000-08-06 21:18:35 +0000172 """Normalize a pathname. Will return the same result for
173 equivalent paths."""
Jack Jansena68bfe21995-08-07 14:09:27 +0000174
Jack Jansen2fc01092000-08-06 21:18:35 +0000175 if ":" not in s:
176 return ":"+s
177
Fred Drakeb4e460a2000-09-28 16:25:20 +0000178 comps = s.split(":")
Jack Jansen2fc01092000-08-06 21:18:35 +0000179 i = 1
180 while i < len(comps)-1:
181 if comps[i] == "" and comps[i-1] != "":
182 if i > 1:
183 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000184 i = i - 1
Jack Jansen2fc01092000-08-06 21:18:35 +0000185 else:
186 # best way to handle this is to raise an exception
Greg Ward034cbf12001-08-08 20:55:10 +0000187 raise norm_error, 'Cannot use :: immediately after volume name'
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000188 else:
Jack Jansen2fc01092000-08-06 21:18:35 +0000189 i = i + 1
190
Fred Drakeb4e460a2000-09-28 16:25:20 +0000191 s = ":".join(comps)
Jack Jansen2fc01092000-08-06 21:18:35 +0000192
193 # remove trailing ":" except for ":" and "Volume:"
194 if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
195 s = s[:-1]
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000196 return s
Guido van Rossum0ec31261995-08-10 18:09:16 +0000197
Jack Jansena68bfe21995-08-07 14:09:27 +0000198
199def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000200 """Directory tree walk with callback function.
201
202 For each directory in the directory tree rooted at top (including top
203 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
204 dirname is the name of the directory, and fnames a list of the names of
205 the files and subdirectories in dirname (excluding '.' and '..'). func
206 may modify the fnames list in-place (e.g. via del or slice assignment),
207 and walk will only recurse into the subdirectories whose names remain in
208 fnames; this can be used to implement a filter, or to impose a specific
209 order of visiting. No semantics are defined for, or required of, arg,
210 beyond that arg is always passed to func. It can be used, e.g., to pass
211 a filename pattern, or a mutable object designed to accumulate
212 statistics. Passing None for arg is common."""
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000213
214 try:
215 names = os.listdir(top)
216 except os.error:
217 return
218 func(arg, top, names)
219 for name in names:
220 name = join(top, name)
Jack Jansen992d58b2002-04-22 13:55:43 +0000221 if isdir(name) and not islink(name):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000222 walk(name, func, arg)
Guido van Rossume294cf61999-01-29 18:05:18 +0000223
224
Guido van Rossume294cf61999-01-29 18:05:18 +0000225def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000226 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000227 if not isabs(path):
228 path = join(os.getcwd(), path)
229 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000230
231# realpath is a no-op on systems without islink support
Jack Jansen992d58b2002-04-22 13:55:43 +0000232def realpath(path):
Tim Peters8ac14952002-05-23 15:15:30 +0000233 path = abspath(path)
234 try:
235 import macfs
236 except ImportError:
237 return path
238 if not path:
239 return path
240 components = path.split(':')
241 path = components[0] + ':'
242 for c in components[1:]:
243 path = join(path, c)
244 path = macfs.ResolveAliasFile(path)[0].as_pathname()
245 return path
Mark Hammond8696ebc2002-10-08 02:44:31 +0000246
247supports_unicode_filenames = False