##// END OF EJS Templates
setup: fail if we cannot determine the version number...
Adam Simpkins -
r33110:6fdc1518 default
parent child Browse files
Show More
@@ -1,838 +1,844
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 sys.version_info < (2, 7, 0, 'final'):
9 9 raise SystemExit('Mercurial requires Python 2.7 or later.')
10 10
11 11 if sys.version_info[0] >= 3:
12 12 printf = eval('print')
13 13 libdir_escape = 'unicode_escape'
14 14 else:
15 15 libdir_escape = 'string_escape'
16 16 def printf(*args, **kwargs):
17 17 f = kwargs.get('file', sys.stdout)
18 18 end = kwargs.get('end', '\n')
19 19 f.write(b' '.join(args) + end)
20 20
21 21 # Solaris Python packaging brain damage
22 22 try:
23 23 import hashlib
24 24 sha = hashlib.sha1()
25 25 except ImportError:
26 26 try:
27 27 import sha
28 28 sha.sha # silence unused import warning
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 zlib.compressobj # silence unused import warning
36 36 except ImportError:
37 37 raise SystemExit(
38 38 "Couldn't import standard zlib (incomplete Python install).")
39 39
40 40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
41 41 isironpython = False
42 42 try:
43 43 isironpython = (platform.python_implementation()
44 44 .lower().find("ironpython") != -1)
45 45 except AttributeError:
46 46 pass
47 47
48 48 if isironpython:
49 49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
50 50 else:
51 51 try:
52 52 import bz2
53 53 bz2.BZ2Compressor # silence unused import warning
54 54 except ImportError:
55 55 raise SystemExit(
56 56 "Couldn't import standard bz2 (incomplete Python install).")
57 57
58 58 ispypy = "PyPy" in sys.version
59 59
60 60 import ctypes
61 61 import os, stat, subprocess, time
62 62 import re
63 63 import shutil
64 64 import tempfile
65 65 from distutils import log
66 66 # We have issues with setuptools on some platforms and builders. Until
67 67 # those are resolved, setuptools is opt-in except for platforms where
68 68 # we don't have issues.
69 69 if os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ:
70 70 from setuptools import setup
71 71 else:
72 72 from distutils.core import setup
73 73 from distutils.ccompiler import new_compiler
74 74 from distutils.core import Command, Extension
75 75 from distutils.dist import Distribution
76 76 from distutils.command.build import build
77 77 from distutils.command.build_ext import build_ext
78 78 from distutils.command.build_py import build_py
79 79 from distutils.command.build_scripts import build_scripts
80 80 from distutils.command.install import install
81 81 from distutils.command.install_lib import install_lib
82 82 from distutils.command.install_scripts import install_scripts
83 83 from distutils.spawn import spawn, find_executable
84 84 from distutils import file_util
85 85 from distutils.errors import (
86 86 CCompilerError,
87 87 DistutilsError,
88 88 DistutilsExecError,
89 89 )
90 90 from distutils.sysconfig import get_python_inc, get_config_var
91 91 from distutils.version import StrictVersion
92 92
93 93 scripts = ['hg']
94 94 if os.name == 'nt':
95 95 # We remove hg.bat if we are able to build hg.exe.
96 96 scripts.append('contrib/win32/hg.bat')
97 97
98 98 def cancompile(cc, code):
99 99 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
100 100 devnull = oldstderr = None
101 101 try:
102 102 fname = os.path.join(tmpdir, 'testcomp.c')
103 103 f = open(fname, 'w')
104 104 f.write(code)
105 105 f.close()
106 106 # Redirect stderr to /dev/null to hide any error messages
107 107 # from the compiler.
108 108 # This will have to be changed if we ever have to check
109 109 # for a function on Windows.
110 110 devnull = open('/dev/null', 'w')
111 111 oldstderr = os.dup(sys.stderr.fileno())
112 112 os.dup2(devnull.fileno(), sys.stderr.fileno())
113 113 objects = cc.compile([fname], output_dir=tmpdir)
114 114 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
115 115 return True
116 116 except Exception:
117 117 return False
118 118 finally:
119 119 if oldstderr is not None:
120 120 os.dup2(oldstderr, sys.stderr.fileno())
121 121 if devnull is not None:
122 122 devnull.close()
123 123 shutil.rmtree(tmpdir)
124 124
125 125 # simplified version of distutils.ccompiler.CCompiler.has_function
126 126 # that actually removes its temporary files.
127 127 def hasfunction(cc, funcname):
128 128 code = 'int main(void) { %s(); }\n' % funcname
129 129 return cancompile(cc, code)
130 130
131 131 def hasheader(cc, headername):
132 132 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
133 133 return cancompile(cc, code)
134 134
135 135 # py2exe needs to be installed to work
136 136 try:
137 137 import py2exe
138 138 py2exe.Distribution # silence unused import warning
139 139 py2exeloaded = True
140 140 # import py2exe's patched Distribution class
141 141 from distutils.core import Distribution
142 142 except ImportError:
143 143 py2exeloaded = False
144 144
145 145 def runcmd(cmd, env):
146 146 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
147 147 stderr=subprocess.PIPE, env=env)
148 148 out, err = p.communicate()
149 149 return out, err
150 150
151 151 def runhg(cmd, env):
152 152 out, err = runcmd(cmd, env)
153 153 # If root is executing setup.py, but the repository is owned by
154 154 # another user (as in "sudo python setup.py install") we will get
155 155 # trust warnings since the .hg/hgrc file is untrusted. That is
156 156 # fine, we don't want to load it anyway. Python may warn about
157 157 # a missing __init__.py in mercurial/locale, we also ignore that.
158 158 err = [e for e in err.splitlines()
159 159 if not e.startswith(b'not trusting file') \
160 160 and not e.startswith(b'warning: Not importing') \
161 161 and not e.startswith(b'obsolete feature not enabled')]
162 162 if err:
163 163 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
164 164 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
165 165 return ''
166 166 return out
167 167
168 168 version = ''
169 169
170 170 # Execute hg out of this directory with a custom environment which takes care
171 171 # to not use any hgrc files and do no localization.
172 172 env = {'HGMODULEPOLICY': 'py',
173 173 'HGRCPATH': '',
174 174 'LANGUAGE': 'C',
175 175 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
176 176 if 'LD_LIBRARY_PATH' in os.environ:
177 177 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
178 178 if 'SystemRoot' in os.environ:
179 179 # SystemRoot is required by Windows to load various DLLs. See:
180 180 # https://bugs.python.org/issue13524#msg148850
181 181 env['SystemRoot'] = os.environ['SystemRoot']
182 182
183 183 if os.path.isdir('.hg'):
184 184 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
185 185 numerictags = [t for t in runhg(cmd, env).split() if t[0:1].isdigit()]
186 186 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
187 if not hgid:
188 # Bail out if hg is having problems interacting with this repository,
189 # rather than falling through and producing a bogus version number.
190 # Continuing with an invalid version number will break extensions
191 # that define minimumhgversion.
192 raise SystemExit('Unable to determine hg version from local repository')
187 193 if numerictags: # tag(s) found
188 194 version = numerictags[-1]
189 195 if hgid.endswith('+'): # propagate the dirty status to the tag
190 196 version += '+'
191 197 else: # no tag found
192 198 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
193 199 '{latesttag}']
194 200 ltag = runhg(ltagcmd, env)
195 201 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
196 202 "only(.,'%s')" % ltag]
197 203 changessince = len(runhg(changessincecmd, env).splitlines())
198 204 version = '%s+%s-%s' % (ltag, changessince, hgid)
199 205 if version.endswith('+'):
200 206 version += time.strftime('%Y%m%d')
201 207 elif os.path.exists('.hg_archival.txt'):
202 208 kw = dict([[t.strip() for t in l.split(':', 1)]
203 209 for l in open('.hg_archival.txt')])
204 210 if 'tag' in kw:
205 211 version = kw['tag']
206 212 elif 'latesttag' in kw:
207 213 if 'changessincelatesttag' in kw:
208 214 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
209 215 else:
210 216 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
211 217 else:
212 218 version = kw.get('node', '')[:12]
213 219
214 220 if version:
215 221 with open("mercurial/__version__.py", "w") as f:
216 222 f.write('# this file is autogenerated by setup.py\n')
217 223 f.write('version = "%s"\n' % version)
218 224
219 225 try:
220 226 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
221 227 os.environ['HGMODULEPOLICY'] = 'py'
222 228 from mercurial import __version__
223 229 version = __version__.version
224 230 except ImportError:
225 231 version = 'unknown'
226 232 finally:
227 233 if oldpolicy is None:
228 234 del os.environ['HGMODULEPOLICY']
229 235 else:
230 236 os.environ['HGMODULEPOLICY'] = oldpolicy
231 237
232 238 class hgbuild(build):
233 239 # Insert hgbuildmo first so that files in mercurial/locale/ are found
234 240 # when build_py is run next.
235 241 sub_commands = [('build_mo', None)] + build.sub_commands
236 242
237 243 class hgbuildmo(build):
238 244
239 245 description = "build translations (.mo files)"
240 246
241 247 def run(self):
242 248 if not find_executable('msgfmt'):
243 249 self.warn("could not find msgfmt executable, no translations "
244 250 "will be built")
245 251 return
246 252
247 253 podir = 'i18n'
248 254 if not os.path.isdir(podir):
249 255 self.warn("could not find %s/ directory" % podir)
250 256 return
251 257
252 258 join = os.path.join
253 259 for po in os.listdir(podir):
254 260 if not po.endswith('.po'):
255 261 continue
256 262 pofile = join(podir, po)
257 263 modir = join('locale', po[:-3], 'LC_MESSAGES')
258 264 mofile = join(modir, 'hg.mo')
259 265 mobuildfile = join('mercurial', mofile)
260 266 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
261 267 if sys.platform != 'sunos5':
262 268 # msgfmt on Solaris does not know about -c
263 269 cmd.append('-c')
264 270 self.mkpath(join('mercurial', modir))
265 271 self.make_file([pofile], mobuildfile, spawn, (cmd,))
266 272
267 273
268 274 class hgdist(Distribution):
269 275 pure = False
270 276 cffi = ispypy
271 277
272 278 global_options = Distribution.global_options + \
273 279 [('pure', None, "use pure (slow) Python "
274 280 "code instead of C extensions"),
275 281 ]
276 282
277 283 def has_ext_modules(self):
278 284 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
279 285 # too late for some cases
280 286 return not self.pure and Distribution.has_ext_modules(self)
281 287
282 288 # This is ugly as a one-liner. So use a variable.
283 289 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
284 290 buildextnegops['no-zstd'] = 'zstd'
285 291
286 292 class hgbuildext(build_ext):
287 293 user_options = build_ext.user_options + [
288 294 ('zstd', None, 'compile zstd bindings [default]'),
289 295 ('no-zstd', None, 'do not compile zstd bindings'),
290 296 ]
291 297
292 298 boolean_options = build_ext.boolean_options + ['zstd']
293 299 negative_opt = buildextnegops
294 300
295 301 def initialize_options(self):
296 302 self.zstd = True
297 303 return build_ext.initialize_options(self)
298 304
299 305 def build_extensions(self):
300 306 # Filter out zstd if disabled via argument.
301 307 if not self.zstd:
302 308 self.extensions = [e for e in self.extensions
303 309 if e.name != 'mercurial.zstd']
304 310
305 311 return build_ext.build_extensions(self)
306 312
307 313 def build_extension(self, ext):
308 314 try:
309 315 build_ext.build_extension(self, ext)
310 316 except CCompilerError:
311 317 if not getattr(ext, 'optional', False):
312 318 raise
313 319 log.warn("Failed to build optional extension '%s' (skipping)",
314 320 ext.name)
315 321
316 322 class hgbuildscripts(build_scripts):
317 323 def run(self):
318 324 if os.name != 'nt' or self.distribution.pure:
319 325 return build_scripts.run(self)
320 326
321 327 exebuilt = False
322 328 try:
323 329 self.run_command('build_hgexe')
324 330 exebuilt = True
325 331 except (DistutilsError, CCompilerError):
326 332 log.warn('failed to build optional hg.exe')
327 333
328 334 if exebuilt:
329 335 # Copying hg.exe to the scripts build directory ensures it is
330 336 # installed by the install_scripts command.
331 337 hgexecommand = self.get_finalized_command('build_hgexe')
332 338 dest = os.path.join(self.build_dir, 'hg.exe')
333 339 self.mkpath(self.build_dir)
334 340 self.copy_file(hgexecommand.hgexepath, dest)
335 341
336 342 # Remove hg.bat because it is redundant with hg.exe.
337 343 self.scripts.remove('contrib/win32/hg.bat')
338 344
339 345 return build_scripts.run(self)
340 346
341 347 class hgbuildpy(build_py):
342 348 def finalize_options(self):
343 349 build_py.finalize_options(self)
344 350
345 351 if self.distribution.pure:
346 352 self.distribution.ext_modules = []
347 353 elif self.distribution.cffi:
348 354 from mercurial.cffi import (
349 355 bdiffbuild,
350 356 mpatchbuild,
351 357 )
352 358 exts = [mpatchbuild.ffi.distutils_extension(),
353 359 bdiffbuild.ffi.distutils_extension()]
354 360 # cffi modules go here
355 361 if sys.platform == 'darwin':
356 362 from mercurial.cffi import osutilbuild
357 363 exts.append(osutilbuild.ffi.distutils_extension())
358 364 self.distribution.ext_modules = exts
359 365 else:
360 366 h = os.path.join(get_python_inc(), 'Python.h')
361 367 if not os.path.exists(h):
362 368 raise SystemExit('Python headers are required to build '
363 369 'Mercurial but weren\'t found in %s' % h)
364 370
365 371 def run(self):
366 372 basepath = os.path.join(self.build_lib, 'mercurial')
367 373 self.mkpath(basepath)
368 374
369 375 if self.distribution.pure:
370 376 modulepolicy = 'py'
371 377 elif self.build_lib == '.':
372 378 # in-place build should run without rebuilding C extensions
373 379 modulepolicy = 'allow'
374 380 else:
375 381 modulepolicy = 'c'
376 382 with open(os.path.join(basepath, '__modulepolicy__.py'), "w") as f:
377 383 f.write('# this file is autogenerated by setup.py\n')
378 384 f.write('modulepolicy = b"%s"\n' % modulepolicy)
379 385
380 386 build_py.run(self)
381 387
382 388 class buildhgextindex(Command):
383 389 description = 'generate prebuilt index of hgext (for frozen package)'
384 390 user_options = []
385 391 _indexfilename = 'hgext/__index__.py'
386 392
387 393 def initialize_options(self):
388 394 pass
389 395
390 396 def finalize_options(self):
391 397 pass
392 398
393 399 def run(self):
394 400 if os.path.exists(self._indexfilename):
395 401 with open(self._indexfilename, 'w') as f:
396 402 f.write('# empty\n')
397 403
398 404 # here no extension enabled, disabled() lists up everything
399 405 code = ('import pprint; from mercurial import extensions; '
400 406 'pprint.pprint(extensions.disabled())')
401 407 out, err = runcmd([sys.executable, '-c', code], env)
402 408 if err:
403 409 raise DistutilsExecError(err)
404 410
405 411 with open(self._indexfilename, 'w') as f:
406 412 f.write('# this file is autogenerated by setup.py\n')
407 413 f.write('docs = ')
408 414 f.write(out)
409 415
410 416 class buildhgexe(build_ext):
411 417 description = 'compile hg.exe from mercurial/exewrapper.c'
412 418
413 419 def build_extensions(self):
414 420 if os.name != 'nt':
415 421 return
416 422 if isinstance(self.compiler, HackedMingw32CCompiler):
417 423 self.compiler.compiler_so = self.compiler.compiler # no -mdll
418 424 self.compiler.dll_libraries = [] # no -lmsrvc90
419 425
420 426 # Different Python installs can have different Python library
421 427 # names. e.g. the official CPython distribution uses pythonXY.dll
422 428 # and MinGW uses libpythonX.Y.dll.
423 429 _kernel32 = ctypes.windll.kernel32
424 430 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
425 431 ctypes.c_void_p,
426 432 ctypes.c_ulong]
427 433 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
428 434 size = 1000
429 435 buf = ctypes.create_string_buffer(size + 1)
430 436 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
431 437 size)
432 438
433 439 if filelen > 0 and filelen != size:
434 440 dllbasename = os.path.basename(buf.value)
435 441 if not dllbasename.lower().endswith('.dll'):
436 442 raise SystemExit('Python DLL does not end with .dll: %s' %
437 443 dllbasename)
438 444 pythonlib = dllbasename[:-4]
439 445 else:
440 446 log.warn('could not determine Python DLL filename; '
441 447 'assuming pythonXY')
442 448
443 449 hv = sys.hexversion
444 450 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
445 451
446 452 log.info('using %s as Python library name' % pythonlib)
447 453 with open('mercurial/hgpythonlib.h', 'wb') as f:
448 454 f.write('/* this file is autogenerated by setup.py */\n')
449 455 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
450 456 objects = self.compiler.compile(['mercurial/exewrapper.c'],
451 457 output_dir=self.build_temp)
452 458 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
453 459 target = os.path.join(dir, 'hg')
454 460 self.compiler.link_executable(objects, target,
455 461 libraries=[],
456 462 output_dir=self.build_temp)
457 463
458 464 @property
459 465 def hgexepath(self):
460 466 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
461 467 return os.path.join(self.build_temp, dir, 'hg.exe')
462 468
463 469 class hginstall(install):
464 470
465 471 user_options = install.user_options + [
466 472 ('old-and-unmanageable', None,
467 473 'noop, present for eggless setuptools compat'),
468 474 ('single-version-externally-managed', None,
469 475 'noop, present for eggless setuptools compat'),
470 476 ]
471 477
472 478 # Also helps setuptools not be sad while we refuse to create eggs.
473 479 single_version_externally_managed = True
474 480
475 481 def get_sub_commands(self):
476 482 # Screen out egg related commands to prevent egg generation. But allow
477 483 # mercurial.egg-info generation, since that is part of modern
478 484 # packaging.
479 485 excl = {'bdist_egg'}
480 486 return filter(lambda x: x not in excl, install.get_sub_commands(self))
481 487
482 488 class hginstalllib(install_lib):
483 489 '''
484 490 This is a specialization of install_lib that replaces the copy_file used
485 491 there so that it supports setting the mode of files after copying them,
486 492 instead of just preserving the mode that the files originally had. If your
487 493 system has a umask of something like 027, preserving the permissions when
488 494 copying will lead to a broken install.
489 495
490 496 Note that just passing keep_permissions=False to copy_file would be
491 497 insufficient, as it might still be applying a umask.
492 498 '''
493 499
494 500 def run(self):
495 501 realcopyfile = file_util.copy_file
496 502 def copyfileandsetmode(*args, **kwargs):
497 503 src, dst = args[0], args[1]
498 504 dst, copied = realcopyfile(*args, **kwargs)
499 505 if copied:
500 506 st = os.stat(src)
501 507 # Persist executable bit (apply it to group and other if user
502 508 # has it)
503 509 if st[stat.ST_MODE] & stat.S_IXUSR:
504 510 setmode = int('0755', 8)
505 511 else:
506 512 setmode = int('0644', 8)
507 513 m = stat.S_IMODE(st[stat.ST_MODE])
508 514 m = (m & ~int('0777', 8)) | setmode
509 515 os.chmod(dst, m)
510 516 file_util.copy_file = copyfileandsetmode
511 517 try:
512 518 install_lib.run(self)
513 519 finally:
514 520 file_util.copy_file = realcopyfile
515 521
516 522 class hginstallscripts(install_scripts):
517 523 '''
518 524 This is a specialization of install_scripts that replaces the @LIBDIR@ with
519 525 the configured directory for modules. If possible, the path is made relative
520 526 to the directory for scripts.
521 527 '''
522 528
523 529 def initialize_options(self):
524 530 install_scripts.initialize_options(self)
525 531
526 532 self.install_lib = None
527 533
528 534 def finalize_options(self):
529 535 install_scripts.finalize_options(self)
530 536 self.set_undefined_options('install',
531 537 ('install_lib', 'install_lib'))
532 538
533 539 def run(self):
534 540 install_scripts.run(self)
535 541
536 542 # It only makes sense to replace @LIBDIR@ with the install path if
537 543 # the install path is known. For wheels, the logic below calculates
538 544 # the libdir to be "../..". This is because the internal layout of a
539 545 # wheel archive looks like:
540 546 #
541 547 # mercurial-3.6.1.data/scripts/hg
542 548 # mercurial/__init__.py
543 549 #
544 550 # When installing wheels, the subdirectories of the "<pkg>.data"
545 551 # directory are translated to system local paths and files therein
546 552 # are copied in place. The mercurial/* files are installed into the
547 553 # site-packages directory. However, the site-packages directory
548 554 # isn't known until wheel install time. This means we have no clue
549 555 # at wheel generation time what the installed site-packages directory
550 556 # will be. And, wheels don't appear to provide the ability to register
551 557 # custom code to run during wheel installation. This all means that
552 558 # we can't reliably set the libdir in wheels: the default behavior
553 559 # of looking in sys.path must do.
554 560
555 561 if (os.path.splitdrive(self.install_dir)[0] !=
556 562 os.path.splitdrive(self.install_lib)[0]):
557 563 # can't make relative paths from one drive to another, so use an
558 564 # absolute path instead
559 565 libdir = self.install_lib
560 566 else:
561 567 common = os.path.commonprefix((self.install_dir, self.install_lib))
562 568 rest = self.install_dir[len(common):]
563 569 uplevel = len([n for n in os.path.split(rest) if n])
564 570
565 571 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
566 572
567 573 for outfile in self.outfiles:
568 574 with open(outfile, 'rb') as fp:
569 575 data = fp.read()
570 576
571 577 # skip binary files
572 578 if b'\0' in data:
573 579 continue
574 580
575 581 # During local installs, the shebang will be rewritten to the final
576 582 # install path. During wheel packaging, the shebang has a special
577 583 # value.
578 584 if data.startswith(b'#!python'):
579 585 log.info('not rewriting @LIBDIR@ in %s because install path '
580 586 'not known' % outfile)
581 587 continue
582 588
583 589 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
584 590 with open(outfile, 'wb') as fp:
585 591 fp.write(data)
586 592
587 593 cmdclass = {'build': hgbuild,
588 594 'build_mo': hgbuildmo,
589 595 'build_ext': hgbuildext,
590 596 'build_py': hgbuildpy,
591 597 'build_scripts': hgbuildscripts,
592 598 'build_hgextindex': buildhgextindex,
593 599 'install': hginstall,
594 600 'install_lib': hginstalllib,
595 601 'install_scripts': hginstallscripts,
596 602 'build_hgexe': buildhgexe,
597 603 }
598 604
599 605 packages = ['mercurial',
600 606 'mercurial.cext',
601 607 'mercurial.cffi',
602 608 'mercurial.hgweb',
603 609 'mercurial.httpclient',
604 610 'mercurial.pure',
605 611 'hgext', 'hgext.convert', 'hgext.fsmonitor',
606 612 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
607 613 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd',
608 614 'hgdemandimport']
609 615
610 616 common_depends = ['mercurial/bitmanipulation.h',
611 617 'mercurial/compat.h',
612 618 'mercurial/cext/util.h']
613 619 common_include_dirs = ['mercurial']
614 620
615 621 osutil_cflags = []
616 622 osutil_ldflags = []
617 623
618 624 # platform specific macros
619 625 for plat, func in [('bsd', 'setproctitle')]:
620 626 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
621 627 osutil_cflags.append('-DHAVE_%s' % func.upper())
622 628
623 629 for plat, macro, code in [
624 630 ('bsd|darwin', 'BSD_STATFS', '''
625 631 #include <sys/param.h>
626 632 #include <sys/mount.h>
627 633 int main() { struct statfs s; return sizeof(s.f_fstypename); }
628 634 '''),
629 635 ('linux', 'LINUX_STATFS', '''
630 636 #include <linux/magic.h>
631 637 #include <sys/vfs.h>
632 638 int main() { struct statfs s; return sizeof(s.f_type); }
633 639 '''),
634 640 ]:
635 641 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
636 642 osutil_cflags.append('-DHAVE_%s' % macro)
637 643
638 644 if sys.platform == 'darwin':
639 645 osutil_ldflags += ['-framework', 'ApplicationServices']
640 646
641 647 extmodules = [
642 648 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
643 649 include_dirs=common_include_dirs,
644 650 depends=common_depends),
645 651 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
646 652 'mercurial/cext/bdiff.c'],
647 653 include_dirs=common_include_dirs,
648 654 depends=common_depends + ['mercurial/bdiff.h']),
649 655 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
650 656 include_dirs=common_include_dirs,
651 657 depends=common_depends),
652 658 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
653 659 'mercurial/cext/mpatch.c'],
654 660 include_dirs=common_include_dirs,
655 661 depends=common_depends),
656 662 Extension('mercurial.cext.parsers', ['mercurial/cext/dirs.c',
657 663 'mercurial/cext/manifest.c',
658 664 'mercurial/cext/parsers.c',
659 665 'mercurial/cext/pathencode.c',
660 666 'mercurial/cext/revlog.c'],
661 667 include_dirs=common_include_dirs,
662 668 depends=common_depends),
663 669 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
664 670 include_dirs=common_include_dirs,
665 671 extra_compile_args=osutil_cflags,
666 672 extra_link_args=osutil_ldflags,
667 673 depends=common_depends),
668 674 Extension('hgext.fsmonitor.pywatchman.bser',
669 675 ['hgext/fsmonitor/pywatchman/bser.c']),
670 676 ]
671 677
672 678 sys.path.insert(0, 'contrib/python-zstandard')
673 679 import setup_zstd
674 680 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
675 681
676 682 try:
677 683 from distutils import cygwinccompiler
678 684
679 685 # the -mno-cygwin option has been deprecated for years
680 686 compiler = cygwinccompiler.Mingw32CCompiler
681 687
682 688 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
683 689 def __init__(self, *args, **kwargs):
684 690 compiler.__init__(self, *args, **kwargs)
685 691 for i in 'compiler compiler_so linker_exe linker_so'.split():
686 692 try:
687 693 getattr(self, i).remove('-mno-cygwin')
688 694 except ValueError:
689 695 pass
690 696
691 697 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
692 698 except ImportError:
693 699 # the cygwinccompiler package is not available on some Python
694 700 # distributions like the ones from the optware project for Synology
695 701 # DiskStation boxes
696 702 class HackedMingw32CCompiler(object):
697 703 pass
698 704
699 705 if os.name == 'nt':
700 706 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
701 707 # extra_link_args to distutils.extensions.Extension() doesn't have any
702 708 # effect.
703 709 from distutils import msvccompiler
704 710
705 711 compiler = msvccompiler.MSVCCompiler
706 712
707 713 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
708 714 def initialize(self):
709 715 compiler.initialize(self)
710 716 # "warning LNK4197: export 'func' specified multiple times"
711 717 self.ldflags_shared.append('/ignore:4197')
712 718 self.ldflags_shared_debug.append('/ignore:4197')
713 719
714 720 msvccompiler.MSVCCompiler = HackedMSVCCompiler
715 721
716 722 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
717 723 'help/*.txt',
718 724 'help/internals/*.txt',
719 725 'default.d/*.rc',
720 726 'dummycert.pem']}
721 727
722 728 def ordinarypath(p):
723 729 return p and p[0] != '.' and p[-1] != '~'
724 730
725 731 for root in ('templates',):
726 732 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
727 733 curdir = curdir.split(os.sep, 1)[1]
728 734 dirs[:] = filter(ordinarypath, dirs)
729 735 for f in filter(ordinarypath, files):
730 736 f = os.path.join(curdir, f)
731 737 packagedata['mercurial'].append(f)
732 738
733 739 datafiles = []
734 740
735 741 # distutils expects version to be str/unicode. Converting it to
736 742 # unicode on Python 2 still works because it won't contain any
737 743 # non-ascii bytes and will be implicitly converted back to bytes
738 744 # when operated on.
739 745 assert isinstance(version, bytes)
740 746 setupversion = version.decode('ascii')
741 747
742 748 extra = {}
743 749
744 750 if py2exeloaded:
745 751 extra['console'] = [
746 752 {'script':'hg',
747 753 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
748 754 'product_version':version}]
749 755 # sub command of 'build' because 'py2exe' does not handle sub_commands
750 756 build.sub_commands.insert(0, ('build_hgextindex', None))
751 757 # put dlls in sub directory so that they won't pollute PATH
752 758 extra['zipfile'] = 'lib/library.zip'
753 759
754 760 if os.name == 'nt':
755 761 # Windows binary file versions for exe/dll files must have the
756 762 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
757 763 setupversion = version.split('+', 1)[0]
758 764
759 765 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
760 766 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
761 767 if version:
762 768 version = version[0]
763 769 if sys.version_info[0] == 3:
764 770 version = version.decode('utf-8')
765 771 xcode4 = (version.startswith('Xcode') and
766 772 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
767 773 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
768 774 else:
769 775 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
770 776 # installed, but instead with only command-line tools. Assume
771 777 # that only happens on >= Lion, thus no PPC support.
772 778 xcode4 = True
773 779 xcode51 = False
774 780
775 781 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
776 782 # distutils.sysconfig
777 783 if xcode4:
778 784 os.environ['ARCHFLAGS'] = ''
779 785
780 786 # XCode 5.1 changes clang such that it now fails to compile if the
781 787 # -mno-fused-madd flag is passed, but the version of Python shipped with
782 788 # OS X 10.9 Mavericks includes this flag. This causes problems in all
783 789 # C extension modules, and a bug has been filed upstream at
784 790 # http://bugs.python.org/issue21244. We also need to patch this here
785 791 # so Mercurial can continue to compile in the meantime.
786 792 if xcode51:
787 793 cflags = get_config_var('CFLAGS')
788 794 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
789 795 os.environ['CFLAGS'] = (
790 796 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
791 797
792 798 setup(name='mercurial',
793 799 version=setupversion,
794 800 author='Matt Mackall and many others',
795 801 author_email='mercurial@mercurial-scm.org',
796 802 url='https://mercurial-scm.org/',
797 803 download_url='https://mercurial-scm.org/release/',
798 804 description=('Fast scalable distributed SCM (revision control, version '
799 805 'control) system'),
800 806 long_description=('Mercurial is a distributed SCM tool written in Python.'
801 807 ' It is used by a number of large projects that require'
802 808 ' fast, reliable distributed revision control, such as '
803 809 'Mozilla.'),
804 810 license='GNU GPLv2 or any later version',
805 811 classifiers=[
806 812 'Development Status :: 6 - Mature',
807 813 'Environment :: Console',
808 814 'Intended Audience :: Developers',
809 815 'Intended Audience :: System Administrators',
810 816 'License :: OSI Approved :: GNU General Public License (GPL)',
811 817 'Natural Language :: Danish',
812 818 'Natural Language :: English',
813 819 'Natural Language :: German',
814 820 'Natural Language :: Italian',
815 821 'Natural Language :: Japanese',
816 822 'Natural Language :: Portuguese (Brazilian)',
817 823 'Operating System :: Microsoft :: Windows',
818 824 'Operating System :: OS Independent',
819 825 'Operating System :: POSIX',
820 826 'Programming Language :: C',
821 827 'Programming Language :: Python',
822 828 'Topic :: Software Development :: Version Control',
823 829 ],
824 830 scripts=scripts,
825 831 packages=packages,
826 832 ext_modules=extmodules,
827 833 data_files=datafiles,
828 834 package_data=packagedata,
829 835 cmdclass=cmdclass,
830 836 distclass=hgdist,
831 837 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email']},
832 838 'bdist_mpkg': {'zipdist': False,
833 839 'license': 'COPYING',
834 840 'readme': 'contrib/macosx/Readme.html',
835 841 'welcome': 'contrib/macosx/Welcome.html',
836 842 },
837 843 },
838 844 **extra)
General Comments 0
You need to be logged in to leave comments. Login now