##// END OF EJS Templates
setup: install cbor packages...
Gregory Szorc -
r37148:a1d2d042 default
parent child Browse files
Show More
@@ -1,1072 +1,1074 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 os
8 8
9 9 supportedpy = '~= 2.7'
10 10 if os.environ.get('HGALLOWPYTHON3', ''):
11 11 # Mercurial will never work on Python 3 before 3.5 due to a lack
12 12 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
13 13 # due to a bug in % formatting in bytestrings.
14 14 #
15 15 # TODO: when we actually work on Python 3, use this string as the
16 16 # actual supportedpy string.
17 17 supportedpy = ','.join([
18 18 '>=2.7',
19 19 '!=3.0.*',
20 20 '!=3.1.*',
21 21 '!=3.2.*',
22 22 '!=3.3.*',
23 23 '!=3.4.*',
24 24 '!=3.6.0',
25 25 '!=3.6.1',
26 26 ])
27 27
28 28 import sys, platform
29 29 if sys.version_info[0] >= 3:
30 30 printf = eval('print')
31 31 libdir_escape = 'unicode_escape'
32 32 def sysstr(s):
33 33 return s.decode('latin-1')
34 34 else:
35 35 libdir_escape = 'string_escape'
36 36 def printf(*args, **kwargs):
37 37 f = kwargs.get('file', sys.stdout)
38 38 end = kwargs.get('end', '\n')
39 39 f.write(b' '.join(args) + end)
40 40 def sysstr(s):
41 41 return s
42 42
43 43 # Attempt to guide users to a modern pip - this means that 2.6 users
44 44 # should have a chance of getting a 4.2 release, and when we ratchet
45 45 # the version requirement forward again hopefully everyone will get
46 46 # something that works for them.
47 47 if sys.version_info < (2, 7, 0, 'final'):
48 48 pip_message = ('This may be due to an out of date pip. '
49 49 'Make sure you have pip >= 9.0.1.')
50 50 try:
51 51 import pip
52 52 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
53 53 if pip_version < (9, 0, 1) :
54 54 pip_message = (
55 55 'Your pip version is out of date, please install '
56 56 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__))
57 57 else:
58 58 # pip is new enough - it must be something else
59 59 pip_message = ''
60 60 except Exception:
61 61 pass
62 62 error = """
63 63 Mercurial does not support Python older than 2.7.
64 64 Python {py} detected.
65 65 {pip}
66 66 """.format(py=sys.version_info, pip=pip_message)
67 67 printf(error, file=sys.stderr)
68 68 sys.exit(1)
69 69
70 70 # We don't yet officially support Python 3. But we want to allow developers to
71 71 # hack on. Detect and disallow running on Python 3 by default. But provide a
72 72 # backdoor to enable working on Python 3.
73 73 if sys.version_info[0] != 2:
74 74 badpython = True
75 75
76 76 # Allow Python 3 from source checkouts.
77 77 if os.path.isdir('.hg'):
78 78 badpython = False
79 79
80 80 if badpython:
81 81 error = """
82 82 Mercurial only supports Python 2.7.
83 83 Python {py} detected.
84 84 Please re-run with Python 2.7.
85 85 """.format(py=sys.version_info)
86 86
87 87 printf(error, file=sys.stderr)
88 88 sys.exit(1)
89 89
90 90 # Solaris Python packaging brain damage
91 91 try:
92 92 import hashlib
93 93 sha = hashlib.sha1()
94 94 except ImportError:
95 95 try:
96 96 import sha
97 97 sha.sha # silence unused import warning
98 98 except ImportError:
99 99 raise SystemExit(
100 100 "Couldn't import standard hashlib (incomplete Python install).")
101 101
102 102 try:
103 103 import zlib
104 104 zlib.compressobj # silence unused import warning
105 105 except ImportError:
106 106 raise SystemExit(
107 107 "Couldn't import standard zlib (incomplete Python install).")
108 108
109 109 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
110 110 isironpython = False
111 111 try:
112 112 isironpython = (platform.python_implementation()
113 113 .lower().find("ironpython") != -1)
114 114 except AttributeError:
115 115 pass
116 116
117 117 if isironpython:
118 118 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
119 119 else:
120 120 try:
121 121 import bz2
122 122 bz2.BZ2Compressor # silence unused import warning
123 123 except ImportError:
124 124 raise SystemExit(
125 125 "Couldn't import standard bz2 (incomplete Python install).")
126 126
127 127 ispypy = "PyPy" in sys.version
128 128
129 129 import ctypes
130 130 import stat, subprocess, time
131 131 import re
132 132 import shutil
133 133 import tempfile
134 134 from distutils import log
135 135 # We have issues with setuptools on some platforms and builders. Until
136 136 # those are resolved, setuptools is opt-in except for platforms where
137 137 # we don't have issues.
138 138 issetuptools = (os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ)
139 139 if issetuptools:
140 140 from setuptools import setup
141 141 else:
142 142 from distutils.core import setup
143 143 from distutils.ccompiler import new_compiler
144 144 from distutils.core import Command, Extension
145 145 from distutils.dist import Distribution
146 146 from distutils.command.build import build
147 147 from distutils.command.build_ext import build_ext
148 148 from distutils.command.build_py import build_py
149 149 from distutils.command.build_scripts import build_scripts
150 150 from distutils.command.install import install
151 151 from distutils.command.install_lib import install_lib
152 152 from distutils.command.install_scripts import install_scripts
153 153 from distutils.spawn import spawn, find_executable
154 154 from distutils import file_util
155 155 from distutils.errors import (
156 156 CCompilerError,
157 157 DistutilsError,
158 158 DistutilsExecError,
159 159 )
160 160 from distutils.sysconfig import get_python_inc, get_config_var
161 161 from distutils.version import StrictVersion
162 162
163 163 def write_if_changed(path, content):
164 164 """Write content to a file iff the content hasn't changed."""
165 165 if os.path.exists(path):
166 166 with open(path, 'rb') as fh:
167 167 current = fh.read()
168 168 else:
169 169 current = b''
170 170
171 171 if current != content:
172 172 with open(path, 'wb') as fh:
173 173 fh.write(content)
174 174
175 175 scripts = ['hg']
176 176 if os.name == 'nt':
177 177 # We remove hg.bat if we are able to build hg.exe.
178 178 scripts.append('contrib/win32/hg.bat')
179 179
180 180 def cancompile(cc, code):
181 181 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
182 182 devnull = oldstderr = None
183 183 try:
184 184 fname = os.path.join(tmpdir, 'testcomp.c')
185 185 f = open(fname, 'w')
186 186 f.write(code)
187 187 f.close()
188 188 # Redirect stderr to /dev/null to hide any error messages
189 189 # from the compiler.
190 190 # This will have to be changed if we ever have to check
191 191 # for a function on Windows.
192 192 devnull = open('/dev/null', 'w')
193 193 oldstderr = os.dup(sys.stderr.fileno())
194 194 os.dup2(devnull.fileno(), sys.stderr.fileno())
195 195 objects = cc.compile([fname], output_dir=tmpdir)
196 196 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
197 197 return True
198 198 except Exception:
199 199 return False
200 200 finally:
201 201 if oldstderr is not None:
202 202 os.dup2(oldstderr, sys.stderr.fileno())
203 203 if devnull is not None:
204 204 devnull.close()
205 205 shutil.rmtree(tmpdir)
206 206
207 207 # simplified version of distutils.ccompiler.CCompiler.has_function
208 208 # that actually removes its temporary files.
209 209 def hasfunction(cc, funcname):
210 210 code = 'int main(void) { %s(); }\n' % funcname
211 211 return cancompile(cc, code)
212 212
213 213 def hasheader(cc, headername):
214 214 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
215 215 return cancompile(cc, code)
216 216
217 217 # py2exe needs to be installed to work
218 218 try:
219 219 import py2exe
220 220 py2exe.Distribution # silence unused import warning
221 221 py2exeloaded = True
222 222 # import py2exe's patched Distribution class
223 223 from distutils.core import Distribution
224 224 except ImportError:
225 225 py2exeloaded = False
226 226
227 227 def runcmd(cmd, env):
228 228 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
229 229 stderr=subprocess.PIPE, env=env)
230 230 out, err = p.communicate()
231 231 return p.returncode, out, err
232 232
233 233 class hgcommand(object):
234 234 def __init__(self, cmd, env):
235 235 self.cmd = cmd
236 236 self.env = env
237 237
238 238 def run(self, args):
239 239 cmd = self.cmd + args
240 240 returncode, out, err = runcmd(cmd, self.env)
241 241 err = filterhgerr(err)
242 242 if err or returncode != 0:
243 243 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
244 244 printf(err, file=sys.stderr)
245 245 return ''
246 246 return out
247 247
248 248 def filterhgerr(err):
249 249 # If root is executing setup.py, but the repository is owned by
250 250 # another user (as in "sudo python setup.py install") we will get
251 251 # trust warnings since the .hg/hgrc file is untrusted. That is
252 252 # fine, we don't want to load it anyway. Python may warn about
253 253 # a missing __init__.py in mercurial/locale, we also ignore that.
254 254 err = [e for e in err.splitlines()
255 255 if (not e.startswith(b'not trusting file')
256 256 and not e.startswith(b'warning: Not importing')
257 257 and not e.startswith(b'obsolete feature not enabled')
258 258 and not e.startswith(b'*** failed to import extension')
259 259 and not e.startswith(b'devel-warn:'))]
260 260 return b'\n'.join(b' ' + e for e in err)
261 261
262 262 def findhg():
263 263 """Try to figure out how we should invoke hg for examining the local
264 264 repository contents.
265 265
266 266 Returns an hgcommand object."""
267 267 # By default, prefer the "hg" command in the user's path. This was
268 268 # presumably the hg command that the user used to create this repository.
269 269 #
270 270 # This repository may require extensions or other settings that would not
271 271 # be enabled by running the hg script directly from this local repository.
272 272 hgenv = os.environ.copy()
273 273 # Use HGPLAIN to disable hgrc settings that would change output formatting,
274 274 # and disable localization for the same reasons.
275 275 hgenv['HGPLAIN'] = '1'
276 276 hgenv['LANGUAGE'] = 'C'
277 277 hgcmd = ['hg']
278 278 # Run a simple "hg log" command just to see if using hg from the user's
279 279 # path works and can successfully interact with this repository.
280 280 check_cmd = ['log', '-r.', '-Ttest']
281 281 try:
282 282 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
283 283 except EnvironmentError:
284 284 retcode = -1
285 285 if retcode == 0 and not filterhgerr(err):
286 286 return hgcommand(hgcmd, hgenv)
287 287
288 288 # Fall back to trying the local hg installation.
289 289 hgenv = localhgenv()
290 290 hgcmd = [sys.executable, 'hg']
291 291 try:
292 292 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
293 293 except EnvironmentError:
294 294 retcode = -1
295 295 if retcode == 0 and not filterhgerr(err):
296 296 return hgcommand(hgcmd, hgenv)
297 297
298 298 raise SystemExit('Unable to find a working hg binary to extract the '
299 299 'version from the repository tags')
300 300
301 301 def localhgenv():
302 302 """Get an environment dictionary to use for invoking or importing
303 303 mercurial from the local repository."""
304 304 # Execute hg out of this directory with a custom environment which takes
305 305 # care to not use any hgrc files and do no localization.
306 306 env = {'HGMODULEPOLICY': 'py',
307 307 'HGRCPATH': '',
308 308 'LANGUAGE': 'C',
309 309 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
310 310 if 'LD_LIBRARY_PATH' in os.environ:
311 311 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
312 312 if 'SystemRoot' in os.environ:
313 313 # SystemRoot is required by Windows to load various DLLs. See:
314 314 # https://bugs.python.org/issue13524#msg148850
315 315 env['SystemRoot'] = os.environ['SystemRoot']
316 316 return env
317 317
318 318 version = ''
319 319
320 320 if os.path.isdir('.hg'):
321 321 hg = findhg()
322 322 cmd = ['log', '-r', '.', '--template', '{tags}\n']
323 323 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
324 324 hgid = sysstr(hg.run(['id', '-i'])).strip()
325 325 if not hgid:
326 326 # Bail out if hg is having problems interacting with this repository,
327 327 # rather than falling through and producing a bogus version number.
328 328 # Continuing with an invalid version number will break extensions
329 329 # that define minimumhgversion.
330 330 raise SystemExit('Unable to determine hg version from local repository')
331 331 if numerictags: # tag(s) found
332 332 version = numerictags[-1]
333 333 if hgid.endswith('+'): # propagate the dirty status to the tag
334 334 version += '+'
335 335 else: # no tag found
336 336 ltagcmd = ['parents', '--template', '{latesttag}']
337 337 ltag = sysstr(hg.run(ltagcmd))
338 338 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
339 339 changessince = len(hg.run(changessincecmd).splitlines())
340 340 version = '%s+%s-%s' % (ltag, changessince, hgid)
341 341 if version.endswith('+'):
342 342 version += time.strftime('%Y%m%d')
343 343 elif os.path.exists('.hg_archival.txt'):
344 344 kw = dict([[t.strip() for t in l.split(':', 1)]
345 345 for l in open('.hg_archival.txt')])
346 346 if 'tag' in kw:
347 347 version = kw['tag']
348 348 elif 'latesttag' in kw:
349 349 if 'changessincelatesttag' in kw:
350 350 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
351 351 else:
352 352 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
353 353 else:
354 354 version = kw.get('node', '')[:12]
355 355
356 356 if version:
357 357 versionb = version
358 358 if not isinstance(versionb, bytes):
359 359 versionb = versionb.encode('ascii')
360 360
361 361 write_if_changed('mercurial/__version__.py', b''.join([
362 362 b'# this file is autogenerated by setup.py\n'
363 363 b'version = "%s"\n' % versionb,
364 364 ]))
365 365
366 366 try:
367 367 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
368 368 os.environ['HGMODULEPOLICY'] = 'py'
369 369 from mercurial import __version__
370 370 version = __version__.version
371 371 except ImportError:
372 372 version = 'unknown'
373 373 finally:
374 374 if oldpolicy is None:
375 375 del os.environ['HGMODULEPOLICY']
376 376 else:
377 377 os.environ['HGMODULEPOLICY'] = oldpolicy
378 378
379 379 class hgbuild(build):
380 380 # Insert hgbuildmo first so that files in mercurial/locale/ are found
381 381 # when build_py is run next.
382 382 sub_commands = [('build_mo', None)] + build.sub_commands
383 383
384 384 class hgbuildmo(build):
385 385
386 386 description = "build translations (.mo files)"
387 387
388 388 def run(self):
389 389 if not find_executable('msgfmt'):
390 390 self.warn("could not find msgfmt executable, no translations "
391 391 "will be built")
392 392 return
393 393
394 394 podir = 'i18n'
395 395 if not os.path.isdir(podir):
396 396 self.warn("could not find %s/ directory" % podir)
397 397 return
398 398
399 399 join = os.path.join
400 400 for po in os.listdir(podir):
401 401 if not po.endswith('.po'):
402 402 continue
403 403 pofile = join(podir, po)
404 404 modir = join('locale', po[:-3], 'LC_MESSAGES')
405 405 mofile = join(modir, 'hg.mo')
406 406 mobuildfile = join('mercurial', mofile)
407 407 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
408 408 if sys.platform != 'sunos5':
409 409 # msgfmt on Solaris does not know about -c
410 410 cmd.append('-c')
411 411 self.mkpath(join('mercurial', modir))
412 412 self.make_file([pofile], mobuildfile, spawn, (cmd,))
413 413
414 414
415 415 class hgdist(Distribution):
416 416 pure = False
417 417 cffi = ispypy
418 418
419 419 global_options = Distribution.global_options + \
420 420 [('pure', None, "use pure (slow) Python "
421 421 "code instead of C extensions"),
422 422 ]
423 423
424 424 def has_ext_modules(self):
425 425 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
426 426 # too late for some cases
427 427 return not self.pure and Distribution.has_ext_modules(self)
428 428
429 429 # This is ugly as a one-liner. So use a variable.
430 430 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
431 431 buildextnegops['no-zstd'] = 'zstd'
432 432
433 433 class hgbuildext(build_ext):
434 434 user_options = build_ext.user_options + [
435 435 ('zstd', None, 'compile zstd bindings [default]'),
436 436 ('no-zstd', None, 'do not compile zstd bindings'),
437 437 ]
438 438
439 439 boolean_options = build_ext.boolean_options + ['zstd']
440 440 negative_opt = buildextnegops
441 441
442 442 def initialize_options(self):
443 443 self.zstd = True
444 444 return build_ext.initialize_options(self)
445 445
446 446 def build_extensions(self):
447 447 # Filter out zstd if disabled via argument.
448 448 if not self.zstd:
449 449 self.extensions = [e for e in self.extensions
450 450 if e.name != 'mercurial.zstd']
451 451
452 452 return build_ext.build_extensions(self)
453 453
454 454 def build_extension(self, ext):
455 455 try:
456 456 build_ext.build_extension(self, ext)
457 457 except CCompilerError:
458 458 if not getattr(ext, 'optional', False):
459 459 raise
460 460 log.warn("Failed to build optional extension '%s' (skipping)",
461 461 ext.name)
462 462
463 463 class hgbuildscripts(build_scripts):
464 464 def run(self):
465 465 if os.name != 'nt' or self.distribution.pure:
466 466 return build_scripts.run(self)
467 467
468 468 exebuilt = False
469 469 try:
470 470 self.run_command('build_hgexe')
471 471 exebuilt = True
472 472 except (DistutilsError, CCompilerError):
473 473 log.warn('failed to build optional hg.exe')
474 474
475 475 if exebuilt:
476 476 # Copying hg.exe to the scripts build directory ensures it is
477 477 # installed by the install_scripts command.
478 478 hgexecommand = self.get_finalized_command('build_hgexe')
479 479 dest = os.path.join(self.build_dir, 'hg.exe')
480 480 self.mkpath(self.build_dir)
481 481 self.copy_file(hgexecommand.hgexepath, dest)
482 482
483 483 # Remove hg.bat because it is redundant with hg.exe.
484 484 self.scripts.remove('contrib/win32/hg.bat')
485 485
486 486 return build_scripts.run(self)
487 487
488 488 class hgbuildpy(build_py):
489 489 def finalize_options(self):
490 490 build_py.finalize_options(self)
491 491
492 492 if self.distribution.pure:
493 493 self.distribution.ext_modules = []
494 494 elif self.distribution.cffi:
495 495 from mercurial.cffi import (
496 496 bdiffbuild,
497 497 mpatchbuild,
498 498 )
499 499 exts = [mpatchbuild.ffi.distutils_extension(),
500 500 bdiffbuild.ffi.distutils_extension()]
501 501 # cffi modules go here
502 502 if sys.platform == 'darwin':
503 503 from mercurial.cffi import osutilbuild
504 504 exts.append(osutilbuild.ffi.distutils_extension())
505 505 self.distribution.ext_modules = exts
506 506 else:
507 507 h = os.path.join(get_python_inc(), 'Python.h')
508 508 if not os.path.exists(h):
509 509 raise SystemExit('Python headers are required to build '
510 510 'Mercurial but weren\'t found in %s' % h)
511 511
512 512 def run(self):
513 513 basepath = os.path.join(self.build_lib, 'mercurial')
514 514 self.mkpath(basepath)
515 515
516 516 if self.distribution.pure:
517 517 modulepolicy = 'py'
518 518 elif self.build_lib == '.':
519 519 # in-place build should run without rebuilding C extensions
520 520 modulepolicy = 'allow'
521 521 else:
522 522 modulepolicy = 'c'
523 523
524 524 content = b''.join([
525 525 b'# this file is autogenerated by setup.py\n',
526 526 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
527 527 ])
528 528 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'),
529 529 content)
530 530
531 531 build_py.run(self)
532 532
533 533 class buildhgextindex(Command):
534 534 description = 'generate prebuilt index of hgext (for frozen package)'
535 535 user_options = []
536 536 _indexfilename = 'hgext/__index__.py'
537 537
538 538 def initialize_options(self):
539 539 pass
540 540
541 541 def finalize_options(self):
542 542 pass
543 543
544 544 def run(self):
545 545 if os.path.exists(self._indexfilename):
546 546 with open(self._indexfilename, 'w') as f:
547 547 f.write('# empty\n')
548 548
549 549 # here no extension enabled, disabled() lists up everything
550 550 code = ('import pprint; from mercurial import extensions; '
551 551 'pprint.pprint(extensions.disabled())')
552 552 returncode, out, err = runcmd([sys.executable, '-c', code],
553 553 localhgenv())
554 554 if err or returncode != 0:
555 555 raise DistutilsExecError(err)
556 556
557 557 with open(self._indexfilename, 'w') as f:
558 558 f.write('# this file is autogenerated by setup.py\n')
559 559 f.write('docs = ')
560 560 f.write(out)
561 561
562 562 class buildhgexe(build_ext):
563 563 description = 'compile hg.exe from mercurial/exewrapper.c'
564 564 user_options = build_ext.user_options + [
565 565 ('long-paths-support', None, 'enable support for long paths on '
566 566 'Windows (off by default and '
567 567 'experimental)'),
568 568 ]
569 569
570 570 LONG_PATHS_MANIFEST = """
571 571 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
572 572 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
573 573 <application>
574 574 <windowsSettings
575 575 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
576 576 <ws2:longPathAware>true</ws2:longPathAware>
577 577 </windowsSettings>
578 578 </application>
579 579 </assembly>"""
580 580
581 581 def initialize_options(self):
582 582 build_ext.initialize_options(self)
583 583 self.long_paths_support = False
584 584
585 585 def build_extensions(self):
586 586 if os.name != 'nt':
587 587 return
588 588 if isinstance(self.compiler, HackedMingw32CCompiler):
589 589 self.compiler.compiler_so = self.compiler.compiler # no -mdll
590 590 self.compiler.dll_libraries = [] # no -lmsrvc90
591 591
592 592 # Different Python installs can have different Python library
593 593 # names. e.g. the official CPython distribution uses pythonXY.dll
594 594 # and MinGW uses libpythonX.Y.dll.
595 595 _kernel32 = ctypes.windll.kernel32
596 596 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
597 597 ctypes.c_void_p,
598 598 ctypes.c_ulong]
599 599 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
600 600 size = 1000
601 601 buf = ctypes.create_string_buffer(size + 1)
602 602 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
603 603 size)
604 604
605 605 if filelen > 0 and filelen != size:
606 606 dllbasename = os.path.basename(buf.value)
607 607 if not dllbasename.lower().endswith('.dll'):
608 608 raise SystemExit('Python DLL does not end with .dll: %s' %
609 609 dllbasename)
610 610 pythonlib = dllbasename[:-4]
611 611 else:
612 612 log.warn('could not determine Python DLL filename; '
613 613 'assuming pythonXY')
614 614
615 615 hv = sys.hexversion
616 616 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
617 617
618 618 log.info('using %s as Python library name' % pythonlib)
619 619 with open('mercurial/hgpythonlib.h', 'wb') as f:
620 620 f.write('/* this file is autogenerated by setup.py */\n')
621 621 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
622 622 objects = self.compiler.compile(['mercurial/exewrapper.c'],
623 623 output_dir=self.build_temp)
624 624 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
625 625 self.hgtarget = os.path.join(dir, 'hg')
626 626 self.compiler.link_executable(objects, self.hgtarget,
627 627 libraries=[],
628 628 output_dir=self.build_temp)
629 629 if self.long_paths_support:
630 630 self.addlongpathsmanifest()
631 631
632 632 def addlongpathsmanifest(self):
633 633 """Add manifest pieces so that hg.exe understands long paths
634 634
635 635 This is an EXPERIMENTAL feature, use with care.
636 636 To enable long paths support, one needs to do two things:
637 637 - build Mercurial with --long-paths-support option
638 638 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
639 639 LongPathsEnabled to have value 1.
640 640
641 641 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
642 642 it happens because Mercurial uses mt.exe circa 2008, which is not
643 643 yet aware of long paths support in the manifest (I think so at least).
644 644 This does not stop mt.exe from embedding/merging the XML properly.
645 645
646 646 Why resource #1 should be used for .exe manifests? I don't know and
647 647 wasn't able to find an explanation for mortals. But it seems to work.
648 648 """
649 649 exefname = self.compiler.executable_filename(self.hgtarget)
650 650 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
651 651 os.close(fdauto)
652 652 with open(manfname, 'w') as f:
653 653 f.write(self.LONG_PATHS_MANIFEST)
654 654 log.info("long paths manifest is written to '%s'" % manfname)
655 655 inputresource = '-inputresource:%s;#1' % exefname
656 656 outputresource = '-outputresource:%s;#1' % exefname
657 657 log.info("running mt.exe to update hg.exe's manifest in-place")
658 658 # supplying both -manifest and -inputresource to mt.exe makes
659 659 # it merge the embedded and supplied manifests in the -outputresource
660 660 self.spawn(['mt.exe', '-nologo', '-manifest', manfname,
661 661 inputresource, outputresource])
662 662 log.info("done updating hg.exe's manifest")
663 663 os.remove(manfname)
664 664
665 665 @property
666 666 def hgexepath(self):
667 667 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
668 668 return os.path.join(self.build_temp, dir, 'hg.exe')
669 669
670 670 class hginstall(install):
671 671
672 672 user_options = install.user_options + [
673 673 ('old-and-unmanageable', None,
674 674 'noop, present for eggless setuptools compat'),
675 675 ('single-version-externally-managed', None,
676 676 'noop, present for eggless setuptools compat'),
677 677 ]
678 678
679 679 # Also helps setuptools not be sad while we refuse to create eggs.
680 680 single_version_externally_managed = True
681 681
682 682 def get_sub_commands(self):
683 683 # Screen out egg related commands to prevent egg generation. But allow
684 684 # mercurial.egg-info generation, since that is part of modern
685 685 # packaging.
686 686 excl = set(['bdist_egg'])
687 687 return filter(lambda x: x not in excl, install.get_sub_commands(self))
688 688
689 689 class hginstalllib(install_lib):
690 690 '''
691 691 This is a specialization of install_lib that replaces the copy_file used
692 692 there so that it supports setting the mode of files after copying them,
693 693 instead of just preserving the mode that the files originally had. If your
694 694 system has a umask of something like 027, preserving the permissions when
695 695 copying will lead to a broken install.
696 696
697 697 Note that just passing keep_permissions=False to copy_file would be
698 698 insufficient, as it might still be applying a umask.
699 699 '''
700 700
701 701 def run(self):
702 702 realcopyfile = file_util.copy_file
703 703 def copyfileandsetmode(*args, **kwargs):
704 704 src, dst = args[0], args[1]
705 705 dst, copied = realcopyfile(*args, **kwargs)
706 706 if copied:
707 707 st = os.stat(src)
708 708 # Persist executable bit (apply it to group and other if user
709 709 # has it)
710 710 if st[stat.ST_MODE] & stat.S_IXUSR:
711 711 setmode = int('0755', 8)
712 712 else:
713 713 setmode = int('0644', 8)
714 714 m = stat.S_IMODE(st[stat.ST_MODE])
715 715 m = (m & ~int('0777', 8)) | setmode
716 716 os.chmod(dst, m)
717 717 file_util.copy_file = copyfileandsetmode
718 718 try:
719 719 install_lib.run(self)
720 720 finally:
721 721 file_util.copy_file = realcopyfile
722 722
723 723 class hginstallscripts(install_scripts):
724 724 '''
725 725 This is a specialization of install_scripts that replaces the @LIBDIR@ with
726 726 the configured directory for modules. If possible, the path is made relative
727 727 to the directory for scripts.
728 728 '''
729 729
730 730 def initialize_options(self):
731 731 install_scripts.initialize_options(self)
732 732
733 733 self.install_lib = None
734 734
735 735 def finalize_options(self):
736 736 install_scripts.finalize_options(self)
737 737 self.set_undefined_options('install',
738 738 ('install_lib', 'install_lib'))
739 739
740 740 def run(self):
741 741 install_scripts.run(self)
742 742
743 743 # It only makes sense to replace @LIBDIR@ with the install path if
744 744 # the install path is known. For wheels, the logic below calculates
745 745 # the libdir to be "../..". This is because the internal layout of a
746 746 # wheel archive looks like:
747 747 #
748 748 # mercurial-3.6.1.data/scripts/hg
749 749 # mercurial/__init__.py
750 750 #
751 751 # When installing wheels, the subdirectories of the "<pkg>.data"
752 752 # directory are translated to system local paths and files therein
753 753 # are copied in place. The mercurial/* files are installed into the
754 754 # site-packages directory. However, the site-packages directory
755 755 # isn't known until wheel install time. This means we have no clue
756 756 # at wheel generation time what the installed site-packages directory
757 757 # will be. And, wheels don't appear to provide the ability to register
758 758 # custom code to run during wheel installation. This all means that
759 759 # we can't reliably set the libdir in wheels: the default behavior
760 760 # of looking in sys.path must do.
761 761
762 762 if (os.path.splitdrive(self.install_dir)[0] !=
763 763 os.path.splitdrive(self.install_lib)[0]):
764 764 # can't make relative paths from one drive to another, so use an
765 765 # absolute path instead
766 766 libdir = self.install_lib
767 767 else:
768 768 common = os.path.commonprefix((self.install_dir, self.install_lib))
769 769 rest = self.install_dir[len(common):]
770 770 uplevel = len([n for n in os.path.split(rest) if n])
771 771
772 772 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
773 773
774 774 for outfile in self.outfiles:
775 775 with open(outfile, 'rb') as fp:
776 776 data = fp.read()
777 777
778 778 # skip binary files
779 779 if b'\0' in data:
780 780 continue
781 781
782 782 # During local installs, the shebang will be rewritten to the final
783 783 # install path. During wheel packaging, the shebang has a special
784 784 # value.
785 785 if data.startswith(b'#!python'):
786 786 log.info('not rewriting @LIBDIR@ in %s because install path '
787 787 'not known' % outfile)
788 788 continue
789 789
790 790 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
791 791 with open(outfile, 'wb') as fp:
792 792 fp.write(data)
793 793
794 794 cmdclass = {'build': hgbuild,
795 795 'build_mo': hgbuildmo,
796 796 'build_ext': hgbuildext,
797 797 'build_py': hgbuildpy,
798 798 'build_scripts': hgbuildscripts,
799 799 'build_hgextindex': buildhgextindex,
800 800 'install': hginstall,
801 801 'install_lib': hginstalllib,
802 802 'install_scripts': hginstallscripts,
803 803 'build_hgexe': buildhgexe,
804 804 }
805 805
806 806 packages = ['mercurial',
807 807 'mercurial.cext',
808 808 'mercurial.cffi',
809 809 'mercurial.hgweb',
810 810 'mercurial.pure',
811 811 'mercurial.thirdparty',
812 812 'mercurial.thirdparty.attr',
813 'mercurial.thirdparty.cbor',
814 'mercurial.thirdparty.cbor.cbor2',
813 815 'mercurial.utils',
814 816 'hgext', 'hgext.convert', 'hgext.fsmonitor',
815 817 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
816 818 'hgext.largefiles', 'hgext.lfs', 'hgext.narrow',
817 819 'hgext.zeroconf', 'hgext3rd',
818 820 'hgdemandimport']
819 821
820 822 common_depends = ['mercurial/bitmanipulation.h',
821 823 'mercurial/compat.h',
822 824 'mercurial/cext/util.h']
823 825 common_include_dirs = ['mercurial']
824 826
825 827 osutil_cflags = []
826 828 osutil_ldflags = []
827 829
828 830 # platform specific macros
829 831 for plat, func in [('bsd', 'setproctitle')]:
830 832 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
831 833 osutil_cflags.append('-DHAVE_%s' % func.upper())
832 834
833 835 for plat, macro, code in [
834 836 ('bsd|darwin', 'BSD_STATFS', '''
835 837 #include <sys/param.h>
836 838 #include <sys/mount.h>
837 839 int main() { struct statfs s; return sizeof(s.f_fstypename); }
838 840 '''),
839 841 ('linux', 'LINUX_STATFS', '''
840 842 #include <linux/magic.h>
841 843 #include <sys/vfs.h>
842 844 int main() { struct statfs s; return sizeof(s.f_type); }
843 845 '''),
844 846 ]:
845 847 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
846 848 osutil_cflags.append('-DHAVE_%s' % macro)
847 849
848 850 if sys.platform == 'darwin':
849 851 osutil_ldflags += ['-framework', 'ApplicationServices']
850 852
851 853 xdiff_srcs = [
852 854 'mercurial/thirdparty/xdiff/xdiffi.c',
853 855 'mercurial/thirdparty/xdiff/xprepare.c',
854 856 'mercurial/thirdparty/xdiff/xutils.c',
855 857 ]
856 858
857 859 xdiff_headers = [
858 860 'mercurial/thirdparty/xdiff/xdiff.h',
859 861 'mercurial/thirdparty/xdiff/xdiffi.h',
860 862 'mercurial/thirdparty/xdiff/xinclude.h',
861 863 'mercurial/thirdparty/xdiff/xmacros.h',
862 864 'mercurial/thirdparty/xdiff/xprepare.h',
863 865 'mercurial/thirdparty/xdiff/xtypes.h',
864 866 'mercurial/thirdparty/xdiff/xutils.h',
865 867 ]
866 868
867 869 extmodules = [
868 870 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
869 871 include_dirs=common_include_dirs,
870 872 depends=common_depends),
871 873 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
872 874 'mercurial/cext/bdiff.c'] + xdiff_srcs,
873 875 include_dirs=common_include_dirs,
874 876 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers),
875 877 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
876 878 include_dirs=common_include_dirs,
877 879 depends=common_depends),
878 880 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
879 881 'mercurial/cext/mpatch.c'],
880 882 include_dirs=common_include_dirs,
881 883 depends=common_depends),
882 884 Extension('mercurial.cext.parsers', ['mercurial/cext/charencode.c',
883 885 'mercurial/cext/dirs.c',
884 886 'mercurial/cext/manifest.c',
885 887 'mercurial/cext/parsers.c',
886 888 'mercurial/cext/pathencode.c',
887 889 'mercurial/cext/revlog.c'],
888 890 include_dirs=common_include_dirs,
889 891 depends=common_depends + ['mercurial/cext/charencode.h']),
890 892 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
891 893 include_dirs=common_include_dirs,
892 894 extra_compile_args=osutil_cflags,
893 895 extra_link_args=osutil_ldflags,
894 896 depends=common_depends),
895 897 Extension('hgext.fsmonitor.pywatchman.bser',
896 898 ['hgext/fsmonitor/pywatchman/bser.c']),
897 899 ]
898 900
899 901 sys.path.insert(0, 'contrib/python-zstandard')
900 902 import setup_zstd
901 903 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
902 904
903 905 try:
904 906 from distutils import cygwinccompiler
905 907
906 908 # the -mno-cygwin option has been deprecated for years
907 909 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
908 910
909 911 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
910 912 def __init__(self, *args, **kwargs):
911 913 mingw32compilerclass.__init__(self, *args, **kwargs)
912 914 for i in 'compiler compiler_so linker_exe linker_so'.split():
913 915 try:
914 916 getattr(self, i).remove('-mno-cygwin')
915 917 except ValueError:
916 918 pass
917 919
918 920 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
919 921 except ImportError:
920 922 # the cygwinccompiler package is not available on some Python
921 923 # distributions like the ones from the optware project for Synology
922 924 # DiskStation boxes
923 925 class HackedMingw32CCompiler(object):
924 926 pass
925 927
926 928 if os.name == 'nt':
927 929 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
928 930 # extra_link_args to distutils.extensions.Extension() doesn't have any
929 931 # effect.
930 932 from distutils import msvccompiler
931 933
932 934 msvccompilerclass = msvccompiler.MSVCCompiler
933 935
934 936 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
935 937 def initialize(self):
936 938 msvccompilerclass.initialize(self)
937 939 # "warning LNK4197: export 'func' specified multiple times"
938 940 self.ldflags_shared.append('/ignore:4197')
939 941 self.ldflags_shared_debug.append('/ignore:4197')
940 942
941 943 msvccompiler.MSVCCompiler = HackedMSVCCompiler
942 944
943 945 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
944 946 'help/*.txt',
945 947 'help/internals/*.txt',
946 948 'default.d/*.rc',
947 949 'dummycert.pem']}
948 950
949 951 def ordinarypath(p):
950 952 return p and p[0] != '.' and p[-1] != '~'
951 953
952 954 for root in ('templates',):
953 955 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
954 956 curdir = curdir.split(os.sep, 1)[1]
955 957 dirs[:] = filter(ordinarypath, dirs)
956 958 for f in filter(ordinarypath, files):
957 959 f = os.path.join(curdir, f)
958 960 packagedata['mercurial'].append(f)
959 961
960 962 datafiles = []
961 963
962 964 # distutils expects version to be str/unicode. Converting it to
963 965 # unicode on Python 2 still works because it won't contain any
964 966 # non-ascii bytes and will be implicitly converted back to bytes
965 967 # when operated on.
966 968 assert isinstance(version, bytes)
967 969 setupversion = version.decode('ascii')
968 970
969 971 extra = {}
970 972
971 973 if issetuptools:
972 974 extra['python_requires'] = supportedpy
973 975 if py2exeloaded:
974 976 extra['console'] = [
975 977 {'script':'hg',
976 978 'copyright':'Copyright (C) 2005-2018 Matt Mackall and others',
977 979 'product_version':version}]
978 980 # sub command of 'build' because 'py2exe' does not handle sub_commands
979 981 build.sub_commands.insert(0, ('build_hgextindex', None))
980 982 # put dlls in sub directory so that they won't pollute PATH
981 983 extra['zipfile'] = 'lib/library.zip'
982 984
983 985 if os.name == 'nt':
984 986 # Windows binary file versions for exe/dll files must have the
985 987 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
986 988 setupversion = version.split('+', 1)[0]
987 989
988 990 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
989 991 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
990 992 if version:
991 993 version = version[0]
992 994 if sys.version_info[0] == 3:
993 995 version = version.decode('utf-8')
994 996 xcode4 = (version.startswith('Xcode') and
995 997 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
996 998 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
997 999 else:
998 1000 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
999 1001 # installed, but instead with only command-line tools. Assume
1000 1002 # that only happens on >= Lion, thus no PPC support.
1001 1003 xcode4 = True
1002 1004 xcode51 = False
1003 1005
1004 1006 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
1005 1007 # distutils.sysconfig
1006 1008 if xcode4:
1007 1009 os.environ['ARCHFLAGS'] = ''
1008 1010
1009 1011 # XCode 5.1 changes clang such that it now fails to compile if the
1010 1012 # -mno-fused-madd flag is passed, but the version of Python shipped with
1011 1013 # OS X 10.9 Mavericks includes this flag. This causes problems in all
1012 1014 # C extension modules, and a bug has been filed upstream at
1013 1015 # http://bugs.python.org/issue21244. We also need to patch this here
1014 1016 # so Mercurial can continue to compile in the meantime.
1015 1017 if xcode51:
1016 1018 cflags = get_config_var('CFLAGS')
1017 1019 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
1018 1020 os.environ['CFLAGS'] = (
1019 1021 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
1020 1022
1021 1023 setup(name='mercurial',
1022 1024 version=setupversion,
1023 1025 author='Matt Mackall and many others',
1024 1026 author_email='mercurial@mercurial-scm.org',
1025 1027 url='https://mercurial-scm.org/',
1026 1028 download_url='https://mercurial-scm.org/release/',
1027 1029 description=('Fast scalable distributed SCM (revision control, version '
1028 1030 'control) system'),
1029 1031 long_description=('Mercurial is a distributed SCM tool written in Python.'
1030 1032 ' It is used by a number of large projects that require'
1031 1033 ' fast, reliable distributed revision control, such as '
1032 1034 'Mozilla.'),
1033 1035 license='GNU GPLv2 or any later version',
1034 1036 classifiers=[
1035 1037 'Development Status :: 6 - Mature',
1036 1038 'Environment :: Console',
1037 1039 'Intended Audience :: Developers',
1038 1040 'Intended Audience :: System Administrators',
1039 1041 'License :: OSI Approved :: GNU General Public License (GPL)',
1040 1042 'Natural Language :: Danish',
1041 1043 'Natural Language :: English',
1042 1044 'Natural Language :: German',
1043 1045 'Natural Language :: Italian',
1044 1046 'Natural Language :: Japanese',
1045 1047 'Natural Language :: Portuguese (Brazilian)',
1046 1048 'Operating System :: Microsoft :: Windows',
1047 1049 'Operating System :: OS Independent',
1048 1050 'Operating System :: POSIX',
1049 1051 'Programming Language :: C',
1050 1052 'Programming Language :: Python',
1051 1053 'Topic :: Software Development :: Version Control',
1052 1054 ],
1053 1055 scripts=scripts,
1054 1056 packages=packages,
1055 1057 ext_modules=extmodules,
1056 1058 data_files=datafiles,
1057 1059 package_data=packagedata,
1058 1060 cmdclass=cmdclass,
1059 1061 distclass=hgdist,
1060 1062 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email',
1061 1063 # implicitly imported per module policy
1062 1064 # (cffi wouldn't be used as a frozen exe)
1063 1065 'mercurial.cext',
1064 1066 #'mercurial.cffi',
1065 1067 'mercurial.pure']},
1066 1068 'bdist_mpkg': {'zipdist': False,
1067 1069 'license': 'COPYING',
1068 1070 'readme': 'contrib/macosx/Readme.html',
1069 1071 'welcome': 'contrib/macosx/Welcome.html',
1070 1072 },
1071 1073 },
1072 1074 **extra)
General Comments 0
You need to be logged in to leave comments. Login now