##// END OF EJS Templates
setup.py: fixing version info for Windows hg.exe (py2exe)...
Adrian Buehlmann -
r10400:fb203201 default
parent child Browse files
Show More
@@ -1,288 +1,300 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # This is the mercurial setup script.
4 4 #
5 5 # 'python setup.py install', or
6 6 # 'python setup.py --help' for more options
7 7
8 8 import sys
9 9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
10 10 raise SystemExit("Mercurial requires Python 2.4 or later.")
11 11
12 12 # Solaris Python packaging brain damage
13 13 try:
14 14 import hashlib
15 15 sha = hashlib.sha1()
16 16 except:
17 17 try:
18 18 import sha
19 19 except:
20 20 raise SystemExit(
21 21 "Couldn't import standard hashlib (incomplete Python install).")
22 22
23 23 try:
24 24 import zlib
25 25 except:
26 26 raise SystemExit(
27 27 "Couldn't import standard zlib (incomplete Python install).")
28 28
29 29 import os, subprocess, time
30 30 import shutil
31 31 import tempfile
32 32 from distutils.core import setup, Extension
33 33 from distutils.dist import Distribution
34 34 from distutils.command.install_data import install_data
35 35 from distutils.command.build import build
36 36 from distutils.command.build_py import build_py
37 37 from distutils.spawn import spawn, find_executable
38 38 from distutils.ccompiler import new_compiler
39 39
40 extra = {}
41 40 scripts = ['hg']
42 41 if os.name == 'nt':
43 42 scripts.append('contrib/win32/hg.bat')
44 43
45 44 # simplified version of distutils.ccompiler.CCompiler.has_function
46 45 # that actually removes its temporary files.
47 46 def hasfunction(cc, funcname):
48 47 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
49 48 devnull = oldstderr = None
50 49 try:
51 50 try:
52 51 fname = os.path.join(tmpdir, 'funcname.c')
53 52 f = open(fname, 'w')
54 53 f.write('int main(void) {\n')
55 54 f.write(' %s();\n' % funcname)
56 55 f.write('}\n')
57 56 f.close()
58 57 # Redirect stderr to /dev/null to hide any error messages
59 58 # from the compiler.
60 59 # This will have to be changed if we ever have to check
61 60 # for a function on Windows.
62 61 devnull = open('/dev/null', 'w')
63 62 oldstderr = os.dup(sys.stderr.fileno())
64 63 os.dup2(devnull.fileno(), sys.stderr.fileno())
65 64 objects = cc.compile([fname], output_dir=tmpdir)
66 65 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
67 66 except:
68 67 return False
69 68 return True
70 69 finally:
71 70 if oldstderr is not None:
72 71 os.dup2(oldstderr, sys.stderr.fileno())
73 72 if devnull is not None:
74 73 devnull.close()
75 74 shutil.rmtree(tmpdir)
76 75
77 76 # py2exe needs to be installed to work
78 77 try:
79 78 import py2exe
79 py2exeloaded = True
80 80
81 81 # Help py2exe to find win32com.shell
82 82 try:
83 83 import modulefinder
84 84 import win32com
85 85 for p in win32com.__path__[1:]: # Take the path to win32comext
86 86 modulefinder.AddPackagePath("win32com", p)
87 87 pn = "win32com.shell"
88 88 __import__(pn)
89 89 m = sys.modules[pn]
90 90 for p in m.__path__[1:]:
91 91 modulefinder.AddPackagePath(pn, p)
92 92 except ImportError:
93 93 pass
94 94
95 extra['console'] = ['hg']
96
97 95 except ImportError:
96 py2exeloaded = False
98 97 pass
99 98
100 99 def runcmd(cmd, env):
101 100 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
102 101 stderr=subprocess.PIPE, env=env)
103 102 out, err = p.communicate()
104 103 # If root is executing setup.py, but the repository is owned by
105 104 # another user (as in "sudo python setup.py install") we will get
106 105 # trust warnings since the .hg/hgrc file is untrusted. That is
107 106 # fine, we don't want to load it anyway. Python may warn about
108 107 # a missing __init__.py in mercurial/locale, we also ignore that.
109 108 err = [e for e in err.splitlines()
110 109 if not e.startswith('Not trusting file') \
111 110 and not e.startswith('warning: Not importing')]
112 111 if err:
113 112 return ''
114 113 return out
115 114
116 115 version = ''
117 116
118 117 if os.path.isdir('.hg'):
119 118 # Execute hg out of this directory with a custom environment which
120 119 # includes the pure Python modules in mercurial/pure. We also take
121 120 # care to not use any hgrc files and do no localization.
122 121 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
123 122 env = {'PYTHONPATH': os.pathsep.join(pypath),
124 123 'HGRCPATH': '',
125 124 'LANGUAGE': 'C'}
126 125 if 'LD_LIBRARY_PATH' in os.environ:
127 126 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
128 127 if 'SystemRoot' in os.environ:
129 128 # Copy SystemRoot into the custom environment for Python 2.6
130 129 # under Windows. Otherwise, the subprocess will fail with
131 130 # error 0xc0150004. See: http://bugs.python.org/issue3440
132 131 env['SystemRoot'] = os.environ['SystemRoot']
133 132 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
134 133 l = runcmd(cmd, env).split()
135 134 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
136 135 l.pop()
137 136 if len(l) > 1: # tag found
138 137 version = l[-1]
139 138 if l[0].endswith('+'): # propagate the dirty status to the tag
140 139 version += '+'
141 140 elif len(l) == 1: # no tag found
142 141 cmd = [sys.executable, 'hg', 'parents', '--template',
143 142 '{latesttag}+{latesttagdistance}-']
144 143 version = runcmd(cmd, env) + l[0]
145 144 if version.endswith('+'):
146 145 version += time.strftime('%Y%m%d')
147 146 elif os.path.exists('.hg_archival.txt'):
148 147 kw = dict([[t.strip() for t in l.split(':', 1)]
149 148 for l in open('.hg_archival.txt')])
150 149 if 'tag' in kw:
151 150 version = kw['tag']
152 151 elif 'latesttag' in kw:
153 152 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
154 153 else:
155 154 version = kw.get('node', '')[:12]
156 155
157 156 if version:
158 157 f = open("mercurial/__version__.py", "w")
159 158 f.write('# this file is autogenerated by setup.py\n')
160 159 f.write('version = "%s"\n' % version)
161 160 f.close()
162 161
163 162
164 163 try:
165 164 from mercurial import __version__
166 165 version = __version__.version
167 166 except ImportError:
168 167 version = 'unknown'
169 168
170 169 class hgbuildmo(build):
171 170
172 171 description = "build translations (.mo files)"
173 172
174 173 def run(self):
175 174 if not find_executable('msgfmt'):
176 175 self.warn("could not find msgfmt executable, no translations "
177 176 "will be built")
178 177 return
179 178
180 179 podir = 'i18n'
181 180 if not os.path.isdir(podir):
182 181 self.warn("could not find %s/ directory" % podir)
183 182 return
184 183
185 184 join = os.path.join
186 185 for po in os.listdir(podir):
187 186 if not po.endswith('.po'):
188 187 continue
189 188 pofile = join(podir, po)
190 189 modir = join('locale', po[:-3], 'LC_MESSAGES')
191 190 mofile = join(modir, 'hg.mo')
192 191 mobuildfile = join('mercurial', mofile)
193 192 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
194 193 if sys.platform != 'sunos5':
195 194 # msgfmt on Solaris does not know about -c
196 195 cmd.append('-c')
197 196 self.mkpath(join('mercurial', modir))
198 197 self.make_file([pofile], mobuildfile, spawn, (cmd,))
199 198
200 199 # Insert hgbuildmo first so that files in mercurial/locale/ are found
201 200 # when build_py is run next.
202 201 build.sub_commands.insert(0, ('build_mo', None))
203 202
204 203 Distribution.pure = 0
205 204 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
206 205 "code instead of C extensions"))
207 206
208 207 class hgbuildpy(build_py):
209 208
210 209 def finalize_options(self):
211 210 build_py.finalize_options(self)
212 211
213 212 if self.distribution.pure:
214 213 if self.py_modules is None:
215 214 self.py_modules = []
216 215 for ext in self.distribution.ext_modules:
217 216 if ext.name.startswith("mercurial."):
218 217 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
219 218 self.distribution.ext_modules = []
220 219
221 220 def find_modules(self):
222 221 modules = build_py.find_modules(self)
223 222 for module in modules:
224 223 if module[0] == "mercurial.pure":
225 224 if module[1] != "__init__":
226 225 yield ("mercurial", module[1], module[2])
227 226 else:
228 227 yield module
229 228
230 229 cmdclass = {'build_mo': hgbuildmo,
231 230 'build_py': hgbuildpy}
232 231
233 232 extmodules = [
234 233 Extension('mercurial.base85', ['mercurial/base85.c']),
235 234 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
236 235 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
237 236 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
238 237 Extension('mercurial.parsers', ['mercurial/parsers.c']),
239 238 Extension('mercurial.osutil', ['mercurial/osutil.c']),
240 239 ]
241 240
242 241 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
243 242 'hgext.highlight', 'hgext.zeroconf']
244 243
245 244 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
246 245 # The inotify extension is only usable with Linux 2.6 kernels.
247 246 # You also need a reasonably recent C library.
248 247 cc = new_compiler()
249 248 if hasfunction(cc, 'inotify_add_watch'):
250 249 extmodules.append(Extension('hgext.inotify.linux._inotify',
251 250 ['hgext/inotify/linux/_inotify.c']))
252 251 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
253 252
254 253 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
255 254 'help/*.txt']}
256 255
257 256 def ordinarypath(p):
258 257 return p and p[0] != '.' and p[-1] != '~'
259 258
260 259 for root in ('templates',):
261 260 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
262 261 curdir = curdir.split(os.sep, 1)[1]
263 262 dirs[:] = filter(ordinarypath, dirs)
264 263 for f in filter(ordinarypath, files):
265 264 f = os.path.join(curdir, f)
266 265 packagedata['mercurial'].append(f)
267 266
268 267 datafiles = []
268 setupversion = version
269 extra = {}
270
271 if py2exeloaded:
272 extra['console'] = [
273 {'script':'hg',
274 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
275 'product_version':version}]
276
277 if os.name == 'nt':
278 # Windows binary file versions for exe/dll files must have the
279 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
280 setupversion = version.split('+', 1)[0]
269 281
270 282 setup(name='mercurial',
271 version=version,
283 version=setupversion,
272 284 author='Matt Mackall',
273 285 author_email='mpm@selenic.com',
274 286 url='http://mercurial.selenic.com/',
275 287 description='Scalable distributed SCM',
276 288 license='GNU GPLv2+',
277 289 scripts=scripts,
278 290 packages=packages,
279 291 ext_modules=extmodules,
280 292 data_files=datafiles,
281 293 package_data=packagedata,
282 294 cmdclass=cmdclass,
283 295 options=dict(py2exe=dict(packages=['hgext', 'email']),
284 296 bdist_mpkg=dict(zipdist=True,
285 297 license='COPYING',
286 298 readme='contrib/macosx/Readme.html',
287 299 welcome='contrib/macosx/Welcome.html')),
288 300 **extra)
General Comments 0
You need to be logged in to leave comments. Login now