##// END OF EJS Templates
setup: print subprocess stderr if there is any...
Bryan O'Sullivan -
r17926:65a46635 default
parent child Browse files
Show More
@@ -1,538 +1,540 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 ImportError:
27 27 try:
28 28 import sha
29 29 except ImportError:
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 ImportError:
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()
43 43 .lower().find("ironpython") != -1)
44 44 except AttributeError:
45 45 pass
46 46
47 47 if isironpython:
48 48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 49 else:
50 50 try:
51 51 import bz2
52 52 except ImportError:
53 53 raise SystemExit(
54 54 "Couldn't import standard bz2 (incomplete Python install).")
55 55
56 56 import os, subprocess, time
57 57 import shutil
58 58 import tempfile
59 59 from distutils import log
60 60 from distutils.core import setup, Command, Extension
61 61 from distutils.dist import Distribution
62 62 from distutils.command.build import build
63 63 from distutils.command.build_ext import build_ext
64 64 from distutils.command.build_py import build_py
65 65 from distutils.command.install_scripts import install_scripts
66 66 from distutils.spawn import spawn, find_executable
67 67 from distutils.ccompiler import new_compiler
68 68 from distutils import cygwinccompiler
69 69 from distutils.errors import CCompilerError, DistutilsExecError
70 70 from distutils.sysconfig import get_python_inc
71 71 from distutils.version import StrictVersion
72 72
73 73 convert2to3 = '--c2to3' in sys.argv
74 74 if convert2to3:
75 75 try:
76 76 from distutils.command.build_py import build_py_2to3 as build_py
77 77 from lib2to3.refactor import get_fixers_from_package as getfixers
78 78 except ImportError:
79 79 if sys.version_info[0] < 3:
80 80 raise SystemExit("--c2to3 is only compatible with python3.")
81 81 raise
82 82 sys.path.append('contrib')
83 83 elif sys.version_info[0] >= 3:
84 84 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
85 85
86 86 scripts = ['hg']
87 87 if os.name == 'nt':
88 88 scripts.append('contrib/win32/hg.bat')
89 89
90 90 # simplified version of distutils.ccompiler.CCompiler.has_function
91 91 # that actually removes its temporary files.
92 92 def hasfunction(cc, funcname):
93 93 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
94 94 devnull = oldstderr = None
95 95 try:
96 96 try:
97 97 fname = os.path.join(tmpdir, 'funcname.c')
98 98 f = open(fname, 'w')
99 99 f.write('int main(void) {\n')
100 100 f.write(' %s();\n' % funcname)
101 101 f.write('}\n')
102 102 f.close()
103 103 # Redirect stderr to /dev/null to hide any error messages
104 104 # from the compiler.
105 105 # This will have to be changed if we ever have to check
106 106 # for a function on Windows.
107 107 devnull = open('/dev/null', 'w')
108 108 oldstderr = os.dup(sys.stderr.fileno())
109 109 os.dup2(devnull.fileno(), sys.stderr.fileno())
110 110 objects = cc.compile([fname], output_dir=tmpdir)
111 111 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
112 112 except Exception:
113 113 return False
114 114 return True
115 115 finally:
116 116 if oldstderr is not None:
117 117 os.dup2(oldstderr, sys.stderr.fileno())
118 118 if devnull is not None:
119 119 devnull.close()
120 120 shutil.rmtree(tmpdir)
121 121
122 122 # py2exe needs to be installed to work
123 123 try:
124 124 import py2exe
125 125 py2exeloaded = True
126 126 # import py2exe's patched Distribution class
127 127 from distutils.core import Distribution
128 128 except ImportError:
129 129 py2exeloaded = False
130 130
131 131 def runcmd(cmd, env):
132 132 if sys.platform == 'plan9':
133 133 # subprocess kludge to work around issues in half-baked Python
134 134 # ports, notably bichued/python:
135 135 _, out, err = os.popen3(cmd)
136 136 return str(out), str(err)
137 137 else:
138 138 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
139 139 stderr=subprocess.PIPE, env=env)
140 140 out, err = p.communicate()
141 141 return out, err
142 142
143 143 def runhg(cmd, env):
144 144 out, err = runcmd(cmd, env)
145 145 # If root is executing setup.py, but the repository is owned by
146 146 # another user (as in "sudo python setup.py install") we will get
147 147 # trust warnings since the .hg/hgrc file is untrusted. That is
148 148 # fine, we don't want to load it anyway. Python may warn about
149 149 # a missing __init__.py in mercurial/locale, we also ignore that.
150 150 err = [e for e in err.splitlines()
151 151 if not e.startswith(b('Not trusting file')) \
152 152 and not e.startswith(b('warning: Not importing'))]
153 153 if err:
154 print >> sys.stderr, "stderr from '%s':" % (' '.join(cmd))
155 print >> sys.stderr, '\n'.join([' ' + e for e in err])
154 156 return ''
155 157 return out
156 158
157 159 version = ''
158 160
159 161 # Execute hg out of this directory with a custom environment which
160 162 # includes the pure Python modules in mercurial/pure. We also take
161 163 # care to not use any hgrc files and do no localization.
162 164 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
163 165 env = {'PYTHONPATH': os.pathsep.join(pypath),
164 166 'HGRCPATH': '',
165 167 'LANGUAGE': 'C'}
166 168 if 'LD_LIBRARY_PATH' in os.environ:
167 169 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
168 170 if 'SystemRoot' in os.environ:
169 171 # Copy SystemRoot into the custom environment for Python 2.6
170 172 # under Windows. Otherwise, the subprocess will fail with
171 173 # error 0xc0150004. See: http://bugs.python.org/issue3440
172 174 env['SystemRoot'] = os.environ['SystemRoot']
173 175
174 176 if os.path.isdir('.hg'):
175 177 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
176 178 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
177 179 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
178 180 if numerictags: # tag(s) found
179 181 version = numerictags[-1]
180 182 if hgid.endswith('+'): # propagate the dirty status to the tag
181 183 version += '+'
182 184 else: # no tag found
183 185 cmd = [sys.executable, 'hg', 'parents', '--template',
184 186 '{latesttag}+{latesttagdistance}-']
185 187 version = runhg(cmd, env) + hgid
186 188 if version.endswith('+'):
187 189 version += time.strftime('%Y%m%d')
188 190 elif os.path.exists('.hg_archival.txt'):
189 191 kw = dict([[t.strip() for t in l.split(':', 1)]
190 192 for l in open('.hg_archival.txt')])
191 193 if 'tag' in kw:
192 194 version = kw['tag']
193 195 elif 'latesttag' in kw:
194 196 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
195 197 else:
196 198 version = kw.get('node', '')[:12]
197 199
198 200 if version:
199 201 f = open("mercurial/__version__.py", "w")
200 202 f.write('# this file is autogenerated by setup.py\n')
201 203 f.write('version = "%s"\n' % version)
202 204 f.close()
203 205
204 206
205 207 try:
206 208 from mercurial import __version__
207 209 version = __version__.version
208 210 except ImportError:
209 211 version = 'unknown'
210 212
211 213 class hgbuild(build):
212 214 # Insert hgbuildmo first so that files in mercurial/locale/ are found
213 215 # when build_py is run next.
214 216 sub_commands = [('build_mo', None),
215 217
216 218 # We also need build_ext before build_py. Otherwise, when 2to3 is
217 219 # called (in build_py), it will not find osutil & friends,
218 220 # thinking that those modules are global and, consequently, making
219 221 # a mess, now that all module imports are global.
220 222
221 223 ('build_ext', build.has_ext_modules),
222 224 ] + build.sub_commands
223 225
224 226 class hgbuildmo(build):
225 227
226 228 description = "build translations (.mo files)"
227 229
228 230 def run(self):
229 231 if not find_executable('msgfmt'):
230 232 self.warn("could not find msgfmt executable, no translations "
231 233 "will be built")
232 234 return
233 235
234 236 podir = 'i18n'
235 237 if not os.path.isdir(podir):
236 238 self.warn("could not find %s/ directory" % podir)
237 239 return
238 240
239 241 join = os.path.join
240 242 for po in os.listdir(podir):
241 243 if not po.endswith('.po'):
242 244 continue
243 245 pofile = join(podir, po)
244 246 modir = join('locale', po[:-3], 'LC_MESSAGES')
245 247 mofile = join(modir, 'hg.mo')
246 248 mobuildfile = join('mercurial', mofile)
247 249 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
248 250 if sys.platform != 'sunos5':
249 251 # msgfmt on Solaris does not know about -c
250 252 cmd.append('-c')
251 253 self.mkpath(join('mercurial', modir))
252 254 self.make_file([pofile], mobuildfile, spawn, (cmd,))
253 255
254 256
255 257 class hgdist(Distribution):
256 258 pure = 0
257 259
258 260 global_options = Distribution.global_options + \
259 261 [('pure', None, "use pure (slow) Python "
260 262 "code instead of C extensions"),
261 263 ('c2to3', None, "(experimental!) convert "
262 264 "code with 2to3"),
263 265 ]
264 266
265 267 def has_ext_modules(self):
266 268 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
267 269 # too late for some cases
268 270 return not self.pure and Distribution.has_ext_modules(self)
269 271
270 272 class hgbuildext(build_ext):
271 273
272 274 def build_extension(self, ext):
273 275 try:
274 276 build_ext.build_extension(self, ext)
275 277 except CCompilerError:
276 278 if not getattr(ext, 'optional', False):
277 279 raise
278 280 log.warn("Failed to build optional extension '%s' (skipping)",
279 281 ext.name)
280 282
281 283 class hgbuildpy(build_py):
282 284 if convert2to3:
283 285 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
284 286 getfixers("hgfixes")))
285 287
286 288 def finalize_options(self):
287 289 build_py.finalize_options(self)
288 290
289 291 if self.distribution.pure:
290 292 if self.py_modules is None:
291 293 self.py_modules = []
292 294 for ext in self.distribution.ext_modules:
293 295 if ext.name.startswith("mercurial."):
294 296 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
295 297 self.distribution.ext_modules = []
296 298 else:
297 299 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
298 300 raise SystemExit('Python headers are required to build '
299 301 'Mercurial')
300 302
301 303 def find_modules(self):
302 304 modules = build_py.find_modules(self)
303 305 for module in modules:
304 306 if module[0] == "mercurial.pure":
305 307 if module[1] != "__init__":
306 308 yield ("mercurial", module[1], module[2])
307 309 else:
308 310 yield module
309 311
310 312 class buildhgextindex(Command):
311 313 description = 'generate prebuilt index of hgext (for frozen package)'
312 314 user_options = []
313 315 _indexfilename = 'hgext/__index__.py'
314 316
315 317 def initialize_options(self):
316 318 pass
317 319
318 320 def finalize_options(self):
319 321 pass
320 322
321 323 def run(self):
322 324 if os.path.exists(self._indexfilename):
323 325 os.unlink(self._indexfilename)
324 326
325 327 # here no extension enabled, disabled() lists up everything
326 328 code = ('import pprint; from mercurial import extensions; '
327 329 'pprint.pprint(extensions.disabled())')
328 330 out, err = runcmd([sys.executable, '-c', code], env)
329 331 if err:
330 332 raise DistutilsExecError(err)
331 333
332 334 f = open(self._indexfilename, 'w')
333 335 f.write('# this file is autogenerated by setup.py\n')
334 336 f.write('docs = ')
335 337 f.write(out)
336 338 f.close()
337 339
338 340 class buildhgexe(build_ext):
339 341 description = 'compile hg.exe from mercurial/exewrapper.c'
340 342
341 343 def build_extensions(self):
342 344 if os.name != 'nt':
343 345 return
344 346 if isinstance(self.compiler, HackedMingw32CCompiler):
345 347 self.compiler.compiler_so = self.compiler.compiler # no -mdll
346 348 self.compiler.dll_libraries = [] # no -lmsrvc90
347 349 hv = sys.hexversion
348 350 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
349 351 f = open('mercurial/hgpythonlib.h', 'wb')
350 352 f.write('/* this file is autogenerated by setup.py */\n')
351 353 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
352 354 f.close()
353 355 objects = self.compiler.compile(['mercurial/exewrapper.c'],
354 356 output_dir=self.build_temp)
355 357 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
356 358 target = os.path.join(dir, 'hg')
357 359 self.compiler.link_executable(objects, target,
358 360 libraries=[],
359 361 output_dir=self.build_temp)
360 362
361 363 class hginstallscripts(install_scripts):
362 364 '''
363 365 This is a specialization of install_scripts that replaces the @LIBDIR@ with
364 366 the configured directory for modules. If possible, the path is made relative
365 367 to the directory for scripts.
366 368 '''
367 369
368 370 def initialize_options(self):
369 371 install_scripts.initialize_options(self)
370 372
371 373 self.install_lib = None
372 374
373 375 def finalize_options(self):
374 376 install_scripts.finalize_options(self)
375 377 self.set_undefined_options('install',
376 378 ('install_lib', 'install_lib'))
377 379
378 380 def run(self):
379 381 install_scripts.run(self)
380 382
381 383 if (os.path.splitdrive(self.install_dir)[0] !=
382 384 os.path.splitdrive(self.install_lib)[0]):
383 385 # can't make relative paths from one drive to another, so use an
384 386 # absolute path instead
385 387 libdir = self.install_lib
386 388 else:
387 389 common = os.path.commonprefix((self.install_dir, self.install_lib))
388 390 rest = self.install_dir[len(common):]
389 391 uplevel = len([n for n in os.path.split(rest) if n])
390 392
391 393 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
392 394
393 395 for outfile in self.outfiles:
394 396 fp = open(outfile, 'rb')
395 397 data = fp.read()
396 398 fp.close()
397 399
398 400 # skip binary files
399 401 if b('\0') in data:
400 402 continue
401 403
402 404 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
403 405 fp = open(outfile, 'wb')
404 406 fp.write(data)
405 407 fp.close()
406 408
407 409 cmdclass = {'build': hgbuild,
408 410 'build_mo': hgbuildmo,
409 411 'build_ext': hgbuildext,
410 412 'build_py': hgbuildpy,
411 413 'build_hgextindex': buildhgextindex,
412 414 'install_scripts': hginstallscripts,
413 415 'build_hgexe': buildhgexe,
414 416 }
415 417
416 418 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
417 419 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
418 420 'hgext.largefiles']
419 421
420 422 pymodules = []
421 423
422 424 extmodules = [
423 425 Extension('mercurial.base85', ['mercurial/base85.c']),
424 426 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
425 427 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
426 428 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
427 429 Extension('mercurial.parsers', ['mercurial/parsers.c',
428 430 'mercurial/pathencode.c']),
429 431 ]
430 432
431 433 osutil_ldflags = []
432 434
433 435 if sys.platform == 'darwin':
434 436 osutil_ldflags += ['-framework', 'ApplicationServices']
435 437
436 438 # disable osutil.c under windows + python 2.4 (issue1364)
437 439 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
438 440 pymodules.append('mercurial.pure.osutil')
439 441 else:
440 442 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
441 443 extra_link_args=osutil_ldflags))
442 444
443 445 # the -mno-cygwin option has been deprecated for years
444 446 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
445 447
446 448 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
447 449 def __init__(self, *args, **kwargs):
448 450 Mingw32CCompiler.__init__(self, *args, **kwargs)
449 451 for i in 'compiler compiler_so linker_exe linker_so'.split():
450 452 try:
451 453 getattr(self, i).remove('-mno-cygwin')
452 454 except ValueError:
453 455 pass
454 456
455 457 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
456 458
457 459 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
458 460 # The inotify extension is only usable with Linux 2.6 kernels.
459 461 # You also need a reasonably recent C library.
460 462 # In any case, if it fails to build the error will be skipped ('optional').
461 463 cc = new_compiler()
462 464 if hasfunction(cc, 'inotify_add_watch'):
463 465 inotify = Extension('hgext.inotify.linux._inotify',
464 466 ['hgext/inotify/linux/_inotify.c'],
465 467 ['mercurial'])
466 468 inotify.optional = True
467 469 extmodules.append(inotify)
468 470 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
469 471
470 472 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
471 473 'help/*.txt']}
472 474
473 475 def ordinarypath(p):
474 476 return p and p[0] != '.' and p[-1] != '~'
475 477
476 478 for root in ('templates',):
477 479 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
478 480 curdir = curdir.split(os.sep, 1)[1]
479 481 dirs[:] = filter(ordinarypath, dirs)
480 482 for f in filter(ordinarypath, files):
481 483 f = os.path.join(curdir, f)
482 484 packagedata['mercurial'].append(f)
483 485
484 486 datafiles = []
485 487 setupversion = version
486 488 extra = {}
487 489
488 490 if py2exeloaded:
489 491 extra['console'] = [
490 492 {'script':'hg',
491 493 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
492 494 'product_version':version}]
493 495 # sub command of 'build' because 'py2exe' does not handle sub_commands
494 496 build.sub_commands.insert(0, ('build_hgextindex', None))
495 497
496 498 if os.name == 'nt':
497 499 # Windows binary file versions for exe/dll files must have the
498 500 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
499 501 setupversion = version.split('+', 1)[0]
500 502
501 503 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
502 504 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
503 505 # distutils.sysconfig
504 506 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
505 507 if version:
506 508 version = version[0]
507 509 xcode4 = (version.startswith('Xcode') and
508 510 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
509 511 else:
510 512 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
511 513 # installed, but instead with only command-line tools. Assume
512 514 # that only happens on >= Lion, thus no PPC support.
513 515 xcode4 = True
514 516
515 517 if xcode4:
516 518 os.environ['ARCHFLAGS'] = ''
517 519
518 520 setup(name='mercurial',
519 521 version=setupversion,
520 522 author='Matt Mackall',
521 523 author_email='mpm@selenic.com',
522 524 url='http://mercurial.selenic.com/',
523 525 description='Scalable distributed SCM',
524 526 license='GNU GPLv2+',
525 527 scripts=scripts,
526 528 packages=packages,
527 529 py_modules=pymodules,
528 530 ext_modules=extmodules,
529 531 data_files=datafiles,
530 532 package_data=packagedata,
531 533 cmdclass=cmdclass,
532 534 distclass=hgdist,
533 535 options=dict(py2exe=dict(packages=['hgext', 'email']),
534 536 bdist_mpkg=dict(zipdist=True,
535 537 license='COPYING',
536 538 readme='contrib/macosx/Readme.html',
537 539 welcome='contrib/macosx/Welcome.html')),
538 540 **extra)
General Comments 0
You need to be logged in to leave comments. Login now