##// END OF EJS Templates
util: split out posix, windows, and win32 modules
Matt Mackall -
r7890:e710f0f5 default
parent child Browse files
Show More
@@ -0,0 +1,222 b''
1 """
2 posix.py - Posix utility function implementations for Mercurial
3
4 Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
5
6 This software may be used and distributed according to the terms of
7 the GNU General Public License version 2, incorporated herein by
8 reference.
9 """
10
11 from i18n import _
12 import os, sys, osutil, errno, stat, getpass
13
14 posixfile = file
15 nulldev = '/dev/null'
16 normpath = os.path.normpath
17 samestat = os.path.samestat
18
19 umask = os.umask(0)
20 os.umask(umask)
21
22 def openhardlinks():
23 '''return true if it is safe to hold open file handles to hardlinks'''
24 return True
25
26 def rcfiles(path):
27 rcs = [os.path.join(path, 'hgrc')]
28 rcdir = os.path.join(path, 'hgrc.d')
29 try:
30 rcs.extend([os.path.join(rcdir, f)
31 for f, kind in osutil.listdir(rcdir)
32 if f.endswith(".rc")])
33 except OSError:
34 pass
35 return rcs
36
37 def system_rcpath():
38 path = []
39 # old mod_python does not set sys.argv
40 if len(getattr(sys, 'argv', [])) > 0:
41 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
42 '/../etc/mercurial'))
43 path.extend(rcfiles('/etc/mercurial'))
44 return path
45
46 def user_rcpath():
47 return [os.path.expanduser('~/.hgrc')]
48
49 def parse_patch_output(output_line):
50 """parses the output produced by patch and returns the file name"""
51 pf = output_line[14:]
52 if os.sys.platform == 'OpenVMS':
53 if pf[0] == '`':
54 pf = pf[1:-1] # Remove the quotes
55 else:
56 if pf.startswith("'") and pf.endswith("'") and " " in pf:
57 pf = pf[1:-1] # Remove the quotes
58 return pf
59
60 def sshargs(sshcmd, host, user, port):
61 '''Build argument list for ssh'''
62 args = user and ("%s@%s" % (user, host)) or host
63 return port and ("%s -p %s" % (args, port)) or args
64
65 def is_exec(f):
66 """check whether a file is executable"""
67 return (os.lstat(f).st_mode & 0100 != 0)
68
69 def set_flags(f, l, x):
70 s = os.lstat(f).st_mode
71 if l:
72 if not stat.S_ISLNK(s):
73 # switch file to link
74 data = file(f).read()
75 os.unlink(f)
76 try:
77 os.symlink(data, f)
78 except:
79 # failed to make a link, rewrite file
80 file(f, "w").write(data)
81 # no chmod needed at this point
82 return
83 if stat.S_ISLNK(s):
84 # switch link to file
85 data = os.readlink(f)
86 os.unlink(f)
87 file(f, "w").write(data)
88 s = 0666 & ~umask # avoid restatting for chmod
89
90 sx = s & 0100
91 if x and not sx:
92 # Turn on +x for every +r bit when making a file executable
93 # and obey umask.
94 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
95 elif not x and sx:
96 # Turn off all +x bits
97 os.chmod(f, s & 0666)
98
99 def set_binary(fd):
100 pass
101
102 def pconvert(path):
103 return path
104
105 def localpath(path):
106 return path
107
108 def shellquote(s):
109 if os.sys.platform == 'OpenVMS':
110 return '"%s"' % s
111 else:
112 return "'%s'" % s.replace("'", "'\\''")
113
114 def quotecommand(cmd):
115 return cmd
116
117 def popen(command, mode='r'):
118 return os.popen(command, mode)
119
120 def testpid(pid):
121 '''return False if pid dead, True if running or not sure'''
122 if os.sys.platform == 'OpenVMS':
123 return True
124 try:
125 os.kill(pid, 0)
126 return True
127 except OSError, inst:
128 return inst.errno != errno.ESRCH
129
130 def explain_exit(code):
131 """return a 2-tuple (desc, code) describing a process's status"""
132 if os.WIFEXITED(code):
133 val = os.WEXITSTATUS(code)
134 return _("exited with status %d") % val, val
135 elif os.WIFSIGNALED(code):
136 val = os.WTERMSIG(code)
137 return _("killed by signal %d") % val, val
138 elif os.WIFSTOPPED(code):
139 val = os.WSTOPSIG(code)
140 return _("stopped by signal %d") % val, val
141 raise ValueError(_("invalid exit code"))
142
143 def isowner(fp, st=None):
144 """Return True if the file object f belongs to the current user.
145
146 The return value of a util.fstat(f) may be passed as the st argument.
147 """
148 if st is None:
149 st = fstat(fp)
150 return st.st_uid == os.getuid()
151
152 def find_exe(command):
153 '''Find executable for command searching like which does.
154 If command is a basename then PATH is searched for command.
155 PATH isn't searched if command is an absolute or relative path.
156 If command isn't found None is returned.'''
157 if sys.platform == 'OpenVMS':
158 return command
159
160 def findexisting(executable):
161 'Will return executable if existing file'
162 if os.path.exists(executable):
163 return executable
164 return None
165
166 if os.sep in command:
167 return findexisting(command)
168
169 for path in os.environ.get('PATH', '').split(os.pathsep):
170 executable = findexisting(os.path.join(path, command))
171 if executable is not None:
172 return executable
173 return None
174
175 def set_signal_handler():
176 pass
177
178 def statfiles(files):
179 'Stat each file in files and yield stat or None if file does not exist.'
180 lstat = os.lstat
181 for nf in files:
182 try:
183 st = lstat(nf)
184 except OSError, err:
185 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
186 raise
187 st = None
188 yield st
189
190 def getuser():
191 '''return name of current user'''
192 return getpass.getuser()
193
194 def expand_glob(pats):
195 '''On Windows, expand the implicit globs in a list of patterns'''
196 return list(pats)
197
198 def username(uid=None):
199 """Return the name of the user with the given uid.
200
201 If uid is None, return the name of the current user."""
202
203 if uid is None:
204 uid = os.getuid()
205 try:
206 return pwd.getpwuid(uid)[0]
207 except KeyError:
208 return str(uid)
209
210 def groupname(gid=None):
211 """Return the name of the group with the given gid.
212
213 If gid is None, return the name of the current group."""
214
215 if gid is None:
216 gid = os.getgid()
217 try:
218 return grp.getgrgid(gid)[0]
219 except KeyError:
220 return str(gid)
221
222
@@ -0,0 +1,266 b''
1 """
2 windows.py - Windows utility function implementations for Mercurial
3
4 Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
5
6 This software may be used and distributed according to the terms of
7 the GNU General Public License version 2, incorporated herein by
8 reference.
9 """
10
11 import msvcrt, sys, os
12 nulldev = 'NUL:'
13
14 umask = 002
15
16 class winstdout:
17 '''stdout on windows misbehaves if sent through a pipe'''
18
19 def __init__(self, fp):
20 self.fp = fp
21
22 def __getattr__(self, key):
23 return getattr(self.fp, key)
24
25 def close(self):
26 try:
27 self.fp.close()
28 except: pass
29
30 def write(self, s):
31 try:
32 # This is workaround for "Not enough space" error on
33 # writing large size of data to console.
34 limit = 16000
35 l = len(s)
36 start = 0
37 while start < l:
38 end = start + limit
39 self.fp.write(s[start:end])
40 start = end
41 except IOError, inst:
42 if inst.errno != 0: raise
43 self.close()
44 raise IOError(errno.EPIPE, 'Broken pipe')
45
46 def flush(self):
47 try:
48 return self.fp.flush()
49 except IOError, inst:
50 if inst.errno != errno.EINVAL: raise
51 self.close()
52 raise IOError(errno.EPIPE, 'Broken pipe')
53
54 sys.stdout = winstdout(sys.stdout)
55
56 def _is_win_9x():
57 '''return true if run on windows 95, 98 or me.'''
58 try:
59 return sys.getwindowsversion()[3] == 1
60 except AttributeError:
61 return 'command' in os.environ.get('comspec', '')
62
63 def openhardlinks():
64 return not _is_win_9x and "win32api" in locals()
65
66 def system_rcpath():
67 try:
68 return system_rcpath_win32()
69 except:
70 return [r'c:\mercurial\mercurial.ini']
71
72 def user_rcpath():
73 '''return os-specific hgrc search path to the user dir'''
74 try:
75 path = user_rcpath_win32()
76 except:
77 home = os.path.expanduser('~')
78 path = [os.path.join(home, 'mercurial.ini'),
79 os.path.join(home, '.hgrc')]
80 userprofile = os.environ.get('USERPROFILE')
81 if userprofile:
82 path.append(os.path.join(userprofile, 'mercurial.ini'))
83 path.append(os.path.join(userprofile, '.hgrc'))
84 return path
85
86 def parse_patch_output(output_line):
87 """parses the output produced by patch and returns the file name"""
88 pf = output_line[14:]
89 if pf[0] == '`':
90 pf = pf[1:-1] # Remove the quotes
91 return pf
92
93 def sshargs(sshcmd, host, user, port):
94 '''Build argument list for ssh or Plink'''
95 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
96 args = user and ("%s@%s" % (user, host)) or host
97 return port and ("%s %s %s" % (args, pflag, port)) or args
98
99 def testpid(pid):
100 '''return False if pid dead, True if running or not known'''
101 return True
102
103 def set_flags(f, l, x):
104 pass
105
106 def set_binary(fd):
107 # When run without console, pipes may expose invalid
108 # fileno(), usually set to -1.
109 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
110 msvcrt.setmode(fd.fileno(), os.O_BINARY)
111
112 def pconvert(path):
113 return '/'.join(path.split(os.sep))
114
115 def localpath(path):
116 return path.replace('/', '\\')
117
118 def normpath(path):
119 return pconvert(os.path.normpath(path))
120
121 def samestat(s1, s2):
122 return False
123
124 # A sequence of backslashes is special iff it precedes a double quote:
125 # - if there's an even number of backslashes, the double quote is not
126 # quoted (i.e. it ends the quoted region)
127 # - if there's an odd number of backslashes, the double quote is quoted
128 # - in both cases, every pair of backslashes is unquoted into a single
129 # backslash
130 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
131 # So, to quote a string, we must surround it in double quotes, double
132 # the number of backslashes that preceed double quotes and add another
133 # backslash before every double quote (being careful with the double
134 # quote we've appended to the end)
135 _quotere = None
136 def shellquote(s):
137 global _quotere
138 if _quotere is None:
139 _quotere = re.compile(r'(\\*)("|\\$)')
140 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
141
142 def quotecommand(cmd):
143 """Build a command string suitable for os.popen* calls."""
144 # The extra quotes are needed because popen* runs the command
145 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
146 return '"' + cmd + '"'
147
148 def popen(command, mode='r'):
149 # Work around "popen spawned process may not write to stdout
150 # under windows"
151 # http://bugs.python.org/issue1366
152 command += " 2> %s" % nulldev
153 return os.popen(quotecommand(command), mode)
154
155 def explain_exit(code):
156 return _("exited with status %d") % code, code
157
158 # if you change this stub into a real check, please try to implement the
159 # username and groupname functions above, too.
160 def isowner(fp, st=None):
161 return True
162
163 def find_exe(command):
164 '''Find executable for command searching like cmd.exe does.
165 If command is a basename then PATH is searched for command.
166 PATH isn't searched if command is an absolute or relative path.
167 An extension from PATHEXT is found and added if not present.
168 If command isn't found None is returned.'''
169 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
170 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
171 if os.path.splitext(command)[1].lower() in pathexts:
172 pathexts = ['']
173
174 def findexisting(pathcommand):
175 'Will append extension (if needed) and return existing file'
176 for ext in pathexts:
177 executable = pathcommand + ext
178 if os.path.exists(executable):
179 return executable
180 return None
181
182 if os.sep in command:
183 return findexisting(command)
184
185 for path in os.environ.get('PATH', '').split(os.pathsep):
186 executable = findexisting(os.path.join(path, command))
187 if executable is not None:
188 return executable
189 return None
190
191 def set_signal_handler():
192 try:
193 set_signal_handler_win32()
194 except NameError:
195 pass
196
197 def statfiles(files):
198 '''Stat each file in files and yield stat or None if file does not exist.
199 Cluster and cache stat per directory to minimize number of OS stat calls.'''
200 ncase = os.path.normcase
201 sep = os.sep
202 dircache = {} # dirname -> filename -> status | None if file does not exist
203 for nf in files:
204 nf = ncase(nf)
205 pos = nf.rfind(sep)
206 if pos == -1:
207 dir, base = '.', nf
208 else:
209 dir, base = nf[:pos+1], nf[pos+1:]
210 cache = dircache.get(dir, None)
211 if cache is None:
212 try:
213 dmap = dict([(ncase(n), s)
214 for n, k, s in osutil.listdir(dir, True)])
215 except OSError, err:
216 # handle directory not found in Python version prior to 2.5
217 # Python <= 2.4 returns native Windows code 3 in errno
218 # Python >= 2.5 returns ENOENT and adds winerror field
219 # EINVAL is raised if dir is not a directory.
220 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
221 errno.ENOTDIR):
222 raise
223 dmap = {}
224 cache = dircache.setdefault(dir, dmap)
225 yield cache.get(base, None)
226
227 def getuser():
228 '''return name of current user'''
229 raise Abort(_('user name not available - set USERNAME '
230 'environment variable'))
231
232 def expand_glob(pats):
233 '''On Windows, expand the implicit globs in a list of patterns'''
234 ret = []
235 for p in pats:
236 kind, name = patkind(p, None)
237 if kind is None:
238 globbed = glob.glob(name)
239 if globbed:
240 ret.extend(globbed)
241 continue
242 # if we couldn't expand the glob, just keep it around
243 ret.append(p)
244 return ret
245
246 def username(uid=None):
247 """Return the name of the user with the given uid.
248
249 If uid is None, return the name of the current user."""
250 return None
251
252 def groupname(gid=None):
253 """Return the name of the group with the given gid.
254
255 If gid is None, return the name of the current group."""
256 return None
257
258 posixfile = file
259 try:
260 # override functions with win32 versions if possible
261 from util_win32 import *
262 if not _is_win_9x():
263 posixfile = posixfile_nt
264 except ImportError:
265 pass
266
@@ -136,7 +136,7 b' def _calcmode(path):'
136 # files in .hg/ will be created using this mode
136 # files in .hg/ will be created using this mode
137 mode = os.stat(path).st_mode
137 mode = os.stat(path).st_mode
138 # avoid some useless chmods
138 # avoid some useless chmods
139 if (0777 & ~util._umask) == (0777 & mode):
139 if (0777 & ~util.umask) == (0777 & mode):
140 mode = None
140 mode = None
141 except OSError:
141 except OSError:
142 mode = None
142 mode = None
This diff has been collapsed as it changes many lines, (517 lines changed) Show them Hide them
@@ -13,7 +13,7 b' platform-specific details from the core.'
13 """
13 """
14
14
15 from i18n import _
15 from i18n import _
16 import cStringIO, errno, getpass, re, shutil, sys, tempfile, traceback, error
16 import cStringIO, errno, re, shutil, sys, tempfile, traceback, error
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
18 import imp, unicodedata
18 import imp, unicodedata
19
19
@@ -339,22 +339,6 b' class Abort(Exception):'
339 def always(fn): return True
339 def always(fn): return True
340 def never(fn): return False
340 def never(fn): return False
341
341
342 def expand_glob(pats):
343 '''On Windows, expand the implicit globs in a list of patterns'''
344 if os.name != 'nt':
345 return list(pats)
346 ret = []
347 for p in pats:
348 kind, name = patkind(p, None)
349 if kind is None:
350 globbed = glob.glob(name)
351 if globbed:
352 ret.extend(globbed)
353 continue
354 # if we couldn't expand the glob, just keep it around
355 ret.append(p)
356 return ret
357
358 def patkind(name, default):
342 def patkind(name, default):
359 """Split a string into an optional pattern kind prefix and the
343 """Split a string into an optional pattern kind prefix and the
360 actual pattern."""
344 actual pattern."""
@@ -858,12 +842,32 b' class path_auditor(object):'
858 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
842 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
859 self.auditeddir.update(prefixes)
843 self.auditeddir.update(prefixes)
860
844
861 def _makelock_file(info, pathname):
845 if os.name == 'nt':
846 from windows import *
847 else:
848 from posix import *
849
850 def makelock(info, pathname):
851 try:
852 return os.symlink(info, pathname)
853 except OSError, why:
854 if why.errno == errno.EEXIST:
855 raise
856 except AttributeError: # no symlink in os
857 pass
858
862 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
859 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
863 os.write(ld, info)
860 os.write(ld, info)
864 os.close(ld)
861 os.close(ld)
865
862
866 def _readlock_file(pathname):
863 def readlock(pathname):
864 try:
865 return os.readlink(pathname)
866 except OSError, why:
867 if why.errno not in (errno.EINVAL, errno.ENOSYS):
868 raise
869 except AttributeError: # no symlink in os
870 pass
867 return posixfile(pathname).read()
871 return posixfile(pathname).read()
868
872
869 def nlinks(pathname):
873 def nlinks(pathname):
@@ -883,103 +887,6 b' def fstat(fp):'
883 except AttributeError:
887 except AttributeError:
884 return os.stat(fp.name)
888 return os.stat(fp.name)
885
889
886 posixfile = file
887
888 def openhardlinks():
889 '''return true if it is safe to hold open file handles to hardlinks'''
890 return True
891
892 def _statfiles(files):
893 'Stat each file in files and yield stat or None if file does not exist.'
894 lstat = os.lstat
895 for nf in files:
896 try:
897 st = lstat(nf)
898 except OSError, err:
899 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
900 raise
901 st = None
902 yield st
903
904 def _statfiles_clustered(files):
905 '''Stat each file in files and yield stat or None if file does not exist.
906 Cluster and cache stat per directory to minimize number of OS stat calls.'''
907 ncase = os.path.normcase
908 sep = os.sep
909 dircache = {} # dirname -> filename -> status | None if file does not exist
910 for nf in files:
911 nf = ncase(nf)
912 pos = nf.rfind(sep)
913 if pos == -1:
914 dir, base = '.', nf
915 else:
916 dir, base = nf[:pos+1], nf[pos+1:]
917 cache = dircache.get(dir, None)
918 if cache is None:
919 try:
920 dmap = dict([(ncase(n), s)
921 for n, k, s in osutil.listdir(dir, True)])
922 except OSError, err:
923 # handle directory not found in Python version prior to 2.5
924 # Python <= 2.4 returns native Windows code 3 in errno
925 # Python >= 2.5 returns ENOENT and adds winerror field
926 # EINVAL is raised if dir is not a directory.
927 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
928 errno.ENOTDIR):
929 raise
930 dmap = {}
931 cache = dircache.setdefault(dir, dmap)
932 yield cache.get(base, None)
933
934 if sys.platform == 'win32':
935 statfiles = _statfiles_clustered
936 else:
937 statfiles = _statfiles
938
939 getuser_fallback = None
940
941 def getuser():
942 '''return name of current user'''
943 try:
944 return getpass.getuser()
945 except ImportError:
946 # import of pwd will fail on windows - try fallback
947 if getuser_fallback:
948 return getuser_fallback()
949 # raised if win32api not available
950 raise Abort(_('user name not available - set USERNAME '
951 'environment variable'))
952
953 def username(uid=None):
954 """Return the name of the user with the given uid.
955
956 If uid is None, return the name of the current user."""
957 try:
958 import pwd
959 if uid is None:
960 uid = os.getuid()
961 try:
962 return pwd.getpwuid(uid)[0]
963 except KeyError:
964 return str(uid)
965 except ImportError:
966 return None
967
968 def groupname(gid=None):
969 """Return the name of the group with the given gid.
970
971 If gid is None, return the name of the current group."""
972 try:
973 import grp
974 if gid is None:
975 gid = os.getgid()
976 try:
977 return grp.getgrgid(gid)[0]
978 except KeyError:
979 return str(gid)
980 except ImportError:
981 return None
982
983 # File system features
890 # File system features
984
891
985 def checkcase(path):
892 def checkcase(path):
@@ -1088,9 +995,6 b' def checklink(path):'
1088 except (OSError, AttributeError):
995 except (OSError, AttributeError):
1089 return False
996 return False
1090
997
1091 _umask = os.umask(0)
1092 os.umask(_umask)
1093
1094 def needbinarypatch():
998 def needbinarypatch():
1095 """return True if patches should be applied in binary mode by default."""
999 """return True if patches should be applied in binary mode by default."""
1096 return os.name == 'nt'
1000 return os.name == 'nt'
@@ -1114,379 +1018,6 b' def gui():'
1114 def lookup_reg(key, name=None, scope=None):
1018 def lookup_reg(key, name=None, scope=None):
1115 return None
1019 return None
1116
1020
1117 # Platform specific variants
1118 if os.name == 'nt':
1119 import msvcrt
1120 nulldev = 'NUL:'
1121
1122 class winstdout:
1123 '''stdout on windows misbehaves if sent through a pipe'''
1124
1125 def __init__(self, fp):
1126 self.fp = fp
1127
1128 def __getattr__(self, key):
1129 return getattr(self.fp, key)
1130
1131 def close(self):
1132 try:
1133 self.fp.close()
1134 except: pass
1135
1136 def write(self, s):
1137 try:
1138 # This is workaround for "Not enough space" error on
1139 # writing large size of data to console.
1140 limit = 16000
1141 l = len(s)
1142 start = 0
1143 while start < l:
1144 end = start + limit
1145 self.fp.write(s[start:end])
1146 start = end
1147 except IOError, inst:
1148 if inst.errno != 0: raise
1149 self.close()
1150 raise IOError(errno.EPIPE, 'Broken pipe')
1151
1152 def flush(self):
1153 try:
1154 return self.fp.flush()
1155 except IOError, inst:
1156 if inst.errno != errno.EINVAL: raise
1157 self.close()
1158 raise IOError(errno.EPIPE, 'Broken pipe')
1159
1160 sys.stdout = winstdout(sys.stdout)
1161
1162 def _is_win_9x():
1163 '''return true if run on windows 95, 98 or me.'''
1164 try:
1165 return sys.getwindowsversion()[3] == 1
1166 except AttributeError:
1167 return 'command' in os.environ.get('comspec', '')
1168
1169 def openhardlinks():
1170 return not _is_win_9x and "win32api" in locals()
1171
1172 def system_rcpath():
1173 try:
1174 return system_rcpath_win32()
1175 except:
1176 return [r'c:\mercurial\mercurial.ini']
1177
1178 def user_rcpath():
1179 '''return os-specific hgrc search path to the user dir'''
1180 try:
1181 path = user_rcpath_win32()
1182 except:
1183 home = os.path.expanduser('~')
1184 path = [os.path.join(home, 'mercurial.ini'),
1185 os.path.join(home, '.hgrc')]
1186 userprofile = os.environ.get('USERPROFILE')
1187 if userprofile:
1188 path.append(os.path.join(userprofile, 'mercurial.ini'))
1189 path.append(os.path.join(userprofile, '.hgrc'))
1190 return path
1191
1192 def parse_patch_output(output_line):
1193 """parses the output produced by patch and returns the file name"""
1194 pf = output_line[14:]
1195 if pf[0] == '`':
1196 pf = pf[1:-1] # Remove the quotes
1197 return pf
1198
1199 def sshargs(sshcmd, host, user, port):
1200 '''Build argument list for ssh or Plink'''
1201 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
1202 args = user and ("%s@%s" % (user, host)) or host
1203 return port and ("%s %s %s" % (args, pflag, port)) or args
1204
1205 def testpid(pid):
1206 '''return False if pid dead, True if running or not known'''
1207 return True
1208
1209 def set_flags(f, l, x):
1210 pass
1211
1212 def set_binary(fd):
1213 # When run without console, pipes may expose invalid
1214 # fileno(), usually set to -1.
1215 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
1216 msvcrt.setmode(fd.fileno(), os.O_BINARY)
1217
1218 def pconvert(path):
1219 return '/'.join(splitpath(path))
1220
1221 def localpath(path):
1222 return path.replace('/', '\\')
1223
1224 def normpath(path):
1225 return pconvert(os.path.normpath(path))
1226
1227 makelock = _makelock_file
1228 readlock = _readlock_file
1229
1230 def samestat(s1, s2):
1231 return False
1232
1233 # A sequence of backslashes is special iff it precedes a double quote:
1234 # - if there's an even number of backslashes, the double quote is not
1235 # quoted (i.e. it ends the quoted region)
1236 # - if there's an odd number of backslashes, the double quote is quoted
1237 # - in both cases, every pair of backslashes is unquoted into a single
1238 # backslash
1239 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
1240 # So, to quote a string, we must surround it in double quotes, double
1241 # the number of backslashes that preceed double quotes and add another
1242 # backslash before every double quote (being careful with the double
1243 # quote we've appended to the end)
1244 _quotere = None
1245 def shellquote(s):
1246 global _quotere
1247 if _quotere is None:
1248 _quotere = re.compile(r'(\\*)("|\\$)')
1249 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
1250
1251 def quotecommand(cmd):
1252 """Build a command string suitable for os.popen* calls."""
1253 # The extra quotes are needed because popen* runs the command
1254 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
1255 return '"' + cmd + '"'
1256
1257 def popen(command, mode='r'):
1258 # Work around "popen spawned process may not write to stdout
1259 # under windows"
1260 # http://bugs.python.org/issue1366
1261 command += " 2> %s" % nulldev
1262 return os.popen(quotecommand(command), mode)
1263
1264 def explain_exit(code):
1265 return _("exited with status %d") % code, code
1266
1267 # if you change this stub into a real check, please try to implement the
1268 # username and groupname functions above, too.
1269 def isowner(fp, st=None):
1270 return True
1271
1272 def find_exe(command):
1273 '''Find executable for command searching like cmd.exe does.
1274 If command is a basename then PATH is searched for command.
1275 PATH isn't searched if command is an absolute or relative path.
1276 An extension from PATHEXT is found and added if not present.
1277 If command isn't found None is returned.'''
1278 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
1279 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
1280 if os.path.splitext(command)[1].lower() in pathexts:
1281 pathexts = ['']
1282
1283 def findexisting(pathcommand):
1284 'Will append extension (if needed) and return existing file'
1285 for ext in pathexts:
1286 executable = pathcommand + ext
1287 if os.path.exists(executable):
1288 return executable
1289 return None
1290
1291 if os.sep in command:
1292 return findexisting(command)
1293
1294 for path in os.environ.get('PATH', '').split(os.pathsep):
1295 executable = findexisting(os.path.join(path, command))
1296 if executable is not None:
1297 return executable
1298 return None
1299
1300 def set_signal_handler():
1301 try:
1302 set_signal_handler_win32()
1303 except NameError:
1304 pass
1305
1306 try:
1307 # override functions with win32 versions if possible
1308 from util_win32 import *
1309 if not _is_win_9x():
1310 posixfile = posixfile_nt
1311 except ImportError:
1312 pass
1313
1314 else:
1315 nulldev = '/dev/null'
1316
1317 def rcfiles(path):
1318 rcs = [os.path.join(path, 'hgrc')]
1319 rcdir = os.path.join(path, 'hgrc.d')
1320 try:
1321 rcs.extend([os.path.join(rcdir, f)
1322 for f, kind in osutil.listdir(rcdir)
1323 if f.endswith(".rc")])
1324 except OSError:
1325 pass
1326 return rcs
1327
1328 def system_rcpath():
1329 path = []
1330 # old mod_python does not set sys.argv
1331 if len(getattr(sys, 'argv', [])) > 0:
1332 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
1333 '/../etc/mercurial'))
1334 path.extend(rcfiles('/etc/mercurial'))
1335 return path
1336
1337 def user_rcpath():
1338 return [os.path.expanduser('~/.hgrc')]
1339
1340 def parse_patch_output(output_line):
1341 """parses the output produced by patch and returns the file name"""
1342 pf = output_line[14:]
1343 if os.sys.platform == 'OpenVMS':
1344 if pf[0] == '`':
1345 pf = pf[1:-1] # Remove the quotes
1346 else:
1347 if pf.startswith("'") and pf.endswith("'") and " " in pf:
1348 pf = pf[1:-1] # Remove the quotes
1349 return pf
1350
1351 def sshargs(sshcmd, host, user, port):
1352 '''Build argument list for ssh'''
1353 args = user and ("%s@%s" % (user, host)) or host
1354 return port and ("%s -p %s" % (args, port)) or args
1355
1356 def is_exec(f):
1357 """check whether a file is executable"""
1358 return (os.lstat(f).st_mode & 0100 != 0)
1359
1360 def set_flags(f, l, x):
1361 s = os.lstat(f).st_mode
1362 if l:
1363 if not stat.S_ISLNK(s):
1364 # switch file to link
1365 data = file(f).read()
1366 os.unlink(f)
1367 try:
1368 os.symlink(data, f)
1369 except:
1370 # failed to make a link, rewrite file
1371 file(f, "w").write(data)
1372 # no chmod needed at this point
1373 return
1374 if stat.S_ISLNK(s):
1375 # switch link to file
1376 data = os.readlink(f)
1377 os.unlink(f)
1378 file(f, "w").write(data)
1379 s = 0666 & ~_umask # avoid restatting for chmod
1380
1381 sx = s & 0100
1382 if x and not sx:
1383 # Turn on +x for every +r bit when making a file executable
1384 # and obey umask.
1385 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
1386 elif not x and sx:
1387 # Turn off all +x bits
1388 os.chmod(f, s & 0666)
1389
1390 def set_binary(fd):
1391 pass
1392
1393 def pconvert(path):
1394 return path
1395
1396 def localpath(path):
1397 return path
1398
1399 normpath = os.path.normpath
1400 samestat = os.path.samestat
1401
1402 def makelock(info, pathname):
1403 try:
1404 os.symlink(info, pathname)
1405 except OSError, why:
1406 if why.errno == errno.EEXIST:
1407 raise
1408 else:
1409 _makelock_file(info, pathname)
1410
1411 def readlock(pathname):
1412 try:
1413 return os.readlink(pathname)
1414 except OSError, why:
1415 if why.errno in (errno.EINVAL, errno.ENOSYS):
1416 return _readlock_file(pathname)
1417 else:
1418 raise
1419
1420 def shellquote(s):
1421 if os.sys.platform == 'OpenVMS':
1422 return '"%s"' % s
1423 else:
1424 return "'%s'" % s.replace("'", "'\\''")
1425
1426 def quotecommand(cmd):
1427 return cmd
1428
1429 def popen(command, mode='r'):
1430 return os.popen(command, mode)
1431
1432 def testpid(pid):
1433 '''return False if pid dead, True if running or not sure'''
1434 if os.sys.platform == 'OpenVMS':
1435 return True
1436 try:
1437 os.kill(pid, 0)
1438 return True
1439 except OSError, inst:
1440 return inst.errno != errno.ESRCH
1441
1442 def explain_exit(code):
1443 """return a 2-tuple (desc, code) describing a process's status"""
1444 if os.WIFEXITED(code):
1445 val = os.WEXITSTATUS(code)
1446 return _("exited with status %d") % val, val
1447 elif os.WIFSIGNALED(code):
1448 val = os.WTERMSIG(code)
1449 return _("killed by signal %d") % val, val
1450 elif os.WIFSTOPPED(code):
1451 val = os.WSTOPSIG(code)
1452 return _("stopped by signal %d") % val, val
1453 raise ValueError(_("invalid exit code"))
1454
1455 def isowner(fp, st=None):
1456 """Return True if the file object f belongs to the current user.
1457
1458 The return value of a util.fstat(f) may be passed as the st argument.
1459 """
1460 if st is None:
1461 st = fstat(fp)
1462 return st.st_uid == os.getuid()
1463
1464 def find_exe(command):
1465 '''Find executable for command searching like which does.
1466 If command is a basename then PATH is searched for command.
1467 PATH isn't searched if command is an absolute or relative path.
1468 If command isn't found None is returned.'''
1469 if sys.platform == 'OpenVMS':
1470 return command
1471
1472 def findexisting(executable):
1473 'Will return executable if existing file'
1474 if os.path.exists(executable):
1475 return executable
1476 return None
1477
1478 if os.sep in command:
1479 return findexisting(command)
1480
1481 for path in os.environ.get('PATH', '').split(os.pathsep):
1482 executable = findexisting(os.path.join(path, command))
1483 if executable is not None:
1484 return executable
1485 return None
1486
1487 def set_signal_handler():
1488 pass
1489
1490 def mktempcopy(name, emptyok=False, createmode=None):
1021 def mktempcopy(name, emptyok=False, createmode=None):
1491 """Create a temporary file with the same contents from name
1022 """Create a temporary file with the same contents from name
1492
1023
@@ -1510,7 +1041,7 b' def mktempcopy(name, emptyok=False, crea'
1510 raise
1041 raise
1511 st_mode = createmode
1042 st_mode = createmode
1512 if st_mode is None:
1043 if st_mode is None:
1513 st_mode = ~_umask
1044 st_mode = ~umask
1514 st_mode &= 0666
1045 st_mode &= 0666
1515 os.chmod(temp, st_mode)
1046 os.chmod(temp, st_mode)
1516 if emptyok:
1047 if emptyok:
@@ -1,15 +1,16 b''
1 # util_win32.py - utility functions that use win32 API
1 '''
2 #
2 win32.py - utility functions that use win32 API
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
5 #
6 # This software may be used and distributed according to the terms of
7 # the GNU General Public License, incorporated herein by reference.
8
5
9 # Mark Hammond's win32all package allows better functionality on
6 This software may be used and distributed according to the terms of
10 # Windows. this module overrides definitions in util.py. if not
7 the GNU General Public License, incorporated herein by reference.
11 # available, import of this module will fail, and generic code will be
8
12 # used.
9 Mark Hammond's win32all package allows better functionality on
10 Windows. this module overrides definitions in util.py. if not
11 available, import of this module will fail, and generic code will be
12 used.
13 '''
13
14
14 import win32api
15 import win32api
15
16
@@ -363,7 +364,9 b' class posixfile_nt(object):'
363 except pywintypes.error, err:
364 except pywintypes.error, err:
364 raise WinIOError(err)
365 raise WinIOError(err)
365
366
366 getuser_fallback = win32api.GetUserName
367 def getuser():
368 '''return name of current user'''
369 return win32api.GetUserName()
367
370
368 def set_signal_handler_win32():
371 def set_signal_handler_win32():
369 """Register a termination handler for console events including
372 """Register a termination handler for console events including
@@ -373,3 +376,4 b' def set_signal_handler_win32():'
373 def handler(event):
376 def handler(event):
374 win32process.ExitProcess(1)
377 win32process.ExitProcess(1)
375 win32api.SetConsoleCtrlHandler(handler)
378 win32api.SetConsoleCtrlHandler(handler)
379
General Comments 0
You need to be logged in to leave comments. Login now