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