##// END OF EJS Templates
setup: make script executable with python3...
Simon Heimberg -
r15492:36f076d0 default
parent child Browse files
Show More
@@ -1,456 +1,456 b''
1 1 #
2 2 # This is the mercurial setup script.
3 3 #
4 4 # 'python setup.py install', or
5 5 # 'python setup.py --help' for more options
6 6
7 7 import sys, platform
8 8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10 10
11 11 if sys.version_info[0] >= 3:
12 12 def b(s):
13 13 '''A helper function to emulate 2.6+ bytes literals using string
14 14 literals.'''
15 15 return s.encode('latin1')
16 16 else:
17 17 def b(s):
18 18 '''A helper function to emulate 2.6+ bytes literals using string
19 19 literals.'''
20 20 return s
21 21
22 22 # Solaris Python packaging brain damage
23 23 try:
24 24 import hashlib
25 25 sha = hashlib.sha1()
26 26 except:
27 27 try:
28 28 import sha
29 29 except:
30 30 raise SystemExit(
31 31 "Couldn't import standard hashlib (incomplete Python install).")
32 32
33 33 try:
34 34 import zlib
35 35 except:
36 36 raise SystemExit(
37 37 "Couldn't import standard zlib (incomplete Python install).")
38 38
39 39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 40 isironpython = False
41 41 try:
42 42 isironpython = platform.python_implementation().lower().find("ironpython") != -1
43 43 except:
44 44 pass
45 45
46 46 if isironpython:
47 print "warning: IronPython detected (no bz2 support)"
47 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
48 48 else:
49 49 try:
50 50 import bz2
51 51 except:
52 52 raise SystemExit(
53 53 "Couldn't import standard bz2 (incomplete Python install).")
54 54
55 55 import os, subprocess, time
56 56 import shutil
57 57 import tempfile
58 58 from distutils import log
59 59 from distutils.core import setup, Command, Extension
60 60 from distutils.dist import Distribution
61 61 from distutils.command.build import build
62 62 from distutils.command.build_ext import build_ext
63 63 from distutils.command.build_py import build_py
64 64 from distutils.command.install_scripts import install_scripts
65 65 from distutils.spawn import spawn, find_executable
66 66 from distutils.ccompiler import new_compiler
67 67 from distutils.errors import CCompilerError, DistutilsExecError
68 68 from distutils.sysconfig import get_python_inc
69 69 from distutils.version import StrictVersion
70 70
71 71 scripts = ['hg']
72 72 if os.name == 'nt':
73 73 scripts.append('contrib/win32/hg.bat')
74 74
75 75 # simplified version of distutils.ccompiler.CCompiler.has_function
76 76 # that actually removes its temporary files.
77 77 def hasfunction(cc, funcname):
78 78 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
79 79 devnull = oldstderr = None
80 80 try:
81 81 try:
82 82 fname = os.path.join(tmpdir, 'funcname.c')
83 83 f = open(fname, 'w')
84 84 f.write('int main(void) {\n')
85 85 f.write(' %s();\n' % funcname)
86 86 f.write('}\n')
87 87 f.close()
88 88 # Redirect stderr to /dev/null to hide any error messages
89 89 # from the compiler.
90 90 # This will have to be changed if we ever have to check
91 91 # for a function on Windows.
92 92 devnull = open('/dev/null', 'w')
93 93 oldstderr = os.dup(sys.stderr.fileno())
94 94 os.dup2(devnull.fileno(), sys.stderr.fileno())
95 95 objects = cc.compile([fname], output_dir=tmpdir)
96 96 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
97 97 except:
98 98 return False
99 99 return True
100 100 finally:
101 101 if oldstderr is not None:
102 102 os.dup2(oldstderr, sys.stderr.fileno())
103 103 if devnull is not None:
104 104 devnull.close()
105 105 shutil.rmtree(tmpdir)
106 106
107 107 # py2exe needs to be installed to work
108 108 try:
109 109 import py2exe
110 110 py2exeloaded = True
111 111 except ImportError:
112 112 py2exeloaded = False
113 113
114 114 def runcmd(cmd, env):
115 115 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
116 116 stderr=subprocess.PIPE, env=env)
117 117 out, err = p.communicate()
118 118 return out, err
119 119
120 120 def runhg(cmd, env):
121 121 out, err = runcmd(cmd, env)
122 122 # If root is executing setup.py, but the repository is owned by
123 123 # another user (as in "sudo python setup.py install") we will get
124 124 # trust warnings since the .hg/hgrc file is untrusted. That is
125 125 # fine, we don't want to load it anyway. Python may warn about
126 126 # a missing __init__.py in mercurial/locale, we also ignore that.
127 127 err = [e for e in err.splitlines()
128 128 if not e.startswith(b('Not trusting file')) \
129 129 and not e.startswith(b('warning: Not importing'))]
130 130 if err:
131 131 return ''
132 132 return out
133 133
134 134 version = ''
135 135
136 136 # Execute hg out of this directory with a custom environment which
137 137 # includes the pure Python modules in mercurial/pure. We also take
138 138 # care to not use any hgrc files and do no localization.
139 139 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
140 140 env = {'PYTHONPATH': os.pathsep.join(pypath),
141 141 'HGRCPATH': '',
142 142 'LANGUAGE': 'C'}
143 143 if 'LD_LIBRARY_PATH' in os.environ:
144 144 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
145 145 if 'SystemRoot' in os.environ:
146 146 # Copy SystemRoot into the custom environment for Python 2.6
147 147 # under Windows. Otherwise, the subprocess will fail with
148 148 # error 0xc0150004. See: http://bugs.python.org/issue3440
149 149 env['SystemRoot'] = os.environ['SystemRoot']
150 150
151 151 if os.path.isdir('.hg'):
152 152 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
153 153 l = runhg(cmd, env).split()
154 154 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
155 155 l.pop()
156 156 if len(l) > 1: # tag found
157 157 version = l[-1]
158 158 if l[0].endswith('+'): # propagate the dirty status to the tag
159 159 version += '+'
160 160 elif len(l) == 1: # no tag found
161 161 cmd = [sys.executable, 'hg', 'parents', '--template',
162 162 '{latesttag}+{latesttagdistance}-']
163 163 version = runhg(cmd, env) + l[0]
164 164 if version.endswith('+'):
165 165 version += time.strftime('%Y%m%d')
166 166 elif os.path.exists('.hg_archival.txt'):
167 167 kw = dict([[t.strip() for t in l.split(':', 1)]
168 168 for l in open('.hg_archival.txt')])
169 169 if 'tag' in kw:
170 170 version = kw['tag']
171 171 elif 'latesttag' in kw:
172 172 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
173 173 else:
174 174 version = kw.get('node', '')[:12]
175 175
176 176 if version:
177 177 f = open("mercurial/__version__.py", "w")
178 178 f.write('# this file is autogenerated by setup.py\n')
179 179 f.write('version = "%s"\n' % version)
180 180 f.close()
181 181
182 182
183 183 try:
184 184 from mercurial import __version__
185 185 version = __version__.version
186 186 except ImportError:
187 187 version = 'unknown'
188 188
189 189 class hgbuild(build):
190 190 # Insert hgbuildmo first so that files in mercurial/locale/ are found
191 191 # when build_py is run next.
192 192 sub_commands = [('build_mo', None),
193 193 ] + build.sub_commands
194 194
195 195 class hgbuildmo(build):
196 196
197 197 description = "build translations (.mo files)"
198 198
199 199 def run(self):
200 200 if not find_executable('msgfmt'):
201 201 self.warn("could not find msgfmt executable, no translations "
202 202 "will be built")
203 203 return
204 204
205 205 podir = 'i18n'
206 206 if not os.path.isdir(podir):
207 207 self.warn("could not find %s/ directory" % podir)
208 208 return
209 209
210 210 join = os.path.join
211 211 for po in os.listdir(podir):
212 212 if not po.endswith('.po'):
213 213 continue
214 214 pofile = join(podir, po)
215 215 modir = join('locale', po[:-3], 'LC_MESSAGES')
216 216 mofile = join(modir, 'hg.mo')
217 217 mobuildfile = join('mercurial', mofile)
218 218 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
219 219 if sys.platform != 'sunos5':
220 220 # msgfmt on Solaris does not know about -c
221 221 cmd.append('-c')
222 222 self.mkpath(join('mercurial', modir))
223 223 self.make_file([pofile], mobuildfile, spawn, (cmd,))
224 224
225 225
226 226 class hgdist(Distribution):
227 227 pure = 0
228 228
229 229 global_options = Distribution.global_options + \
230 230 [('pure', None, "use pure (slow) Python "
231 231 "code instead of C extensions"),
232 232 ]
233 233
234 234 def has_ext_modules(self):
235 235 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
236 236 # too late for some cases
237 237 return not self.pure and Distribution.has_ext_modules(self)
238 238
239 239 class hgbuildext(build_ext):
240 240
241 241 def build_extension(self, ext):
242 242 try:
243 243 build_ext.build_extension(self, ext)
244 244 except CCompilerError:
245 245 if not getattr(ext, 'optional', False):
246 246 raise
247 247 log.warn("Failed to build optional extension '%s' (skipping)",
248 248 ext.name)
249 249
250 250 class hgbuildpy(build_py):
251 251
252 252 def finalize_options(self):
253 253 build_py.finalize_options(self)
254 254
255 255 if self.distribution.pure:
256 256 if self.py_modules is None:
257 257 self.py_modules = []
258 258 for ext in self.distribution.ext_modules:
259 259 if ext.name.startswith("mercurial."):
260 260 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
261 261 self.distribution.ext_modules = []
262 262 else:
263 263 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
264 264 raise SystemExit("Python headers are required to build Mercurial")
265 265
266 266 def find_modules(self):
267 267 modules = build_py.find_modules(self)
268 268 for module in modules:
269 269 if module[0] == "mercurial.pure":
270 270 if module[1] != "__init__":
271 271 yield ("mercurial", module[1], module[2])
272 272 else:
273 273 yield module
274 274
275 275 class buildhgextindex(Command):
276 276 description = 'generate prebuilt index of hgext (for frozen package)'
277 277 user_options = []
278 278 _indexfilename = 'hgext/__index__.py'
279 279
280 280 def initialize_options(self):
281 281 pass
282 282
283 283 def finalize_options(self):
284 284 pass
285 285
286 286 def run(self):
287 287 if os.path.exists(self._indexfilename):
288 288 os.unlink(self._indexfilename)
289 289
290 290 # here no extension enabled, disabled() lists up everything
291 291 code = ('import pprint; from mercurial import extensions; '
292 292 'pprint.pprint(extensions.disabled())')
293 293 out, err = runcmd([sys.executable, '-c', code], env)
294 294 if err:
295 295 raise DistutilsExecError(err)
296 296
297 297 f = open(self._indexfilename, 'w')
298 298 f.write('# this file is autogenerated by setup.py\n')
299 299 f.write('docs = ')
300 300 f.write(out)
301 301 f.close()
302 302
303 303 class hginstallscripts(install_scripts):
304 304 '''
305 305 This is a specialization of install_scripts that replaces the @LIBDIR@ with
306 306 the configured directory for modules. If possible, the path is made relative
307 307 to the directory for scripts.
308 308 '''
309 309
310 310 def initialize_options(self):
311 311 install_scripts.initialize_options(self)
312 312
313 313 self.install_lib = None
314 314
315 315 def finalize_options(self):
316 316 install_scripts.finalize_options(self)
317 317 self.set_undefined_options('install',
318 318 ('install_lib', 'install_lib'))
319 319
320 320 def run(self):
321 321 install_scripts.run(self)
322 322
323 323 if (os.path.splitdrive(self.install_dir)[0] !=
324 324 os.path.splitdrive(self.install_lib)[0]):
325 325 # can't make relative paths from one drive to another, so use an
326 326 # absolute path instead
327 327 libdir = self.install_lib
328 328 else:
329 329 common = os.path.commonprefix((self.install_dir, self.install_lib))
330 330 rest = self.install_dir[len(common):]
331 331 uplevel = len([n for n in os.path.split(rest) if n])
332 332
333 333 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
334 334
335 335 for outfile in self.outfiles:
336 336 fp = open(outfile, 'rb')
337 337 data = fp.read()
338 338 fp.close()
339 339
340 340 # skip binary files
341 341 if '\0' in data:
342 342 continue
343 343
344 344 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
345 345 fp = open(outfile, 'wb')
346 346 fp.write(data)
347 347 fp.close()
348 348
349 349 cmdclass = {'build': hgbuild,
350 350 'build_mo': hgbuildmo,
351 351 'build_ext': hgbuildext,
352 352 'build_py': hgbuildpy,
353 353 'build_hgextindex': buildhgextindex,
354 354 'install_scripts': hginstallscripts}
355 355
356 356 packages = ['mercurial', 'mercurial.hgweb',
357 357 'mercurial.httpclient', 'mercurial.httpclient.tests',
358 358 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
359 359 'hgext.largefiles']
360 360
361 361 pymodules = []
362 362
363 363 extmodules = [
364 364 Extension('mercurial.base85', ['mercurial/base85.c']),
365 365 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
366 366 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
367 367 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
368 368 Extension('mercurial.parsers', ['mercurial/parsers.c']),
369 369 ]
370 370
371 371 osutil_ldflags = []
372 372
373 373 if sys.platform == 'darwin':
374 374 osutil_ldflags += ['-framework', 'ApplicationServices']
375 375
376 376 # disable osutil.c under windows + python 2.4 (issue1364)
377 377 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
378 378 pymodules.append('mercurial.pure.osutil')
379 379 else:
380 380 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
381 381 extra_link_args=osutil_ldflags))
382 382
383 383 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
384 384 # The inotify extension is only usable with Linux 2.6 kernels.
385 385 # You also need a reasonably recent C library.
386 386 # In any case, if it fails to build the error will be skipped ('optional').
387 387 cc = new_compiler()
388 388 if hasfunction(cc, 'inotify_add_watch'):
389 389 inotify = Extension('hgext.inotify.linux._inotify',
390 390 ['hgext/inotify/linux/_inotify.c'],
391 391 ['mercurial'])
392 392 inotify.optional = True
393 393 extmodules.append(inotify)
394 394 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
395 395
396 396 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
397 397 'help/*.txt']}
398 398
399 399 def ordinarypath(p):
400 400 return p and p[0] != '.' and p[-1] != '~'
401 401
402 402 for root in ('templates',):
403 403 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
404 404 curdir = curdir.split(os.sep, 1)[1]
405 405 dirs[:] = filter(ordinarypath, dirs)
406 406 for f in filter(ordinarypath, files):
407 407 f = os.path.join(curdir, f)
408 408 packagedata['mercurial'].append(f)
409 409
410 410 datafiles = []
411 411 setupversion = version
412 412 extra = {}
413 413
414 414 if py2exeloaded:
415 415 extra['console'] = [
416 416 {'script':'hg',
417 417 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
418 418 'product_version':version}]
419 419 # sub command of 'build' because 'py2exe' does not handle sub_commands
420 420 build.sub_commands.insert(0, ('build_hgextindex', None))
421 421
422 422 if os.name == 'nt':
423 423 # Windows binary file versions for exe/dll files must have the
424 424 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
425 425 setupversion = version.split('+', 1)[0]
426 426
427 427 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
428 428 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
429 429 # distutils.sysconfig
430 430 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()[0]
431 431 # Also parse only first digit, because 3.2.1 can't be parsed nicely
432 432 if (version.startswith('Xcode') and
433 433 StrictVersion(version.split()[1]) >= StrictVersion('4.0')):
434 434 os.environ['ARCHFLAGS'] = ''
435 435
436 436 setup(name='mercurial',
437 437 version=setupversion,
438 438 author='Matt Mackall',
439 439 author_email='mpm@selenic.com',
440 440 url='http://mercurial.selenic.com/',
441 441 description='Scalable distributed SCM',
442 442 license='GNU GPLv2+',
443 443 scripts=scripts,
444 444 packages=packages,
445 445 py_modules=pymodules,
446 446 ext_modules=extmodules,
447 447 data_files=datafiles,
448 448 package_data=packagedata,
449 449 cmdclass=cmdclass,
450 450 distclass=hgdist,
451 451 options=dict(py2exe=dict(packages=['hgext', 'email']),
452 452 bdist_mpkg=dict(zipdist=True,
453 453 license='COPYING',
454 454 readme='contrib/macosx/Readme.html',
455 455 welcome='contrib/macosx/Welcome.html')),
456 456 **extra)
General Comments 0
You need to be logged in to leave comments. Login now