]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/macpath.py
dist/mkfile: run binds in subshell
[plan9front.git] / sys / lib / python / macpath.py
1 """Pathname and path-related operations for the Macintosh."""
2
3 import os
4 from stat import *
5
6 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
7            "basename","dirname","commonprefix","getsize","getmtime",
8            "getatime","getctime", "islink","exists","lexists","isdir","isfile",
9            "walk","expanduser","expandvars","normpath","abspath",
10            "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
11            "devnull","realpath","supports_unicode_filenames"]
12
13 # strings representing various path-related bits and pieces
14 curdir = ':'
15 pardir = '::'
16 extsep = '.'
17 sep = ':'
18 pathsep = '\n'
19 defpath = ':'
20 altsep = None
21 devnull = 'Dev:Null'
22
23 # Normalize the case of a pathname.  Dummy in Posix, but <s>.lower() here.
24
25 def normcase(path):
26     return path.lower()
27
28
29 def isabs(s):
30     """Return true if a path is absolute.
31     On the Mac, relative paths begin with a colon,
32     but as a special case, paths with no colons at all are also relative.
33     Anything else is absolute (the string up to the first colon is the
34     volume name)."""
35
36     return ':' in s and s[0] != ':'
37
38
39 def join(s, *p):
40     path = s
41     for t in p:
42         if (not s) or isabs(t):
43             path = t
44             continue
45         if t[:1] == ':':
46             t = t[1:]
47         if ':' not in path:
48             path = ':' + path
49         if path[-1:] != ':':
50             path = path + ':'
51         path = path + t
52     return path
53
54
55 def split(s):
56     """Split a pathname into two parts: the directory leading up to the final
57     bit, and the basename (the filename, without colons, in that directory).
58     The result (s, t) is such that join(s, t) yields the original argument."""
59
60     if ':' not in s: return '', s
61     colon = 0
62     for i in range(len(s)):
63         if s[i] == ':': colon = i + 1
64     path, file = s[:colon-1], s[colon:]
65     if path and not ':' in path:
66         path = path + ':'
67     return path, file
68
69
70 def splitext(p):
71     """Split a path into root and extension.
72     The extension is everything starting at the last dot in the last
73     pathname component; the root is everything before that.
74     It is always true that root + ext == p."""
75
76     i = p.rfind('.')
77     if i<=p.rfind(':'):
78         return p, ''
79     else:
80         return p[:i], p[i:]
81
82
83 def splitdrive(p):
84     """Split a pathname into a drive specification and the rest of the
85     path.  Useful on DOS/Windows/NT; on the Mac, the drive is always
86     empty (don't use the volume name -- it doesn't have the same
87     syntactic and semantic oddities as DOS drive letters, such as there
88     being a separate current directory per drive)."""
89
90     return '', p
91
92
93 # Short interfaces to split()
94
95 def dirname(s): return split(s)[0]
96 def basename(s): return split(s)[1]
97
98 def ismount(s):
99     if not isabs(s):
100         return False
101     components = split(s)
102     return len(components) == 2 and components[1] == ''
103
104 def isdir(s):
105     """Return true if the pathname refers to an existing directory."""
106
107     try:
108         st = os.stat(s)
109     except os.error:
110         return 0
111     return S_ISDIR(st.st_mode)
112
113
114 # Get size, mtime, atime of files.
115
116 def getsize(filename):
117     """Return the size of a file, reported by os.stat()."""
118     return os.stat(filename).st_size
119
120 def getmtime(filename):
121     """Return the last modification time of a file, reported by os.stat()."""
122     return os.stat(filename).st_mtime
123
124 def getatime(filename):
125     """Return the last access time of a file, reported by os.stat()."""
126     return os.stat(filename).st_atime
127
128
129 def islink(s):
130     """Return true if the pathname refers to a symbolic link."""
131
132     try:
133         import Carbon.File
134         return Carbon.File.ResolveAliasFile(s, 0)[2]
135     except:
136         return False
137
138
139 def isfile(s):
140     """Return true if the pathname refers to an existing regular file."""
141
142     try:
143         st = os.stat(s)
144     except os.error:
145         return False
146     return S_ISREG(st.st_mode)
147
148 def getctime(filename):
149     """Return the creation time of a file, reported by os.stat()."""
150     return os.stat(filename).st_ctime
151
152 def exists(s):
153     """Test whether a path exists.  Returns False for broken symbolic links"""
154
155     try:
156         st = os.stat(s)
157     except os.error:
158         return False
159     return True
160
161 # Is `stat`/`lstat` a meaningful difference on the Mac?  This is safe in any
162 # case.
163
164 def lexists(path):
165     """Test whether a path exists.  Returns True for broken symbolic links"""
166
167     try:
168         st = os.lstat(path)
169     except os.error:
170         return False
171     return True
172
173 # Return the longest prefix of all list elements.
174
175 def commonprefix(m):
176     "Given a list of pathnames, returns the longest common leading component"
177     if not m: return ''
178     s1 = min(m)
179     s2 = max(m)
180     n = min(len(s1), len(s2))
181     for i in xrange(n):
182         if s1[i] != s2[i]:
183             return s1[:i]
184     return s1[:n]
185
186
187 def expandvars(path):
188     """Dummy to retain interface-compatibility with other operating systems."""
189     return path
190
191
192 def expanduser(path):
193     """Dummy to retain interface-compatibility with other operating systems."""
194     return path
195
196 class norm_error(Exception):
197     """Path cannot be normalized"""
198
199 def normpath(s):
200     """Normalize a pathname.  Will return the same result for
201     equivalent paths."""
202
203     if ":" not in s:
204         return ":"+s
205
206     comps = s.split(":")
207     i = 1
208     while i < len(comps)-1:
209         if comps[i] == "" and comps[i-1] != "":
210             if i > 1:
211                 del comps[i-1:i+1]
212                 i = i - 1
213             else:
214                 # best way to handle this is to raise an exception
215                 raise norm_error, 'Cannot use :: immediately after volume name'
216         else:
217             i = i + 1
218
219     s = ":".join(comps)
220
221     # remove trailing ":" except for ":" and "Volume:"
222     if s[-1] == ":" and len(comps) > 2 and s != ":"*len(s):
223         s = s[:-1]
224     return s
225
226
227 def walk(top, func, arg):
228     """Directory tree walk with callback function.
229
230     For each directory in the directory tree rooted at top (including top
231     itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
232     dirname is the name of the directory, and fnames a list of the names of
233     the files and subdirectories in dirname (excluding '.' and '..').  func
234     may modify the fnames list in-place (e.g. via del or slice assignment),
235     and walk will only recurse into the subdirectories whose names remain in
236     fnames; this can be used to implement a filter, or to impose a specific
237     order of visiting.  No semantics are defined for, or required of, arg,
238     beyond that arg is always passed to func.  It can be used, e.g., to pass
239     a filename pattern, or a mutable object designed to accumulate
240     statistics.  Passing None for arg is common."""
241
242     try:
243         names = os.listdir(top)
244     except os.error:
245         return
246     func(arg, top, names)
247     for name in names:
248         name = join(top, name)
249         if isdir(name) and not islink(name):
250             walk(name, func, arg)
251
252
253 def abspath(path):
254     """Return an absolute path."""
255     if not isabs(path):
256         path = join(os.getcwd(), path)
257     return normpath(path)
258
259 # realpath is a no-op on systems without islink support
260 def realpath(path):
261     path = abspath(path)
262     try:
263         import Carbon.File
264     except ImportError:
265         return path
266     if not path:
267         return path
268     components = path.split(':')
269     path = components[0] + ':'
270     for c in components[1:]:
271         path = join(path, c)
272         path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname()
273     return path
274
275 supports_unicode_filenames = False