##// END OF EJS Templates
Merge with crew-stable
Patrick Mezard -
r9178:cf7c6acb merge default
parent child Browse files
Show More
@@ -1,106 +1,109 b''
1 The standalone Windows installer for Mercurial is built in a somewhat
1 The standalone Windows installer for Mercurial is built in a somewhat
2 jury-rigged fashion.
2 jury-rigged fashion.
3
3
4 It has the following prerequisites, at least as I build it:
4 It has the following prerequisites, at least as I build it:
5
5
6 Python for Windows
6 Python for Windows
7 http://www.python.org/ftp/python/2.4.3/python-2.4.3.msi
7 http://www.python.org/ftp/python/2.4.3/python-2.4.3.msi
8
8
9 MinGW
9 MinGW
10 http://www.mingw.org/
10 http://www.mingw.org/
11
11
12 Python for Windows Extensions
12 Python for Windows Extensions
13 http://sourceforge.net/projects/pywin32/
13 http://sourceforge.net/projects/pywin32/
14
14
15 mfc71.dll (just download, don't install; not needed for Python 2.6)
15 mfc71.dll (just download, don't install; not needed for Python 2.6)
16 http://starship.python.net/crew/mhammond/win32/
16 http://starship.python.net/crew/mhammond/win32/
17
17
18 Visual C++ 2008 redistributable package (needed for Python 2.6)
18 Visual C++ 2008 redistributable package (needed for Python 2.6)
19 http://www.microsoft.com/downloads/details.aspx?familyid=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en
19 http://www.microsoft.com/downloads/details.aspx?familyid=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en
20
20
21 The py2exe distutils extension
21 The py2exe distutils extension
22 http://sourceforge.net/projects/py2exe/
22 http://sourceforge.net/projects/py2exe/
23
23
24 GnuWin32 gettext utility
25 http://gnuwin32.sourceforge.net/packages/gettext.htm
26
24 Inno Setup
27 Inno Setup
25 http://www.jrsoftware.org/isinfo.php
28 http://www.jrsoftware.org/isinfo.php
26
29
27 ISTool - optional
30 ISTool - optional
28 http://www.istool.org/default.aspx/
31 http://www.istool.org/default.aspx/
29
32
30 add_path (you need only add_path.exe in the zip file)
33 add_path (you need only add_path.exe in the zip file)
31 http://www.barisione.org/apps.html#add_path
34 http://www.barisione.org/apps.html#add_path
32
35
33 Asciidoc - optional
36 Asciidoc - optional
34 http://www.methods.co.nz/asciidoc/
37 http://www.methods.co.nz/asciidoc/
35
38
36 And, of course, Mercurial itself.
39 And, of course, Mercurial itself.
37
40
38 Once you have all this installed and built, clone a copy of the
41 Once you have all this installed and built, clone a copy of the
39 Mercurial repository you want to package, and name the repo
42 Mercurial repository you want to package, and name the repo
40 C:\hg\hg-release.
43 C:\hg\hg-release.
41
44
42 In a shell, build a standalone copy of the hg.exe program:
45 In a shell, build a standalone copy of the hg.exe program:
43
46
44 python setup.py build -c mingw32
47 python setup.py build -c mingw32
45 python setup.py py2exe -b 1
48 python setup.py py2exe -b 1
46
49
47 Note: the previously suggested combined command of "python setup.py build -c
50 Note: the previously suggested combined command of "python setup.py build -c
48 mingw32 py2exe -b 1" doesn't work correctly anymore as it doesn't include the
51 mingw32 py2exe -b 1" doesn't work correctly anymore as it doesn't include the
49 extensions in the mercurial subdirectory.
52 extensions in the mercurial subdirectory.
50
53
51 If you want to create a file named setup.cfg with the contents:
54 If you want to create a file named setup.cfg with the contents:
52
55
53 [build]
56 [build]
54 compiler=mingw32
57 compiler=mingw32
55
58
56 you can skip the first build step.
59 you can skip the first build step.
57
60
58 Copy add_path.exe into the dist directory that just got created.
61 Copy add_path.exe into the dist directory that just got created.
59
62
60 If you are using Python up to version 2.5.4, copy mfc71.dll into the dist
63 If you are using Python up to version 2.5.4, copy mfc71.dll into the dist
61 directory that just got created.
64 directory that just got created.
62
65
63 If you are using Python 2.6 or later, after installing the Visual C++ 2008
66 If you are using Python 2.6 or later, after installing the Visual C++ 2008
64 redistributable package copy into the dist directory that just got created the
67 redistributable package copy into the dist directory that just got created the
65 following files:
68 following files:
66 - from the directory starting with
69 - from the directory starting with
67 Windows/WinSxS/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8
70 Windows/WinSxS/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8
68 the files named: msvcm90.dll, msvcp90.dll and msvcr90.dll
71 the files named: msvcm90.dll, msvcp90.dll and msvcr90.dll
69 - from the directory starting with
72 - from the directory starting with
70 Windows/WinSxS/x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8
73 Windows/WinSxS/x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8
71 the files named: mfc90.dll, mfc90u.dll, mfcm90.dll and mfcm90u.dll
74 the files named: mfc90.dll, mfc90u.dll, mfcm90.dll and mfcm90u.dll
72 - from the directory named Windows/WinSxS/Manifests, the manifest file
75 - from the directory named Windows/WinSxS/Manifests, the manifest file
73 starting with x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8
76 starting with x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8
74 (rename it to Microsoft.VC90.CRT.manifest) and the manifest file starting
77 (rename it to Microsoft.VC90.CRT.manifest) and the manifest file starting
75 with x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8 (rename it to
78 with x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8 (rename it to
76 Microsoft.VC90.MFC.manifest)
79 Microsoft.VC90.MFC.manifest)
77
80
78 Before building the installer, you have to build Mercurial HTML documentation
81 Before building the installer, you have to build Mercurial HTML documentation
79 (or fix mercurial.iss to not reference the doc directory). Assuming you have an
82 (or fix mercurial.iss to not reference the doc directory). Assuming you have an
80 "asciidoc.bat" batch file somewhere in your PATH:
83 "asciidoc.bat" batch file somewhere in your PATH:
81
84
82 cd doc
85 cd doc
83 mingw32-make ASCIIDOC=asciidoc.bat html
86 mingw32-make ASCIIDOC=asciidoc.bat html
84 cd ..
87 cd ..
85
88
86 If you use ISTool, you open the C:\hg\hg-release\contrib\win32\mercurial.iss
89 If you use ISTool, you open the C:\hg\hg-release\contrib\win32\mercurial.iss
87 file and type Ctrl-F9 to compile the installer file.
90 file and type Ctrl-F9 to compile the installer file.
88
91
89 Otherwise you run the Inno Setup compiler. Assuming it's on the path you run:
92 Otherwise you run the Inno Setup compiler. Assuming it's on the path you run:
90
93
91 iscc contrib\win32\mercurial.iss
94 iscc contrib\win32\mercurial.iss
92
95
93 The actual installer will be in the C:\hg\hg-release\Output directory.
96 The actual installer will be in the C:\hg\hg-release\Output directory.
94
97
95 To automate the steps above you may want to create a batchfile based on the
98 To automate the steps above you may want to create a batchfile based on the
96 following:
99 following:
97
100
98 echo [build] > setup.cfg
101 echo [build] > setup.cfg
99 echo compiler=mingw32 >> setup.cfg
102 echo compiler=mingw32 >> setup.cfg
100 python setup.py py2exe -b 1
103 python setup.py py2exe -b 1
101 cd doc
104 cd doc
102 mingw32-make ASCIIDOC=asciidoc.bat html
105 mingw32-make ASCIIDOC=asciidoc.bat html
103 cd ..
106 cd ..
104 iscc contrib\win32\mercurial.iss
107 iscc contrib\win32\mercurial.iss
105
108
106 and run it from the root of the hg repository (c:\hg\hg-release).
109 and run it from the root of the hg repository (c:\hg\hg-release).
@@ -1,282 +1,283 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 while start < l:
45 while start < l:
45 end = start + limit
46 end = start + limit
46 self.fp.write(s[start:end])
47 self.fp.write(s[start:end])
47 start = end
48 start = end
48 except IOError, inst:
49 except IOError, inst:
49 if inst.errno != 0: raise
50 if inst.errno != 0: raise
50 self.close()
51 self.close()
51 raise IOError(errno.EPIPE, 'Broken pipe')
52 raise IOError(errno.EPIPE, 'Broken pipe')
52
53
53 def flush(self):
54 def flush(self):
54 try:
55 try:
55 return self.fp.flush()
56 return self.fp.flush()
56 except IOError, inst:
57 except IOError, inst:
57 if inst.errno != errno.EINVAL: raise
58 if inst.errno != errno.EINVAL: raise
58 self.close()
59 self.close()
59 raise IOError(errno.EPIPE, 'Broken pipe')
60 raise IOError(errno.EPIPE, 'Broken pipe')
60
61
61 sys.stdout = winstdout(sys.stdout)
62 sys.stdout = winstdout(sys.stdout)
62
63
63 def _is_win_9x():
64 def _is_win_9x():
64 '''return true if run on windows 95, 98 or me.'''
65 '''return true if run on windows 95, 98 or me.'''
65 try:
66 try:
66 return sys.getwindowsversion()[3] == 1
67 return sys.getwindowsversion()[3] == 1
67 except AttributeError:
68 except AttributeError:
68 return 'command' in os.environ.get('comspec', '')
69 return 'command' in os.environ.get('comspec', '')
69
70
70 def openhardlinks():
71 def openhardlinks():
71 return not _is_win_9x() and "win32api" in globals()
72 return not _is_win_9x() and "win32api" in globals()
72
73
73 def system_rcpath():
74 def system_rcpath():
74 try:
75 try:
75 return system_rcpath_win32()
76 return system_rcpath_win32()
76 except:
77 except:
77 return [r'c:\mercurial\mercurial.ini']
78 return [r'c:\mercurial\mercurial.ini']
78
79
79 def user_rcpath():
80 def user_rcpath():
80 '''return os-specific hgrc search path to the user dir'''
81 '''return os-specific hgrc search path to the user dir'''
81 try:
82 try:
82 path = user_rcpath_win32()
83 path = user_rcpath_win32()
83 except:
84 except:
84 home = os.path.expanduser('~')
85 home = os.path.expanduser('~')
85 path = [os.path.join(home, 'mercurial.ini'),
86 path = [os.path.join(home, 'mercurial.ini'),
86 os.path.join(home, '.hgrc')]
87 os.path.join(home, '.hgrc')]
87 userprofile = os.environ.get('USERPROFILE')
88 userprofile = os.environ.get('USERPROFILE')
88 if userprofile:
89 if userprofile:
89 path.append(os.path.join(userprofile, 'mercurial.ini'))
90 path.append(os.path.join(userprofile, 'mercurial.ini'))
90 path.append(os.path.join(userprofile, '.hgrc'))
91 path.append(os.path.join(userprofile, '.hgrc'))
91 return path
92 return path
92
93
93 def parse_patch_output(output_line):
94 def parse_patch_output(output_line):
94 """parses the output produced by patch and returns the filename"""
95 """parses the output produced by patch and returns the filename"""
95 pf = output_line[14:]
96 pf = output_line[14:]
96 if pf[0] == '`':
97 if pf[0] == '`':
97 pf = pf[1:-1] # Remove the quotes
98 pf = pf[1:-1] # Remove the quotes
98 return pf
99 return pf
99
100
100 def sshargs(sshcmd, host, user, port):
101 def sshargs(sshcmd, host, user, port):
101 '''Build argument list for ssh or Plink'''
102 '''Build argument list for ssh or Plink'''
102 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
103 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
103 args = user and ("%s@%s" % (user, host)) or host
104 args = user and ("%s@%s" % (user, host)) or host
104 return port and ("%s %s %s" % (args, pflag, port)) or args
105 return port and ("%s %s %s" % (args, pflag, port)) or args
105
106
106 def testpid(pid):
107 def testpid(pid):
107 '''return False if pid dead, True if running or not known'''
108 '''return False if pid dead, True if running or not known'''
108 return True
109 return True
109
110
110 def set_flags(f, l, x):
111 def set_flags(f, l, x):
111 pass
112 pass
112
113
113 def set_binary(fd):
114 def set_binary(fd):
114 # When run without console, pipes may expose invalid
115 # When run without console, pipes may expose invalid
115 # fileno(), usually set to -1.
116 # fileno(), usually set to -1.
116 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
117 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
117 msvcrt.setmode(fd.fileno(), os.O_BINARY)
118 msvcrt.setmode(fd.fileno(), os.O_BINARY)
118
119
119 def pconvert(path):
120 def pconvert(path):
120 return '/'.join(path.split(os.sep))
121 return '/'.join(path.split(os.sep))
121
122
122 def localpath(path):
123 def localpath(path):
123 return path.replace('/', '\\')
124 return path.replace('/', '\\')
124
125
125 def normpath(path):
126 def normpath(path):
126 return pconvert(os.path.normpath(path))
127 return pconvert(os.path.normpath(path))
127
128
128 def samestat(s1, s2):
129 def samestat(s1, s2):
129 return False
130 return False
130
131
131 # A sequence of backslashes is special iff it precedes a double quote:
132 # A sequence of backslashes is special iff it precedes a double quote:
132 # - if there's an even number of backslashes, the double quote is not
133 # - if there's an even number of backslashes, the double quote is not
133 # quoted (i.e. it ends the quoted region)
134 # quoted (i.e. it ends the quoted region)
134 # - if there's an odd number of backslashes, the double quote is quoted
135 # - if there's an odd number of backslashes, the double quote is quoted
135 # - in both cases, every pair of backslashes is unquoted into a single
136 # - in both cases, every pair of backslashes is unquoted into a single
136 # backslash
137 # backslash
137 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
138 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
138 # So, to quote a string, we must surround it in double quotes, double
139 # So, to quote a string, we must surround it in double quotes, double
139 # the number of backslashes that preceed double quotes and add another
140 # the number of backslashes that preceed double quotes and add another
140 # backslash before every double quote (being careful with the double
141 # backslash before every double quote (being careful with the double
141 # quote we've appended to the end)
142 # quote we've appended to the end)
142 _quotere = None
143 _quotere = None
143 def shellquote(s):
144 def shellquote(s):
144 global _quotere
145 global _quotere
145 if _quotere is None:
146 if _quotere is None:
146 _quotere = re.compile(r'(\\*)("|\\$)')
147 _quotere = re.compile(r'(\\*)("|\\$)')
147 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
148 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
148
149
149 def quotecommand(cmd):
150 def quotecommand(cmd):
150 """Build a command string suitable for os.popen* calls."""
151 """Build a command string suitable for os.popen* calls."""
151 # The extra quotes are needed because popen* runs the command
152 # The extra quotes are needed because popen* runs the command
152 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
153 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
153 return '"' + cmd + '"'
154 return '"' + cmd + '"'
154
155
155 def popen(command, mode='r'):
156 def popen(command, mode='r'):
156 # Work around "popen spawned process may not write to stdout
157 # Work around "popen spawned process may not write to stdout
157 # under windows"
158 # under windows"
158 # http://bugs.python.org/issue1366
159 # http://bugs.python.org/issue1366
159 command += " 2> %s" % nulldev
160 command += " 2> %s" % nulldev
160 return os.popen(quotecommand(command), mode)
161 return os.popen(quotecommand(command), mode)
161
162
162 def explain_exit(code):
163 def explain_exit(code):
163 return _("exited with status %d") % code, code
164 return _("exited with status %d") % code, code
164
165
165 # if you change this stub into a real check, please try to implement the
166 # if you change this stub into a real check, please try to implement the
166 # username and groupname functions above, too.
167 # username and groupname functions above, too.
167 def isowner(st):
168 def isowner(st):
168 return True
169 return True
169
170
170 def find_exe(command):
171 def find_exe(command):
171 '''Find executable for command searching like cmd.exe does.
172 '''Find executable for command searching like cmd.exe does.
172 If command is a basename then PATH is searched for command.
173 If command is a basename then PATH is searched for command.
173 PATH isn't searched if command is an absolute or relative path.
174 PATH isn't searched if command is an absolute or relative path.
174 An extension from PATHEXT is found and added if not present.
175 An extension from PATHEXT is found and added if not present.
175 If command isn't found None is returned.'''
176 If command isn't found None is returned.'''
176 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
177 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
177 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
178 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
178 if os.path.splitext(command)[1].lower() in pathexts:
179 if os.path.splitext(command)[1].lower() in pathexts:
179 pathexts = ['']
180 pathexts = ['']
180
181
181 def findexisting(pathcommand):
182 def findexisting(pathcommand):
182 'Will append extension (if needed) and return existing file'
183 'Will append extension (if needed) and return existing file'
183 for ext in pathexts:
184 for ext in pathexts:
184 executable = pathcommand + ext
185 executable = pathcommand + ext
185 if os.path.exists(executable):
186 if os.path.exists(executable):
186 return executable
187 return executable
187 return None
188 return None
188
189
189 if os.sep in command:
190 if os.sep in command:
190 return findexisting(command)
191 return findexisting(command)
191
192
192 for path in os.environ.get('PATH', '').split(os.pathsep):
193 for path in os.environ.get('PATH', '').split(os.pathsep):
193 executable = findexisting(os.path.join(path, command))
194 executable = findexisting(os.path.join(path, command))
194 if executable is not None:
195 if executable is not None:
195 return executable
196 return executable
196 return None
197 return None
197
198
198 def set_signal_handler():
199 def set_signal_handler():
199 try:
200 try:
200 set_signal_handler_win32()
201 set_signal_handler_win32()
201 except NameError:
202 except NameError:
202 pass
203 pass
203
204
204 def statfiles(files):
205 def statfiles(files):
205 '''Stat each file in files and yield stat or None if file does not exist.
206 '''Stat each file in files and yield stat or None if file does not exist.
206 Cluster and cache stat per directory to minimize number of OS stat calls.'''
207 Cluster and cache stat per directory to minimize number of OS stat calls.'''
207 ncase = os.path.normcase
208 ncase = os.path.normcase
208 sep = os.sep
209 sep = os.sep
209 dircache = {} # dirname -> filename -> status | None if file does not exist
210 dircache = {} # dirname -> filename -> status | None if file does not exist
210 for nf in files:
211 for nf in files:
211 nf = ncase(nf)
212 nf = ncase(nf)
212 dir, base = os.path.split(nf)
213 dir, base = os.path.split(nf)
213 if not dir:
214 if not dir:
214 dir = '.'
215 dir = '.'
215 cache = dircache.get(dir, None)
216 cache = dircache.get(dir, None)
216 if cache is None:
217 if cache is None:
217 try:
218 try:
218 dmap = dict([(ncase(n), s)
219 dmap = dict([(ncase(n), s)
219 for n, k, s in osutil.listdir(dir, True)])
220 for n, k, s in osutil.listdir(dir, True)])
220 except OSError, err:
221 except OSError, err:
221 # handle directory not found in Python version prior to 2.5
222 # handle directory not found in Python version prior to 2.5
222 # Python <= 2.4 returns native Windows code 3 in errno
223 # Python <= 2.4 returns native Windows code 3 in errno
223 # Python >= 2.5 returns ENOENT and adds winerror field
224 # Python >= 2.5 returns ENOENT and adds winerror field
224 # EINVAL is raised if dir is not a directory.
225 # EINVAL is raised if dir is not a directory.
225 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
226 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
226 errno.ENOTDIR):
227 errno.ENOTDIR):
227 raise
228 raise
228 dmap = {}
229 dmap = {}
229 cache = dircache.setdefault(dir, dmap)
230 cache = dircache.setdefault(dir, dmap)
230 yield cache.get(base, None)
231 yield cache.get(base, None)
231
232
232 def getuser():
233 def getuser():
233 '''return name of current user'''
234 '''return name of current user'''
234 raise error.Abort(_('user name not available - set USERNAME '
235 raise error.Abort(_('user name not available - set USERNAME '
235 'environment variable'))
236 'environment variable'))
236
237
237 def username(uid=None):
238 def username(uid=None):
238 """Return the name of the user with the given uid.
239 """Return the name of the user with the given uid.
239
240
240 If uid is None, return the name of the current user."""
241 If uid is None, return the name of the current user."""
241 return None
242 return None
242
243
243 def groupname(gid=None):
244 def groupname(gid=None):
244 """Return the name of the group with the given gid.
245 """Return the name of the group with the given gid.
245
246
246 If gid is None, return the name of the current group."""
247 If gid is None, return the name of the current group."""
247 return None
248 return None
248
249
249 def _removedirs(name):
250 def _removedirs(name):
250 """special version of os.removedirs that does not remove symlinked
251 """special version of os.removedirs that does not remove symlinked
251 directories or junction points if they actually contain files"""
252 directories or junction points if they actually contain files"""
252 if osutil.listdir(name):
253 if osutil.listdir(name):
253 return
254 return
254 os.rmdir(name)
255 os.rmdir(name)
255 head, tail = os.path.split(name)
256 head, tail = os.path.split(name)
256 if not tail:
257 if not tail:
257 head, tail = os.path.split(head)
258 head, tail = os.path.split(head)
258 while head and tail:
259 while head and tail:
259 try:
260 try:
260 if osutil.listdir(name):
261 if osutil.listdir(name):
261 return
262 return
262 os.rmdir(head)
263 os.rmdir(head)
263 except:
264 except:
264 break
265 break
265 head, tail = os.path.split(head)
266 head, tail = os.path.split(head)
266
267
267 def unlink(f):
268 def unlink(f):
268 """unlink and remove the directory if it is empty"""
269 """unlink and remove the directory if it is empty"""
269 os.unlink(f)
270 os.unlink(f)
270 # try removing directories that might now be empty
271 # try removing directories that might now be empty
271 try:
272 try:
272 _removedirs(os.path.dirname(f))
273 _removedirs(os.path.dirname(f))
273 except OSError:
274 except OSError:
274 pass
275 pass
275
276
276 try:
277 try:
277 # override functions with win32 versions if possible
278 # override functions with win32 versions if possible
278 from win32 import *
279 from win32 import *
279 except ImportError:
280 except ImportError:
280 pass
281 pass
281
282
282 expandglobs = True
283 expandglobs = True
@@ -1,40 +1,40 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from mercurial import demandimport
3 from mercurial import demandimport
4 demandimport.enable()
4 demandimport.enable()
5
5
6 import re
6 import re
7
7
8 rsub = re.sub
8 rsub = re.sub
9 def f(obj):
9 def f(obj):
10 l = repr(obj)
10 l = repr(obj)
11 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
11 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
12 l = rsub("from '.*'", "from '?'", l)
12 l = rsub("from '.*'", "from '?'", l)
13 return l
13 return l
14
14
15 import os
15 import os
16
16
17 print "os =", f(os)
17 print "os =", f(os)
18 print "os.system =", f(os.system)
18 print "os.system =", f(os.system)
19 print "os =", f(os)
19 print "os =", f(os)
20
20
21 from mercurial import util
21 from mercurial import util
22
22
23 print "util =", f(util)
23 print "util =", f(util)
24 print "util.system =", f(util.system)
24 print "util.system =", f(util.system)
25 print "util =", f(util)
25 print "util =", f(util)
26 print "util.system =", f(util.system)
26 print "util.system =", f(util.system)
27
27
28 import re as fred
28 import re as fred
29 print "fred =", f(fred)
29 print "fred =", f(fred)
30
30
31 import sys as re
31 import sys as re
32 print "re =", f(re)
32 print "re =", f(re)
33
33
34 print "fred =", f(fred)
34 print "fred =", f(fred)
35 print "fred.sub =", f(fred.sub)
35 print "fred.sub =", f(fred.sub)
36 print "fred =", f(fred)
36 print "fred =", f(fred)
37
37
38 print "re =", f(re)
38 print "re =", f(re)
39 print "re.stdout =", f(re.stdout)
39 print "re.stderr =", f(re.stderr)
40 print "re =", f(re)
40 print "re =", f(re)
@@ -1,15 +1,15 b''
1 os = <unloaded module 'os'>
1 os = <unloaded module 'os'>
2 os.system = <built-in function system>
2 os.system = <built-in function system>
3 os = <module 'os' from '?'>
3 os = <module 'os' from '?'>
4 util = <unloaded module 'util'>
4 util = <unloaded module 'util'>
5 util.system = <function system at 0x?>
5 util.system = <function system at 0x?>
6 util = <module 'mercurial.util' from '?'>
6 util = <module 'mercurial.util' from '?'>
7 util.system = <function system at 0x?>
7 util.system = <function system at 0x?>
8 fred = <unloaded module 're'>
8 fred = <unloaded module 're'>
9 re = <unloaded module 'sys'>
9 re = <unloaded module 'sys'>
10 fred = <unloaded module 're'>
10 fred = <unloaded module 're'>
11 fred.sub = <function sub at 0x?>
11 fred.sub = <function sub at 0x?>
12 fred = <proxied module 're'>
12 fred = <proxied module 're'>
13 re = <unloaded module 'sys'>
13 re = <unloaded module 'sys'>
14 re.stdout = <open file '<stdout>', mode 'w' at 0x?>
14 re.stderr = <open file '<stderr>', mode 'w' at 0x?>
15 re = <proxied module 'sys'>
15 re = <proxied module 'sys'>
General Comments 0
You need to be logged in to leave comments. Login now