##// END OF EJS Templates
posix: ignore execution bit in cygwin (issue3301)
A. S. Budden -
r16240:95e45abe default
parent child Browse files
Show More
@@ -1,453 +1,460
1 # posix.py - Posix utility function implementations for Mercurial
1 # posix.py - Posix utility function implementations for Mercurial
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys, errno, stat, getpass, pwd, grp, tempfile, unicodedata
9 import os, sys, errno, stat, getpass, pwd, grp, tempfile, unicodedata
10
10
11 posixfile = open
11 posixfile = open
12 nulldev = '/dev/null'
12 nulldev = '/dev/null'
13 normpath = os.path.normpath
13 normpath = os.path.normpath
14 samestat = os.path.samestat
14 samestat = os.path.samestat
15 oslink = os.link
15 oslink = os.link
16 unlink = os.unlink
16 unlink = os.unlink
17 rename = os.rename
17 rename = os.rename
18 expandglobs = False
18 expandglobs = False
19
19
20 umask = os.umask(0)
20 umask = os.umask(0)
21 os.umask(umask)
21 os.umask(umask)
22
22
23 def openhardlinks():
23 def openhardlinks():
24 '''return true if it is safe to hold open file handles to hardlinks'''
24 '''return true if it is safe to hold open file handles to hardlinks'''
25 return True
25 return True
26
26
27 def nlinks(name):
27 def nlinks(name):
28 '''return number of hardlinks for the given file'''
28 '''return number of hardlinks for the given file'''
29 return os.lstat(name).st_nlink
29 return os.lstat(name).st_nlink
30
30
31 def parsepatchoutput(output_line):
31 def parsepatchoutput(output_line):
32 """parses the output produced by patch and returns the filename"""
32 """parses the output produced by patch and returns the filename"""
33 pf = output_line[14:]
33 pf = output_line[14:]
34 if os.sys.platform == 'OpenVMS':
34 if os.sys.platform == 'OpenVMS':
35 if pf[0] == '`':
35 if pf[0] == '`':
36 pf = pf[1:-1] # Remove the quotes
36 pf = pf[1:-1] # Remove the quotes
37 else:
37 else:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
39 pf = pf[1:-1] # Remove the quotes
39 pf = pf[1:-1] # Remove the quotes
40 return pf
40 return pf
41
41
42 def sshargs(sshcmd, host, user, port):
42 def sshargs(sshcmd, host, user, port):
43 '''Build argument list for ssh'''
43 '''Build argument list for ssh'''
44 args = user and ("%s@%s" % (user, host)) or host
44 args = user and ("%s@%s" % (user, host)) or host
45 return port and ("%s -p %s" % (args, port)) or args
45 return port and ("%s -p %s" % (args, port)) or args
46
46
47 def isexec(f):
47 def isexec(f):
48 """check whether a file is executable"""
48 """check whether a file is executable"""
49 return (os.lstat(f).st_mode & 0100 != 0)
49 return (os.lstat(f).st_mode & 0100 != 0)
50
50
51 def setflags(f, l, x):
51 def setflags(f, l, x):
52 s = os.lstat(f).st_mode
52 s = os.lstat(f).st_mode
53 if l:
53 if l:
54 if not stat.S_ISLNK(s):
54 if not stat.S_ISLNK(s):
55 # switch file to link
55 # switch file to link
56 fp = open(f)
56 fp = open(f)
57 data = fp.read()
57 data = fp.read()
58 fp.close()
58 fp.close()
59 os.unlink(f)
59 os.unlink(f)
60 try:
60 try:
61 os.symlink(data, f)
61 os.symlink(data, f)
62 except OSError:
62 except OSError:
63 # failed to make a link, rewrite file
63 # failed to make a link, rewrite file
64 fp = open(f, "w")
64 fp = open(f, "w")
65 fp.write(data)
65 fp.write(data)
66 fp.close()
66 fp.close()
67 # no chmod needed at this point
67 # no chmod needed at this point
68 return
68 return
69 if stat.S_ISLNK(s):
69 if stat.S_ISLNK(s):
70 # switch link to file
70 # switch link to file
71 data = os.readlink(f)
71 data = os.readlink(f)
72 os.unlink(f)
72 os.unlink(f)
73 fp = open(f, "w")
73 fp = open(f, "w")
74 fp.write(data)
74 fp.write(data)
75 fp.close()
75 fp.close()
76 s = 0666 & ~umask # avoid restatting for chmod
76 s = 0666 & ~umask # avoid restatting for chmod
77
77
78 sx = s & 0100
78 sx = s & 0100
79 if x and not sx:
79 if x and not sx:
80 # Turn on +x for every +r bit when making a file executable
80 # Turn on +x for every +r bit when making a file executable
81 # and obey umask.
81 # and obey umask.
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
83 elif not x and sx:
83 elif not x and sx:
84 # Turn off all +x bits
84 # Turn off all +x bits
85 os.chmod(f, s & 0666)
85 os.chmod(f, s & 0666)
86
86
87 def copymode(src, dst, mode=None):
87 def copymode(src, dst, mode=None):
88 '''Copy the file mode from the file at path src to dst.
88 '''Copy the file mode from the file at path src to dst.
89 If src doesn't exist, we're using mode instead. If mode is None, we're
89 If src doesn't exist, we're using mode instead. If mode is None, we're
90 using umask.'''
90 using umask.'''
91 try:
91 try:
92 st_mode = os.lstat(src).st_mode & 0777
92 st_mode = os.lstat(src).st_mode & 0777
93 except OSError, inst:
93 except OSError, inst:
94 if inst.errno != errno.ENOENT:
94 if inst.errno != errno.ENOENT:
95 raise
95 raise
96 st_mode = mode
96 st_mode = mode
97 if st_mode is None:
97 if st_mode is None:
98 st_mode = ~umask
98 st_mode = ~umask
99 st_mode &= 0666
99 st_mode &= 0666
100 os.chmod(dst, st_mode)
100 os.chmod(dst, st_mode)
101
101
102 def checkexec(path):
102 def checkexec(path):
103 """
103 """
104 Check whether the given path is on a filesystem with UNIX-like exec flags
104 Check whether the given path is on a filesystem with UNIX-like exec flags
105
105
106 Requires a directory (like /foo/.hg)
106 Requires a directory (like /foo/.hg)
107 """
107 """
108
108
109 # VFAT on some Linux versions can flip mode but it doesn't persist
109 # VFAT on some Linux versions can flip mode but it doesn't persist
110 # a FS remount. Frequently we can detect it if files are created
110 # a FS remount. Frequently we can detect it if files are created
111 # with exec bit on.
111 # with exec bit on.
112
112
113 try:
113 try:
114 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
114 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
115 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
115 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
116 try:
116 try:
117 os.close(fh)
117 os.close(fh)
118 m = os.stat(fn).st_mode & 0777
118 m = os.stat(fn).st_mode & 0777
119 new_file_has_exec = m & EXECFLAGS
119 new_file_has_exec = m & EXECFLAGS
120 os.chmod(fn, m ^ EXECFLAGS)
120 os.chmod(fn, m ^ EXECFLAGS)
121 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
121 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
122 finally:
122 finally:
123 os.unlink(fn)
123 os.unlink(fn)
124 except (IOError, OSError):
124 except (IOError, OSError):
125 # we don't care, the user probably won't be able to commit anyway
125 # we don't care, the user probably won't be able to commit anyway
126 return False
126 return False
127 return not (new_file_has_exec or exec_flags_cannot_flip)
127 return not (new_file_has_exec or exec_flags_cannot_flip)
128
128
129 def checklink(path):
129 def checklink(path):
130 """check whether the given path is on a symlink-capable filesystem"""
130 """check whether the given path is on a symlink-capable filesystem"""
131 # mktemp is not racy because symlink creation will fail if the
131 # mktemp is not racy because symlink creation will fail if the
132 # file already exists
132 # file already exists
133 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
133 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
134 try:
134 try:
135 os.symlink(".", name)
135 os.symlink(".", name)
136 os.unlink(name)
136 os.unlink(name)
137 return True
137 return True
138 except (OSError, AttributeError):
138 except (OSError, AttributeError):
139 return False
139 return False
140
140
141 def checkosfilename(path):
141 def checkosfilename(path):
142 '''Check that the base-relative path is a valid filename on this platform.
142 '''Check that the base-relative path is a valid filename on this platform.
143 Returns None if the path is ok, or a UI string describing the problem.'''
143 Returns None if the path is ok, or a UI string describing the problem.'''
144 pass # on posix platforms, every path is ok
144 pass # on posix platforms, every path is ok
145
145
146 def setbinary(fd):
146 def setbinary(fd):
147 pass
147 pass
148
148
149 def pconvert(path):
149 def pconvert(path):
150 return path
150 return path
151
151
152 def localpath(path):
152 def localpath(path):
153 return path
153 return path
154
154
155 def samefile(fpath1, fpath2):
155 def samefile(fpath1, fpath2):
156 """Returns whether path1 and path2 refer to the same file. This is only
156 """Returns whether path1 and path2 refer to the same file. This is only
157 guaranteed to work for files, not directories."""
157 guaranteed to work for files, not directories."""
158 return os.path.samefile(fpath1, fpath2)
158 return os.path.samefile(fpath1, fpath2)
159
159
160 def samedevice(fpath1, fpath2):
160 def samedevice(fpath1, fpath2):
161 """Returns whether fpath1 and fpath2 are on the same device. This is only
161 """Returns whether fpath1 and fpath2 are on the same device. This is only
162 guaranteed to work for files, not directories."""
162 guaranteed to work for files, not directories."""
163 st1 = os.lstat(fpath1)
163 st1 = os.lstat(fpath1)
164 st2 = os.lstat(fpath2)
164 st2 = os.lstat(fpath2)
165 return st1.st_dev == st2.st_dev
165 return st1.st_dev == st2.st_dev
166
166
167 encodinglower = None
167 encodinglower = None
168 encodingupper = None
168 encodingupper = None
169
169
170 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
170 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
171 def normcase(path):
171 def normcase(path):
172 return path.lower()
172 return path.lower()
173
173
174 if sys.platform == 'darwin':
174 if sys.platform == 'darwin':
175 import fcntl # only needed on darwin, missing on jython
175 import fcntl # only needed on darwin, missing on jython
176
176
177 def normcase(path):
177 def normcase(path):
178 try:
178 try:
179 u = path.decode('utf-8')
179 u = path.decode('utf-8')
180 except UnicodeDecodeError:
180 except UnicodeDecodeError:
181 # percent-encode any characters that don't round-trip
181 # percent-encode any characters that don't round-trip
182 p2 = path.decode('utf-8', 'ignore').encode('utf-8')
182 p2 = path.decode('utf-8', 'ignore').encode('utf-8')
183 s = ""
183 s = ""
184 pos = 0
184 pos = 0
185 for c in path:
185 for c in path:
186 if p2[pos:pos + 1] == c:
186 if p2[pos:pos + 1] == c:
187 s += c
187 s += c
188 pos += 1
188 pos += 1
189 else:
189 else:
190 s += "%%%02X" % ord(c)
190 s += "%%%02X" % ord(c)
191 u = s.decode('utf-8')
191 u = s.decode('utf-8')
192
192
193 # Decompose then lowercase (HFS+ technote specifies lower)
193 # Decompose then lowercase (HFS+ technote specifies lower)
194 return unicodedata.normalize('NFD', u).lower().encode('utf-8')
194 return unicodedata.normalize('NFD', u).lower().encode('utf-8')
195
195
196 def realpath(path):
196 def realpath(path):
197 '''
197 '''
198 Returns the true, canonical file system path equivalent to the given
198 Returns the true, canonical file system path equivalent to the given
199 path.
199 path.
200
200
201 Equivalent means, in this case, resulting in the same, unique
201 Equivalent means, in this case, resulting in the same, unique
202 file system link to the path. Every file system entry, whether a file,
202 file system link to the path. Every file system entry, whether a file,
203 directory, hard link or symbolic link or special, will have a single
203 directory, hard link or symbolic link or special, will have a single
204 path preferred by the system, but may allow multiple, differing path
204 path preferred by the system, but may allow multiple, differing path
205 lookups to point to it.
205 lookups to point to it.
206
206
207 Most regular UNIX file systems only allow a file system entry to be
207 Most regular UNIX file systems only allow a file system entry to be
208 looked up by its distinct path. Obviously, this does not apply to case
208 looked up by its distinct path. Obviously, this does not apply to case
209 insensitive file systems, whether case preserving or not. The most
209 insensitive file systems, whether case preserving or not. The most
210 complex issue to deal with is file systems transparently reencoding the
210 complex issue to deal with is file systems transparently reencoding the
211 path, such as the non-standard Unicode normalisation required for HFS+
211 path, such as the non-standard Unicode normalisation required for HFS+
212 and HFSX.
212 and HFSX.
213 '''
213 '''
214 # Constants copied from /usr/include/sys/fcntl.h
214 # Constants copied from /usr/include/sys/fcntl.h
215 F_GETPATH = 50
215 F_GETPATH = 50
216 O_SYMLINK = 0x200000
216 O_SYMLINK = 0x200000
217
217
218 try:
218 try:
219 fd = os.open(path, O_SYMLINK)
219 fd = os.open(path, O_SYMLINK)
220 except OSError, err:
220 except OSError, err:
221 if err.errno == errno.ENOENT:
221 if err.errno == errno.ENOENT:
222 return path
222 return path
223 raise
223 raise
224
224
225 try:
225 try:
226 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
226 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
227 finally:
227 finally:
228 os.close(fd)
228 os.close(fd)
229 elif sys.version_info < (2, 4, 2, 'final'):
229 elif sys.version_info < (2, 4, 2, 'final'):
230 # Workaround for http://bugs.python.org/issue1213894 (os.path.realpath
230 # Workaround for http://bugs.python.org/issue1213894 (os.path.realpath
231 # didn't resolve symlinks that were the first component of the path.)
231 # didn't resolve symlinks that were the first component of the path.)
232 def realpath(path):
232 def realpath(path):
233 if os.path.isabs(path):
233 if os.path.isabs(path):
234 return os.path.realpath(path)
234 return os.path.realpath(path)
235 else:
235 else:
236 return os.path.realpath('./' + path)
236 return os.path.realpath('./' + path)
237 else:
237 else:
238 # Fallback to the likely inadequate Python builtin function.
238 # Fallback to the likely inadequate Python builtin function.
239 realpath = os.path.realpath
239 realpath = os.path.realpath
240
240
241 if sys.platform == 'cygwin':
241 if sys.platform == 'cygwin':
242 # workaround for cygwin, in which mount point part of path is
242 # workaround for cygwin, in which mount point part of path is
243 # treated as case sensitive, even though underlying NTFS is case
243 # treated as case sensitive, even though underlying NTFS is case
244 # insensitive.
244 # insensitive.
245
245
246 # default mount points
246 # default mount points
247 cygwinmountpoints = sorted([
247 cygwinmountpoints = sorted([
248 "/usr/bin",
248 "/usr/bin",
249 "/usr/lib",
249 "/usr/lib",
250 "/cygdrive",
250 "/cygdrive",
251 ], reverse=True)
251 ], reverse=True)
252
252
253 # use upper-ing as normcase as same as NTFS workaround
253 # use upper-ing as normcase as same as NTFS workaround
254 def normcase(path):
254 def normcase(path):
255 pathlen = len(path)
255 pathlen = len(path)
256 if (pathlen == 0) or (path[0] != os.sep):
256 if (pathlen == 0) or (path[0] != os.sep):
257 # treat as relative
257 # treat as relative
258 return encodingupper(path)
258 return encodingupper(path)
259
259
260 # to preserve case of mountpoint part
260 # to preserve case of mountpoint part
261 for mp in cygwinmountpoints:
261 for mp in cygwinmountpoints:
262 if not path.startswith(mp):
262 if not path.startswith(mp):
263 continue
263 continue
264
264
265 mplen = len(mp)
265 mplen = len(mp)
266 if mplen == pathlen: # mount point itself
266 if mplen == pathlen: # mount point itself
267 return mp
267 return mp
268 if path[mplen] == os.sep:
268 if path[mplen] == os.sep:
269 return mp + encodingupper(path[mplen:])
269 return mp + encodingupper(path[mplen:])
270
270
271 return encodingupper(path)
271 return encodingupper(path)
272
272
273 # Cygwin translates native ACLs to POSIX permissions,
274 # but these translations are not supported by native
275 # tools, so the exec bit tends to be set erroneously.
276 # Therefore, disable executable bit access on Cygwin.
277 def checkexec(path):
278 return False
279
273 def shellquote(s):
280 def shellquote(s):
274 if os.sys.platform == 'OpenVMS':
281 if os.sys.platform == 'OpenVMS':
275 return '"%s"' % s
282 return '"%s"' % s
276 else:
283 else:
277 return "'%s'" % s.replace("'", "'\\''")
284 return "'%s'" % s.replace("'", "'\\''")
278
285
279 def quotecommand(cmd):
286 def quotecommand(cmd):
280 return cmd
287 return cmd
281
288
282 def popen(command, mode='r'):
289 def popen(command, mode='r'):
283 return os.popen(command, mode)
290 return os.popen(command, mode)
284
291
285 def testpid(pid):
292 def testpid(pid):
286 '''return False if pid dead, True if running or not sure'''
293 '''return False if pid dead, True if running or not sure'''
287 if os.sys.platform == 'OpenVMS':
294 if os.sys.platform == 'OpenVMS':
288 return True
295 return True
289 try:
296 try:
290 os.kill(pid, 0)
297 os.kill(pid, 0)
291 return True
298 return True
292 except OSError, inst:
299 except OSError, inst:
293 return inst.errno != errno.ESRCH
300 return inst.errno != errno.ESRCH
294
301
295 def explainexit(code):
302 def explainexit(code):
296 """return a 2-tuple (desc, code) describing a subprocess status
303 """return a 2-tuple (desc, code) describing a subprocess status
297 (codes from kill are negative - not os.system/wait encoding)"""
304 (codes from kill are negative - not os.system/wait encoding)"""
298 if code >= 0:
305 if code >= 0:
299 return _("exited with status %d") % code, code
306 return _("exited with status %d") % code, code
300 return _("killed by signal %d") % -code, -code
307 return _("killed by signal %d") % -code, -code
301
308
302 def isowner(st):
309 def isowner(st):
303 """Return True if the stat object st is from the current user."""
310 """Return True if the stat object st is from the current user."""
304 return st.st_uid == os.getuid()
311 return st.st_uid == os.getuid()
305
312
306 def findexe(command):
313 def findexe(command):
307 '''Find executable for command searching like which does.
314 '''Find executable for command searching like which does.
308 If command is a basename then PATH is searched for command.
315 If command is a basename then PATH is searched for command.
309 PATH isn't searched if command is an absolute or relative path.
316 PATH isn't searched if command is an absolute or relative path.
310 If command isn't found None is returned.'''
317 If command isn't found None is returned.'''
311 if sys.platform == 'OpenVMS':
318 if sys.platform == 'OpenVMS':
312 return command
319 return command
313
320
314 def findexisting(executable):
321 def findexisting(executable):
315 'Will return executable if existing file'
322 'Will return executable if existing file'
316 if os.path.isfile(executable) and os.access(executable, os.X_OK):
323 if os.path.isfile(executable) and os.access(executable, os.X_OK):
317 return executable
324 return executable
318 return None
325 return None
319
326
320 if os.sep in command:
327 if os.sep in command:
321 return findexisting(command)
328 return findexisting(command)
322
329
323 for path in os.environ.get('PATH', '').split(os.pathsep):
330 for path in os.environ.get('PATH', '').split(os.pathsep):
324 executable = findexisting(os.path.join(path, command))
331 executable = findexisting(os.path.join(path, command))
325 if executable is not None:
332 if executable is not None:
326 return executable
333 return executable
327 return None
334 return None
328
335
329 def setsignalhandler():
336 def setsignalhandler():
330 pass
337 pass
331
338
332 def statfiles(files):
339 def statfiles(files):
333 'Stat each file in files and yield stat or None if file does not exist.'
340 'Stat each file in files and yield stat or None if file does not exist.'
334 lstat = os.lstat
341 lstat = os.lstat
335 for nf in files:
342 for nf in files:
336 try:
343 try:
337 st = lstat(nf)
344 st = lstat(nf)
338 except OSError, err:
345 except OSError, err:
339 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
346 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
340 raise
347 raise
341 st = None
348 st = None
342 yield st
349 yield st
343
350
344 def getuser():
351 def getuser():
345 '''return name of current user'''
352 '''return name of current user'''
346 return getpass.getuser()
353 return getpass.getuser()
347
354
348 def username(uid=None):
355 def username(uid=None):
349 """Return the name of the user with the given uid.
356 """Return the name of the user with the given uid.
350
357
351 If uid is None, return the name of the current user."""
358 If uid is None, return the name of the current user."""
352
359
353 if uid is None:
360 if uid is None:
354 uid = os.getuid()
361 uid = os.getuid()
355 try:
362 try:
356 return pwd.getpwuid(uid)[0]
363 return pwd.getpwuid(uid)[0]
357 except KeyError:
364 except KeyError:
358 return str(uid)
365 return str(uid)
359
366
360 def groupname(gid=None):
367 def groupname(gid=None):
361 """Return the name of the group with the given gid.
368 """Return the name of the group with the given gid.
362
369
363 If gid is None, return the name of the current group."""
370 If gid is None, return the name of the current group."""
364
371
365 if gid is None:
372 if gid is None:
366 gid = os.getgid()
373 gid = os.getgid()
367 try:
374 try:
368 return grp.getgrgid(gid)[0]
375 return grp.getgrgid(gid)[0]
369 except KeyError:
376 except KeyError:
370 return str(gid)
377 return str(gid)
371
378
372 def groupmembers(name):
379 def groupmembers(name):
373 """Return the list of members of the group with the given
380 """Return the list of members of the group with the given
374 name, KeyError if the group does not exist.
381 name, KeyError if the group does not exist.
375 """
382 """
376 return list(grp.getgrnam(name).gr_mem)
383 return list(grp.getgrnam(name).gr_mem)
377
384
378 def spawndetached(args):
385 def spawndetached(args):
379 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
386 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
380 args[0], args)
387 args[0], args)
381
388
382 def gethgcmd():
389 def gethgcmd():
383 return sys.argv[:1]
390 return sys.argv[:1]
384
391
385 def termwidth():
392 def termwidth():
386 try:
393 try:
387 import termios, array, fcntl
394 import termios, array, fcntl
388 for dev in (sys.stderr, sys.stdout, sys.stdin):
395 for dev in (sys.stderr, sys.stdout, sys.stdin):
389 try:
396 try:
390 try:
397 try:
391 fd = dev.fileno()
398 fd = dev.fileno()
392 except AttributeError:
399 except AttributeError:
393 continue
400 continue
394 if not os.isatty(fd):
401 if not os.isatty(fd):
395 continue
402 continue
396 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
403 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
397 width = array.array('h', arri)[1]
404 width = array.array('h', arri)[1]
398 if width > 0:
405 if width > 0:
399 return width
406 return width
400 except ValueError:
407 except ValueError:
401 pass
408 pass
402 except IOError, e:
409 except IOError, e:
403 if e[0] == errno.EINVAL:
410 if e[0] == errno.EINVAL:
404 pass
411 pass
405 else:
412 else:
406 raise
413 raise
407 except ImportError:
414 except ImportError:
408 pass
415 pass
409 return 80
416 return 80
410
417
411 def makedir(path, notindexed):
418 def makedir(path, notindexed):
412 os.mkdir(path)
419 os.mkdir(path)
413
420
414 def unlinkpath(f):
421 def unlinkpath(f):
415 """unlink and remove the directory if it is empty"""
422 """unlink and remove the directory if it is empty"""
416 os.unlink(f)
423 os.unlink(f)
417 # try removing directories that might now be empty
424 # try removing directories that might now be empty
418 try:
425 try:
419 os.removedirs(os.path.dirname(f))
426 os.removedirs(os.path.dirname(f))
420 except OSError:
427 except OSError:
421 pass
428 pass
422
429
423 def lookupreg(key, name=None, scope=None):
430 def lookupreg(key, name=None, scope=None):
424 return None
431 return None
425
432
426 def hidewindow():
433 def hidewindow():
427 """Hide current shell window.
434 """Hide current shell window.
428
435
429 Used to hide the window opened when starting asynchronous
436 Used to hide the window opened when starting asynchronous
430 child process under Windows, unneeded on other systems.
437 child process under Windows, unneeded on other systems.
431 """
438 """
432 pass
439 pass
433
440
434 class cachestat(object):
441 class cachestat(object):
435 def __init__(self, path):
442 def __init__(self, path):
436 self.stat = os.stat(path)
443 self.stat = os.stat(path)
437
444
438 def cacheable(self):
445 def cacheable(self):
439 return bool(self.stat.st_ino)
446 return bool(self.stat.st_ino)
440
447
441 __hash__ = object.__hash__
448 __hash__ = object.__hash__
442
449
443 def __eq__(self, other):
450 def __eq__(self, other):
444 try:
451 try:
445 return self.stat == other.stat
452 return self.stat == other.stat
446 except AttributeError:
453 except AttributeError:
447 return False
454 return False
448
455
449 def __ne__(self, other):
456 def __ne__(self, other):
450 return not self == other
457 return not self == other
451
458
452 def executablepath():
459 def executablepath():
453 return None # available on Windows only
460 return None # available on Windows only
General Comments 0
You need to be logged in to leave comments. Login now