blob: 24f4a141d44428b535c97873083a5661b8005343 [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",
8 "getatime","islink","exists","isdir","isfile",
9 "walk","expanduser","expandvars","normpath","abspath"]
Guido van Rossumb5e05e91991-01-01 18:10:40 +000010
Fred Drakeb4e460a2000-09-28 16:25:20 +000011# Normalize the case of a pathname. Dummy in Posix, but <s>.lower() here.
Guido van Rossum599f2ed1992-01-14 18:28:18 +000012
Fred Drakeb4e460a2000-09-28 16:25:20 +000013def normcase(path):
14 return path.lower()
Guido van Rossum599f2ed1992-01-14 18:28:18 +000015
16
Guido van Rossum217a5fa1990-12-26 15:40:07 +000017def isabs(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000018 """Return true if a path is absolute.
19 On the Mac, relative paths begin with a colon,
20 but as a special case, paths with no colons at all are also relative.
21 Anything else is absolute (the string up to the first colon is the
22 volume name)."""
23
Fred Drake8152d322000-12-12 23:20:45 +000024 return ':' in s and s[0] != ':'
Guido van Rossum217a5fa1990-12-26 15:40:07 +000025
Guido van Rossumb5e05e91991-01-01 18:10:40 +000026
Barry Warsaw384d2491997-02-18 21:53:25 +000027def join(s, *p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000028 path = s
29 for t in p:
30 if (not s) or isabs(t):
31 path = t
32 continue
33 if t[:1] == ':':
34 t = t[1:]
35 if ':' not in path:
36 path = ':' + path
Fred Drake8152d322000-12-12 23:20:45 +000037 if path[-1:] != ':':
Guido van Rossum54f22ed2000-02-04 15:10:34 +000038 path = path + ':'
39 path = path + t
40 return path
Guido van Rossum217a5fa1990-12-26 15:40:07 +000041
Guido van Rossumb5e05e91991-01-01 18:10:40 +000042
Guido van Rossumb5e05e91991-01-01 18:10:40 +000043def split(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000044 """Split a pathname into two parts: the directory leading up to the final
45 bit, and the basename (the filename, without colons, in that directory).
46 The result (s, t) is such that join(s, t) yields the original argument."""
Guido van Rossumb5e05e91991-01-01 18:10:40 +000047
Guido van Rossum54f22ed2000-02-04 15:10:34 +000048 if ':' not in s: return '', s
49 colon = 0
50 for i in range(len(s)):
Fred Drakeb4e460a2000-09-28 16:25:20 +000051 if s[i] == ':': colon = i + 1
Guido van Rossum54f22ed2000-02-04 15:10:34 +000052 path, file = s[:colon-1], s[colon:]
53 if path and not ':' in path:
54 path = path + ':'
55 return path, file
Guido van Rossumb5e05e91991-01-01 18:10:40 +000056
Guido van Rossuma48bf791996-07-23 02:28:32 +000057
58def splitext(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000059 """Split a path into root and extension.
60 The extension is everything starting at the last dot in the last
61 pathname component; the root is everything before that.
62 It is always true that root + ext == p."""
Guido van Rossuma48bf791996-07-23 02:28:32 +000063
Guido van Rossum54f22ed2000-02-04 15:10:34 +000064 root, ext = '', ''
65 for c in p:
66 if c == ':':
67 root, ext = root + ext + c, ''
68 elif c == '.':
69 if ext:
70 root, ext = root + ext, c
71 else:
72 ext = c
73 elif ext:
74 ext = ext + c
75 else:
76 root = root + c
77 return root, ext
Guido van Rossuma48bf791996-07-23 02:28:32 +000078
Guido van Rossum0ec31261995-08-10 18:09:16 +000079
80def splitdrive(p):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000081 """Split a pathname into a drive specification and the rest of the
82 path. Useful on DOS/Windows/NT; on the Mac, the drive is always
83 empty (don't use the volume name -- it doesn't have the same
84 syntactic and semantic oddities as DOS drive letters, such as there
85 being a separate current directory per drive)."""
86
87 return '', p
Guido van Rossum0ec31261995-08-10 18:09:16 +000088
89
Guido van Rossumc629d341992-11-05 10:43:02 +000090# Short interfaces to split()
91
92def dirname(s): return split(s)[0]
93def basename(s): return split(s)[1]
94
95
Guido van Rossum217a5fa1990-12-26 15:40:07 +000096def isdir(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000097 """Return true if the pathname refers to an existing directory."""
98
99 try:
100 st = os.stat(s)
101 except os.error:
102 return 0
103 return S_ISDIR(st[ST_MODE])
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000104
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000105
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000106# Get size, mtime, atime of files.
107
108def getsize(filename):
109 """Return the size of a file, reported by os.stat()."""
110 st = os.stat(filename)
Fred Drake69f87c51999-07-23 15:04:05 +0000111 return st[ST_SIZE]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000112
113def getmtime(filename):
114 """Return the last modification time of a file, reported by os.stat()."""
115 st = os.stat(filename)
Fred Drake69f87c51999-07-23 15:04:05 +0000116 return st[ST_MTIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000117
118def getatime(filename):
119 """Return the last access time of a file, reported by os.stat()."""
120 st = os.stat(filename)
Guido van Rossum46d56512000-07-01 10:52:49 +0000121 return st[ST_ATIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000122
123
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000124def islink(s):
Jack Jansen992d58b2002-04-22 13:55:43 +0000125 """Return true if the pathname refers to a symbolic link."""
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000126
Jack Jansen992d58b2002-04-22 13:55:43 +0000127 try:
128 import macfs
129 return macfs.ResolveAliasFile(s)[2]
130 except:
131 return False
Guido van Rossum7e4b2de1995-01-27 02:41:45 +0000132
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000133
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000134def isfile(s):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000135 """Return true if the pathname refers to an existing regular file."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000136
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000137 try:
138 st = os.stat(s)
139 except os.error:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000140 return False
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000141 return S_ISREG(st[ST_MODE])
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000142
Guido van Rossumb5e05e91991-01-01 18:10:40 +0000143
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000144def exists(s):
Tim Petersbc0e9102002-04-04 22:55:58 +0000145 """Return True if the pathname refers to an existing file or directory."""
Guido van Rossumc629d341992-11-05 10:43:02 +0000146
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000147 try:
148 st = os.stat(s)
149 except os.error:
Tim Petersbc0e9102002-04-04 22:55:58 +0000150 return False
151 return True
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000152
Jack Jansen03c06ee2000-08-23 09:13:40 +0000153# Return the longest prefix of all list elements.
154
155def commonprefix(m):
156 "Given a list of pathnames, returns the longest common leading component"
157 if not m: return ''
158 prefix = m[0]
159 for item in m:
160 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000161 if prefix[:i+1] != item[:i+1]:
Jack Jansen03c06ee2000-08-23 09:13:40 +0000162 prefix = prefix[:i]
163 if i == 0: return ''
164 break
165 return prefix
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000166
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000167def expandvars(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000168 """Dummy to retain interface-compatibility with other operating systems."""
169 return path
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000170
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000171
Jack Jansenf4e7d2a1995-12-15 13:23:37 +0000172def expanduser(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000173 """Dummy to retain interface-compatibility with other operating systems."""
174 return path
Guido van Rossum0ec31261995-08-10 18:09:16 +0000175
Neal Norwitz93cf79f2002-03-31 14:06:41 +0000176class norm_error(Exception):
177 """Path cannot be normalized"""
Guido van Rossumc629d341992-11-05 10:43:02 +0000178
179def normpath(s):
Jack Jansen2fc01092000-08-06 21:18:35 +0000180 """Normalize a pathname. Will return the same result for
181 equivalent paths."""
Jack Jansena68bfe21995-08-07 14:09:27 +0000182
Jack Jansen2fc01092000-08-06 21:18:35 +0000183 if ":" not in s:
184 return ":"+s
185
Fred Drakeb4e460a2000-09-28 16:25:20 +0000186 comps = s.split(":")
Jack Jansen2fc01092000-08-06 21:18:35 +0000187 i = 1
188 while i < len(comps)-1:
189 if comps[i] == "" and comps[i-1] != "":
190 if i > 1:
191 del comps[i-1:i+1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000192 i = i - 1
Jack Jansen2fc01092000-08-06 21:18:35 +0000193 else:
194 # best way to handle this is to raise an exception
Greg Ward034cbf12001-08-08 20:55:10 +0000195 raise norm_error, 'Cannot use :: immediately after volume name'
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000196 else:
Jack Jansen2fc01092000-08-06 21:18:35 +0000197 i = i + 1
198
Fred Drakeb4e460a2000-09-28 16:25:20 +0000199 s = ":".join(comps)
Jack Jansen2fc01092000-08-06 21:18:35 +0000200
201 # remove trailing ":" except for ":" and "Volume:"
202 if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
203 s = s[:-1]
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000204 return s
Guido van Rossum0ec31261995-08-10 18:09:16 +0000205
Jack Jansena68bfe21995-08-07 14:09:27 +0000206
207def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000208 """Directory tree walk with callback function.
209
210 For each directory in the directory tree rooted at top (including top
211 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
212 dirname is the name of the directory, and fnames a list of the names of
213 the files and subdirectories in dirname (excluding '.' and '..'). func
214 may modify the fnames list in-place (e.g. via del or slice assignment),
215 and walk will only recurse into the subdirectories whose names remain in
216 fnames; this can be used to implement a filter, or to impose a specific
217 order of visiting. No semantics are defined for, or required of, arg,
218 beyond that arg is always passed to func. It can be used, e.g., to pass
219 a filename pattern, or a mutable object designed to accumulate
220 statistics. Passing None for arg is common."""
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000221
222 try:
223 names = os.listdir(top)
224 except os.error:
225 return
226 func(arg, top, names)
227 for name in names:
228 name = join(top, name)
Jack Jansen992d58b2002-04-22 13:55:43 +0000229 if isdir(name) and not islink(name):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000230 walk(name, func, arg)
Guido van Rossume294cf61999-01-29 18:05:18 +0000231
232
Guido van Rossume294cf61999-01-29 18:05:18 +0000233def abspath(path):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000234 """Return an absolute path."""
Guido van Rossume294cf61999-01-29 18:05:18 +0000235 if not isabs(path):
236 path = join(os.getcwd(), path)
237 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000238
239# realpath is a no-op on systems without islink support
Jack Jansen992d58b2002-04-22 13:55:43 +0000240def realpath(path):
241 path = abspath(path)
242 try:
243 import macfs
244 except ImportError:
245 return path
246 if not path:
247 return path
248 components = path.split(':')
249 path = components[0] + ':'
250 for c in components[1:]:
251 path = join(path, c)
252 path = macfs.ResolveAliasFile(path)[0].as_pathname()
253 return path