##// END OF EJS Templates
util: add realpath() for getting the 'true' path....
Dan Villiom Podlaski Christiansen -
r9238:40196d03 default
parent child Browse files
Show More
@@ -1,214 +1,252 b''
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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import osutil
9 import osutil
10 import os, sys, errno, stat, getpass, pwd, grp
10 import os, sys, errno, stat, getpass, pwd, grp, fcntl
11
11
12 posixfile = open
12 posixfile = open
13 nulldev = '/dev/null'
13 nulldev = '/dev/null'
14 normpath = os.path.normpath
14 normpath = os.path.normpath
15 samestat = os.path.samestat
15 samestat = os.path.samestat
16 expandglobs = False
16 expandglobs = False
17
17
18 umask = os.umask(0)
18 umask = os.umask(0)
19 os.umask(umask)
19 os.umask(umask)
20
20
21 def openhardlinks():
21 def openhardlinks():
22 '''return true if it is safe to hold open file handles to hardlinks'''
22 '''return true if it is safe to hold open file handles to hardlinks'''
23 return True
23 return True
24
24
25 def rcfiles(path):
25 def rcfiles(path):
26 rcs = [os.path.join(path, 'hgrc')]
26 rcs = [os.path.join(path, 'hgrc')]
27 rcdir = os.path.join(path, 'hgrc.d')
27 rcdir = os.path.join(path, 'hgrc.d')
28 try:
28 try:
29 rcs.extend([os.path.join(rcdir, f)
29 rcs.extend([os.path.join(rcdir, f)
30 for f, kind in osutil.listdir(rcdir)
30 for f, kind in osutil.listdir(rcdir)
31 if f.endswith(".rc")])
31 if f.endswith(".rc")])
32 except OSError:
32 except OSError:
33 pass
33 pass
34 return rcs
34 return rcs
35
35
36 def system_rcpath():
36 def system_rcpath():
37 path = []
37 path = []
38 # old mod_python does not set sys.argv
38 # old mod_python does not set sys.argv
39 if len(getattr(sys, 'argv', [])) > 0:
39 if len(getattr(sys, 'argv', [])) > 0:
40 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
40 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
41 '/../etc/mercurial'))
41 '/../etc/mercurial'))
42 path.extend(rcfiles('/etc/mercurial'))
42 path.extend(rcfiles('/etc/mercurial'))
43 return path
43 return path
44
44
45 def user_rcpath():
45 def user_rcpath():
46 return [os.path.expanduser('~/.hgrc')]
46 return [os.path.expanduser('~/.hgrc')]
47
47
48 def parse_patch_output(output_line):
48 def parse_patch_output(output_line):
49 """parses the output produced by patch and returns the filename"""
49 """parses the output produced by patch and returns the filename"""
50 pf = output_line[14:]
50 pf = output_line[14:]
51 if os.sys.platform == 'OpenVMS':
51 if os.sys.platform == 'OpenVMS':
52 if pf[0] == '`':
52 if pf[0] == '`':
53 pf = pf[1:-1] # Remove the quotes
53 pf = pf[1:-1] # Remove the quotes
54 else:
54 else:
55 if pf.startswith("'") and pf.endswith("'") and " " in pf:
55 if pf.startswith("'") and pf.endswith("'") and " " in pf:
56 pf = pf[1:-1] # Remove the quotes
56 pf = pf[1:-1] # Remove the quotes
57 return pf
57 return pf
58
58
59 def sshargs(sshcmd, host, user, port):
59 def sshargs(sshcmd, host, user, port):
60 '''Build argument list for ssh'''
60 '''Build argument list for ssh'''
61 args = user and ("%s@%s" % (user, host)) or host
61 args = user and ("%s@%s" % (user, host)) or host
62 return port and ("%s -p %s" % (args, port)) or args
62 return port and ("%s -p %s" % (args, port)) or args
63
63
64 def is_exec(f):
64 def is_exec(f):
65 """check whether a file is executable"""
65 """check whether a file is executable"""
66 return (os.lstat(f).st_mode & 0100 != 0)
66 return (os.lstat(f).st_mode & 0100 != 0)
67
67
68 def set_flags(f, l, x):
68 def set_flags(f, l, x):
69 s = os.lstat(f).st_mode
69 s = os.lstat(f).st_mode
70 if l:
70 if l:
71 if not stat.S_ISLNK(s):
71 if not stat.S_ISLNK(s):
72 # switch file to link
72 # switch file to link
73 data = open(f).read()
73 data = open(f).read()
74 os.unlink(f)
74 os.unlink(f)
75 try:
75 try:
76 os.symlink(data, f)
76 os.symlink(data, f)
77 except:
77 except:
78 # failed to make a link, rewrite file
78 # failed to make a link, rewrite file
79 open(f, "w").write(data)
79 open(f, "w").write(data)
80 # no chmod needed at this point
80 # no chmod needed at this point
81 return
81 return
82 if stat.S_ISLNK(s):
82 if stat.S_ISLNK(s):
83 # switch link to file
83 # switch link to file
84 data = os.readlink(f)
84 data = os.readlink(f)
85 os.unlink(f)
85 os.unlink(f)
86 open(f, "w").write(data)
86 open(f, "w").write(data)
87 s = 0666 & ~umask # avoid restatting for chmod
87 s = 0666 & ~umask # avoid restatting for chmod
88
88
89 sx = s & 0100
89 sx = s & 0100
90 if x and not sx:
90 if x and not sx:
91 # Turn on +x for every +r bit when making a file executable
91 # Turn on +x for every +r bit when making a file executable
92 # and obey umask.
92 # and obey umask.
93 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
93 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
94 elif not x and sx:
94 elif not x and sx:
95 # Turn off all +x bits
95 # Turn off all +x bits
96 os.chmod(f, s & 0666)
96 os.chmod(f, s & 0666)
97
97
98 def set_binary(fd):
98 def set_binary(fd):
99 pass
99 pass
100
100
101 def pconvert(path):
101 def pconvert(path):
102 return path
102 return path
103
103
104 def localpath(path):
104 def localpath(path):
105 return path
105 return path
106
106
107 if sys.platform == 'darwin':
108 def realpath(path):
109 '''
110 Returns the true, canonical file system path equivalent to the given
111 path.
112
113 Equivalent means, in this case, resulting in the same, unique
114 file system link to the path. Every file system entry, whether a file,
115 directory, hard link or symbolic link or special, will have a single
116 path preferred by the system, but may allow multiple, differing path
117 lookups to point to it.
118
119 Most regular UNIX file systems only allow a file system entry to be
120 looked up by its distinct path. Obviously, this does not apply to case
121 insensitive file systems, whether case preserving or not. The most
122 complex issue to deal with is file systems transparently reencoding the
123 path, such as the non-standard Unicode normalisation required for HFS+
124 and HFSX.
125 '''
126 # Constants copied from /usr/include/sys/fcntl.h
127 F_GETPATH = 50
128 O_SYMLINK = 0x200000
129
130 try:
131 fd = os.open(path, O_SYMLINK)
132 except OSError, err:
133 if err.errno is errno.ENOENT:
134 return path
135 raise
136
137 try:
138 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
139 finally:
140 os.close(fd)
141 else:
142 # Fallback to the likely inadequate Python builtin function.
143 realpath = os.path.realpath
144
107 def shellquote(s):
145 def shellquote(s):
108 if os.sys.platform == 'OpenVMS':
146 if os.sys.platform == 'OpenVMS':
109 return '"%s"' % s
147 return '"%s"' % s
110 else:
148 else:
111 return "'%s'" % s.replace("'", "'\\''")
149 return "'%s'" % s.replace("'", "'\\''")
112
150
113 def quotecommand(cmd):
151 def quotecommand(cmd):
114 return cmd
152 return cmd
115
153
116 def popen(command, mode='r'):
154 def popen(command, mode='r'):
117 return os.popen(command, mode)
155 return os.popen(command, mode)
118
156
119 def testpid(pid):
157 def testpid(pid):
120 '''return False if pid dead, True if running or not sure'''
158 '''return False if pid dead, True if running or not sure'''
121 if os.sys.platform == 'OpenVMS':
159 if os.sys.platform == 'OpenVMS':
122 return True
160 return True
123 try:
161 try:
124 os.kill(pid, 0)
162 os.kill(pid, 0)
125 return True
163 return True
126 except OSError, inst:
164 except OSError, inst:
127 return inst.errno != errno.ESRCH
165 return inst.errno != errno.ESRCH
128
166
129 def explain_exit(code):
167 def explain_exit(code):
130 """return a 2-tuple (desc, code) describing a process's status"""
168 """return a 2-tuple (desc, code) describing a process's status"""
131 if os.WIFEXITED(code):
169 if os.WIFEXITED(code):
132 val = os.WEXITSTATUS(code)
170 val = os.WEXITSTATUS(code)
133 return _("exited with status %d") % val, val
171 return _("exited with status %d") % val, val
134 elif os.WIFSIGNALED(code):
172 elif os.WIFSIGNALED(code):
135 val = os.WTERMSIG(code)
173 val = os.WTERMSIG(code)
136 return _("killed by signal %d") % val, val
174 return _("killed by signal %d") % val, val
137 elif os.WIFSTOPPED(code):
175 elif os.WIFSTOPPED(code):
138 val = os.WSTOPSIG(code)
176 val = os.WSTOPSIG(code)
139 return _("stopped by signal %d") % val, val
177 return _("stopped by signal %d") % val, val
140 raise ValueError(_("invalid exit code"))
178 raise ValueError(_("invalid exit code"))
141
179
142 def isowner(st):
180 def isowner(st):
143 """Return True if the stat object st is from the current user."""
181 """Return True if the stat object st is from the current user."""
144 return st.st_uid == os.getuid()
182 return st.st_uid == os.getuid()
145
183
146 def find_exe(command):
184 def find_exe(command):
147 '''Find executable for command searching like which does.
185 '''Find executable for command searching like which does.
148 If command is a basename then PATH is searched for command.
186 If command is a basename then PATH is searched for command.
149 PATH isn't searched if command is an absolute or relative path.
187 PATH isn't searched if command is an absolute or relative path.
150 If command isn't found None is returned.'''
188 If command isn't found None is returned.'''
151 if sys.platform == 'OpenVMS':
189 if sys.platform == 'OpenVMS':
152 return command
190 return command
153
191
154 def findexisting(executable):
192 def findexisting(executable):
155 'Will return executable if existing file'
193 'Will return executable if existing file'
156 if os.path.exists(executable):
194 if os.path.exists(executable):
157 return executable
195 return executable
158 return None
196 return None
159
197
160 if os.sep in command:
198 if os.sep in command:
161 return findexisting(command)
199 return findexisting(command)
162
200
163 for path in os.environ.get('PATH', '').split(os.pathsep):
201 for path in os.environ.get('PATH', '').split(os.pathsep):
164 executable = findexisting(os.path.join(path, command))
202 executable = findexisting(os.path.join(path, command))
165 if executable is not None:
203 if executable is not None:
166 return executable
204 return executable
167 return None
205 return None
168
206
169 def set_signal_handler():
207 def set_signal_handler():
170 pass
208 pass
171
209
172 def statfiles(files):
210 def statfiles(files):
173 'Stat each file in files and yield stat or None if file does not exist.'
211 'Stat each file in files and yield stat or None if file does not exist.'
174 lstat = os.lstat
212 lstat = os.lstat
175 for nf in files:
213 for nf in files:
176 try:
214 try:
177 st = lstat(nf)
215 st = lstat(nf)
178 except OSError, err:
216 except OSError, err:
179 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
217 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
180 raise
218 raise
181 st = None
219 st = None
182 yield st
220 yield st
183
221
184 def getuser():
222 def getuser():
185 '''return name of current user'''
223 '''return name of current user'''
186 return getpass.getuser()
224 return getpass.getuser()
187
225
188 def expand_glob(pats):
226 def expand_glob(pats):
189 '''On Windows, expand the implicit globs in a list of patterns'''
227 '''On Windows, expand the implicit globs in a list of patterns'''
190 return list(pats)
228 return list(pats)
191
229
192 def username(uid=None):
230 def username(uid=None):
193 """Return the name of the user with the given uid.
231 """Return the name of the user with the given uid.
194
232
195 If uid is None, return the name of the current user."""
233 If uid is None, return the name of the current user."""
196
234
197 if uid is None:
235 if uid is None:
198 uid = os.getuid()
236 uid = os.getuid()
199 try:
237 try:
200 return pwd.getpwuid(uid)[0]
238 return pwd.getpwuid(uid)[0]
201 except KeyError:
239 except KeyError:
202 return str(uid)
240 return str(uid)
203
241
204 def groupname(gid=None):
242 def groupname(gid=None):
205 """Return the name of the group with the given gid.
243 """Return the name of the group with the given gid.
206
244
207 If gid is None, return the name of the current group."""
245 If gid is None, return the name of the current group."""
208
246
209 if gid is None:
247 if gid is None:
210 gid = os.getgid()
248 gid = os.getgid()
211 try:
249 try:
212 return grp.getgrgid(gid)[0]
250 return grp.getgrgid(gid)[0]
213 except KeyError:
251 except KeyError:
214 return str(gid)
252 return str(gid)
@@ -1,283 +1,292 b''
1 # windows.py - Windows utility function implementations for Mercurial
1 # windows.py - Windows 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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import osutil, error
9 import osutil, error
10 import errno, msvcrt, os, re, sys
10 import errno, msvcrt, os, re, sys
11
11
12 nulldev = 'NUL:'
12 nulldev = 'NUL:'
13 umask = 002
13 umask = 002
14
14
15 # wrap osutil.posixfile to provide friendlier exceptions
15 # wrap osutil.posixfile to provide friendlier exceptions
16 def posixfile(name, mode='r', buffering=-1):
16 def posixfile(name, mode='r', buffering=-1):
17 try:
17 try:
18 return osutil.posixfile(name, mode, buffering)
18 return osutil.posixfile(name, mode, buffering)
19 except WindowsError, err:
19 except WindowsError, err:
20 raise IOError(err.errno, err.strerror)
20 raise IOError(err.errno, err.strerror)
21 posixfile.__doc__ = osutil.posixfile.__doc__
21 posixfile.__doc__ = osutil.posixfile.__doc__
22
22
23 class winstdout(object):
23 class winstdout(object):
24 '''stdout on windows misbehaves if sent through a pipe'''
24 '''stdout on windows misbehaves if sent through a pipe'''
25
25
26 def __init__(self, fp):
26 def __init__(self, fp):
27 self.fp = fp
27 self.fp = fp
28
28
29 def __getattr__(self, key):
29 def __getattr__(self, key):
30 return getattr(self.fp, key)
30 return getattr(self.fp, key)
31
31
32 def close(self):
32 def close(self):
33 try:
33 try:
34 self.fp.close()
34 self.fp.close()
35 except: pass
35 except: pass
36
36
37 def write(self, s):
37 def write(self, s):
38 try:
38 try:
39 # This is workaround for "Not enough space" error on
39 # This is workaround for "Not enough space" error on
40 # writing large size of data to console.
40 # writing large size of data to console.
41 limit = 16000
41 limit = 16000
42 l = len(s)
42 l = len(s)
43 start = 0
43 start = 0
44 self.softspace = 0;
44 self.softspace = 0;
45 while start < l:
45 while start < l:
46 end = start + limit
46 end = start + limit
47 self.fp.write(s[start:end])
47 self.fp.write(s[start:end])
48 start = end
48 start = end
49 except IOError, inst:
49 except IOError, inst:
50 if inst.errno != 0: raise
50 if inst.errno != 0: raise
51 self.close()
51 self.close()
52 raise IOError(errno.EPIPE, 'Broken pipe')
52 raise IOError(errno.EPIPE, 'Broken pipe')
53
53
54 def flush(self):
54 def flush(self):
55 try:
55 try:
56 return self.fp.flush()
56 return self.fp.flush()
57 except IOError, inst:
57 except IOError, inst:
58 if inst.errno != errno.EINVAL: raise
58 if inst.errno != errno.EINVAL: raise
59 self.close()
59 self.close()
60 raise IOError(errno.EPIPE, 'Broken pipe')
60 raise IOError(errno.EPIPE, 'Broken pipe')
61
61
62 sys.stdout = winstdout(sys.stdout)
62 sys.stdout = winstdout(sys.stdout)
63
63
64 def _is_win_9x():
64 def _is_win_9x():
65 '''return true if run on windows 95, 98 or me.'''
65 '''return true if run on windows 95, 98 or me.'''
66 try:
66 try:
67 return sys.getwindowsversion()[3] == 1
67 return sys.getwindowsversion()[3] == 1
68 except AttributeError:
68 except AttributeError:
69 return 'command' in os.environ.get('comspec', '')
69 return 'command' in os.environ.get('comspec', '')
70
70
71 def openhardlinks():
71 def openhardlinks():
72 return not _is_win_9x() and "win32api" in globals()
72 return not _is_win_9x() and "win32api" in globals()
73
73
74 def system_rcpath():
74 def system_rcpath():
75 try:
75 try:
76 return system_rcpath_win32()
76 return system_rcpath_win32()
77 except:
77 except:
78 return [r'c:\mercurial\mercurial.ini']
78 return [r'c:\mercurial\mercurial.ini']
79
79
80 def user_rcpath():
80 def user_rcpath():
81 '''return os-specific hgrc search path to the user dir'''
81 '''return os-specific hgrc search path to the user dir'''
82 try:
82 try:
83 path = user_rcpath_win32()
83 path = user_rcpath_win32()
84 except:
84 except:
85 home = os.path.expanduser('~')
85 home = os.path.expanduser('~')
86 path = [os.path.join(home, 'mercurial.ini'),
86 path = [os.path.join(home, 'mercurial.ini'),
87 os.path.join(home, '.hgrc')]
87 os.path.join(home, '.hgrc')]
88 userprofile = os.environ.get('USERPROFILE')
88 userprofile = os.environ.get('USERPROFILE')
89 if userprofile:
89 if userprofile:
90 path.append(os.path.join(userprofile, 'mercurial.ini'))
90 path.append(os.path.join(userprofile, 'mercurial.ini'))
91 path.append(os.path.join(userprofile, '.hgrc'))
91 path.append(os.path.join(userprofile, '.hgrc'))
92 return path
92 return path
93
93
94 def parse_patch_output(output_line):
94 def parse_patch_output(output_line):
95 """parses the output produced by patch and returns the filename"""
95 """parses the output produced by patch and returns the filename"""
96 pf = output_line[14:]
96 pf = output_line[14:]
97 if pf[0] == '`':
97 if pf[0] == '`':
98 pf = pf[1:-1] # Remove the quotes
98 pf = pf[1:-1] # Remove the quotes
99 return pf
99 return pf
100
100
101 def sshargs(sshcmd, host, user, port):
101 def sshargs(sshcmd, host, user, port):
102 '''Build argument list for ssh or Plink'''
102 '''Build argument list for ssh or Plink'''
103 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
103 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
104 args = user and ("%s@%s" % (user, host)) or host
104 args = user and ("%s@%s" % (user, host)) or host
105 return port and ("%s %s %s" % (args, pflag, port)) or args
105 return port and ("%s %s %s" % (args, pflag, port)) or args
106
106
107 def testpid(pid):
107 def testpid(pid):
108 '''return False if pid dead, True if running or not known'''
108 '''return False if pid dead, True if running or not known'''
109 return True
109 return True
110
110
111 def set_flags(f, l, x):
111 def set_flags(f, l, x):
112 pass
112 pass
113
113
114 def set_binary(fd):
114 def set_binary(fd):
115 # When run without console, pipes may expose invalid
115 # When run without console, pipes may expose invalid
116 # fileno(), usually set to -1.
116 # fileno(), usually set to -1.
117 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
117 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
118 msvcrt.setmode(fd.fileno(), os.O_BINARY)
118 msvcrt.setmode(fd.fileno(), os.O_BINARY)
119
119
120 def pconvert(path):
120 def pconvert(path):
121 return '/'.join(path.split(os.sep))
121 return '/'.join(path.split(os.sep))
122
122
123 def localpath(path):
123 def localpath(path):
124 return path.replace('/', '\\')
124 return path.replace('/', '\\')
125
125
126 def normpath(path):
126 def normpath(path):
127 return pconvert(os.path.normpath(path))
127 return pconvert(os.path.normpath(path))
128
128
129 def realpath(path):
130 '''
131 Returns the true, canonical file system path equivalent to the given
132 path.
133 '''
134 # TODO: There may be a more clever way to do this that also handles other,
135 # less common file systems.
136 return os.path.normpath(os.path.normcase(os.path.realpath(path)))
137
129 def samestat(s1, s2):
138 def samestat(s1, s2):
130 return False
139 return False
131
140
132 # A sequence of backslashes is special iff it precedes a double quote:
141 # A sequence of backslashes is special iff it precedes a double quote:
133 # - if there's an even number of backslashes, the double quote is not
142 # - if there's an even number of backslashes, the double quote is not
134 # quoted (i.e. it ends the quoted region)
143 # quoted (i.e. it ends the quoted region)
135 # - if there's an odd number of backslashes, the double quote is quoted
144 # - if there's an odd number of backslashes, the double quote is quoted
136 # - in both cases, every pair of backslashes is unquoted into a single
145 # - in both cases, every pair of backslashes is unquoted into a single
137 # backslash
146 # backslash
138 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
147 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
139 # So, to quote a string, we must surround it in double quotes, double
148 # So, to quote a string, we must surround it in double quotes, double
140 # the number of backslashes that preceed double quotes and add another
149 # the number of backslashes that preceed double quotes and add another
141 # backslash before every double quote (being careful with the double
150 # backslash before every double quote (being careful with the double
142 # quote we've appended to the end)
151 # quote we've appended to the end)
143 _quotere = None
152 _quotere = None
144 def shellquote(s):
153 def shellquote(s):
145 global _quotere
154 global _quotere
146 if _quotere is None:
155 if _quotere is None:
147 _quotere = re.compile(r'(\\*)("|\\$)')
156 _quotere = re.compile(r'(\\*)("|\\$)')
148 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
157 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
149
158
150 def quotecommand(cmd):
159 def quotecommand(cmd):
151 """Build a command string suitable for os.popen* calls."""
160 """Build a command string suitable for os.popen* calls."""
152 # The extra quotes are needed because popen* runs the command
161 # The extra quotes are needed because popen* runs the command
153 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
162 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
154 return '"' + cmd + '"'
163 return '"' + cmd + '"'
155
164
156 def popen(command, mode='r'):
165 def popen(command, mode='r'):
157 # Work around "popen spawned process may not write to stdout
166 # Work around "popen spawned process may not write to stdout
158 # under windows"
167 # under windows"
159 # http://bugs.python.org/issue1366
168 # http://bugs.python.org/issue1366
160 command += " 2> %s" % nulldev
169 command += " 2> %s" % nulldev
161 return os.popen(quotecommand(command), mode)
170 return os.popen(quotecommand(command), mode)
162
171
163 def explain_exit(code):
172 def explain_exit(code):
164 return _("exited with status %d") % code, code
173 return _("exited with status %d") % code, code
165
174
166 # if you change this stub into a real check, please try to implement the
175 # if you change this stub into a real check, please try to implement the
167 # username and groupname functions above, too.
176 # username and groupname functions above, too.
168 def isowner(st):
177 def isowner(st):
169 return True
178 return True
170
179
171 def find_exe(command):
180 def find_exe(command):
172 '''Find executable for command searching like cmd.exe does.
181 '''Find executable for command searching like cmd.exe does.
173 If command is a basename then PATH is searched for command.
182 If command is a basename then PATH is searched for command.
174 PATH isn't searched if command is an absolute or relative path.
183 PATH isn't searched if command is an absolute or relative path.
175 An extension from PATHEXT is found and added if not present.
184 An extension from PATHEXT is found and added if not present.
176 If command isn't found None is returned.'''
185 If command isn't found None is returned.'''
177 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
186 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
178 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
187 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
179 if os.path.splitext(command)[1].lower() in pathexts:
188 if os.path.splitext(command)[1].lower() in pathexts:
180 pathexts = ['']
189 pathexts = ['']
181
190
182 def findexisting(pathcommand):
191 def findexisting(pathcommand):
183 'Will append extension (if needed) and return existing file'
192 'Will append extension (if needed) and return existing file'
184 for ext in pathexts:
193 for ext in pathexts:
185 executable = pathcommand + ext
194 executable = pathcommand + ext
186 if os.path.exists(executable):
195 if os.path.exists(executable):
187 return executable
196 return executable
188 return None
197 return None
189
198
190 if os.sep in command:
199 if os.sep in command:
191 return findexisting(command)
200 return findexisting(command)
192
201
193 for path in os.environ.get('PATH', '').split(os.pathsep):
202 for path in os.environ.get('PATH', '').split(os.pathsep):
194 executable = findexisting(os.path.join(path, command))
203 executable = findexisting(os.path.join(path, command))
195 if executable is not None:
204 if executable is not None:
196 return executable
205 return executable
197 return None
206 return None
198
207
199 def set_signal_handler():
208 def set_signal_handler():
200 try:
209 try:
201 set_signal_handler_win32()
210 set_signal_handler_win32()
202 except NameError:
211 except NameError:
203 pass
212 pass
204
213
205 def statfiles(files):
214 def statfiles(files):
206 '''Stat each file in files and yield stat or None if file does not exist.
215 '''Stat each file in files and yield stat or None if file does not exist.
207 Cluster and cache stat per directory to minimize number of OS stat calls.'''
216 Cluster and cache stat per directory to minimize number of OS stat calls.'''
208 ncase = os.path.normcase
217 ncase = os.path.normcase
209 sep = os.sep
218 sep = os.sep
210 dircache = {} # dirname -> filename -> status | None if file does not exist
219 dircache = {} # dirname -> filename -> status | None if file does not exist
211 for nf in files:
220 for nf in files:
212 nf = ncase(nf)
221 nf = ncase(nf)
213 dir, base = os.path.split(nf)
222 dir, base = os.path.split(nf)
214 if not dir:
223 if not dir:
215 dir = '.'
224 dir = '.'
216 cache = dircache.get(dir, None)
225 cache = dircache.get(dir, None)
217 if cache is None:
226 if cache is None:
218 try:
227 try:
219 dmap = dict([(ncase(n), s)
228 dmap = dict([(ncase(n), s)
220 for n, k, s in osutil.listdir(dir, True)])
229 for n, k, s in osutil.listdir(dir, True)])
221 except OSError, err:
230 except OSError, err:
222 # handle directory not found in Python version prior to 2.5
231 # handle directory not found in Python version prior to 2.5
223 # Python <= 2.4 returns native Windows code 3 in errno
232 # Python <= 2.4 returns native Windows code 3 in errno
224 # Python >= 2.5 returns ENOENT and adds winerror field
233 # Python >= 2.5 returns ENOENT and adds winerror field
225 # EINVAL is raised if dir is not a directory.
234 # EINVAL is raised if dir is not a directory.
226 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
235 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
227 errno.ENOTDIR):
236 errno.ENOTDIR):
228 raise
237 raise
229 dmap = {}
238 dmap = {}
230 cache = dircache.setdefault(dir, dmap)
239 cache = dircache.setdefault(dir, dmap)
231 yield cache.get(base, None)
240 yield cache.get(base, None)
232
241
233 def getuser():
242 def getuser():
234 '''return name of current user'''
243 '''return name of current user'''
235 raise error.Abort(_('user name not available - set USERNAME '
244 raise error.Abort(_('user name not available - set USERNAME '
236 'environment variable'))
245 'environment variable'))
237
246
238 def username(uid=None):
247 def username(uid=None):
239 """Return the name of the user with the given uid.
248 """Return the name of the user with the given uid.
240
249
241 If uid is None, return the name of the current user."""
250 If uid is None, return the name of the current user."""
242 return None
251 return None
243
252
244 def groupname(gid=None):
253 def groupname(gid=None):
245 """Return the name of the group with the given gid.
254 """Return the name of the group with the given gid.
246
255
247 If gid is None, return the name of the current group."""
256 If gid is None, return the name of the current group."""
248 return None
257 return None
249
258
250 def _removedirs(name):
259 def _removedirs(name):
251 """special version of os.removedirs that does not remove symlinked
260 """special version of os.removedirs that does not remove symlinked
252 directories or junction points if they actually contain files"""
261 directories or junction points if they actually contain files"""
253 if osutil.listdir(name):
262 if osutil.listdir(name):
254 return
263 return
255 os.rmdir(name)
264 os.rmdir(name)
256 head, tail = os.path.split(name)
265 head, tail = os.path.split(name)
257 if not tail:
266 if not tail:
258 head, tail = os.path.split(head)
267 head, tail = os.path.split(head)
259 while head and tail:
268 while head and tail:
260 try:
269 try:
261 if osutil.listdir(name):
270 if osutil.listdir(name):
262 return
271 return
263 os.rmdir(head)
272 os.rmdir(head)
264 except:
273 except:
265 break
274 break
266 head, tail = os.path.split(head)
275 head, tail = os.path.split(head)
267
276
268 def unlink(f):
277 def unlink(f):
269 """unlink and remove the directory if it is empty"""
278 """unlink and remove the directory if it is empty"""
270 os.unlink(f)
279 os.unlink(f)
271 # try removing directories that might now be empty
280 # try removing directories that might now be empty
272 try:
281 try:
273 _removedirs(os.path.dirname(f))
282 _removedirs(os.path.dirname(f))
274 except OSError:
283 except OSError:
275 pass
284 pass
276
285
277 try:
286 try:
278 # override functions with win32 versions if possible
287 # override functions with win32 versions if possible
279 from win32 import *
288 from win32 import *
280 except ImportError:
289 except ImportError:
281 pass
290 pass
282
291
283 expandglobs = True
292 expandglobs = True
General Comments 0
You need to be logged in to leave comments. Login now