##// END OF EJS Templates
policy: try and always have a bytes for module policy...
Augie Fackler -
r31308:62939e01 default
parent child Browse files
Show More
@@ -1,45 +1,45
1 1 # policy.py - module policy logic for Mercurial.
2 2 #
3 3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import os
11 11 import sys
12 12
13 13 # Rules for how modules can be loaded. Values are:
14 14 #
15 15 # c - require C extensions
16 16 # allow - allow pure Python implementation when C loading fails
17 17 # cffi - required cffi versions (implemented within pure module)
18 18 # cffi-allow - allow pure Python implementation if cffi version is missing
19 19 # py - only load pure Python modules
20 20 #
21 21 # By default, require the C extensions for performance reasons.
22 22 policy = 'c'
23 23 policynoc = ('cffi', 'cffi-allow', 'py')
24 24 policynocffi = ('c', 'py')
25 25
26 26 try:
27 27 from . import __modulepolicy__
28 28 policy = __modulepolicy__.modulepolicy
29 29 except ImportError:
30 30 pass
31 31
32 32 # PyPy doesn't load C extensions.
33 33 #
34 34 # The canonical way to do this is to test platform.python_implementation().
35 35 # But we don't import platform and don't bloat for it here.
36 36 if '__pypy__' in sys.builtin_module_names:
37 37 policy = 'cffi'
38 38
39 39 # Our C extensions aren't yet compatible with Python 3. So use pure Python
40 40 # on Python 3 for now.
41 41 if sys.version_info[0] >= 3:
42 policy = 'py'
42 policy = b'py'
43 43
44 44 # Environment variable can always force settings.
45 45 policy = os.environ.get('HGMODULEPOLICY', policy)
@@ -1,761 +1,761
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, 6, 0, 'final'):
9 9 raise SystemExit("Mercurial requires Python 2.6 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_lib import install_lib
81 81 from distutils.command.install_scripts import install_scripts
82 82 from distutils.spawn import spawn, find_executable
83 83 from distutils import file_util
84 84 from distutils.errors import (
85 85 CCompilerError,
86 86 DistutilsError,
87 87 DistutilsExecError,
88 88 )
89 89 from distutils.sysconfig import get_python_inc, get_config_var
90 90 from distutils.version import StrictVersion
91 91
92 92 scripts = ['hg']
93 93 if os.name == 'nt':
94 94 # We remove hg.bat if we are able to build hg.exe.
95 95 scripts.append('contrib/win32/hg.bat')
96 96
97 97 # simplified version of distutils.ccompiler.CCompiler.has_function
98 98 # that actually removes its temporary files.
99 99 def hasfunction(cc, funcname):
100 100 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
101 101 devnull = oldstderr = None
102 102 try:
103 103 fname = os.path.join(tmpdir, 'funcname.c')
104 104 f = open(fname, 'w')
105 105 f.write('int main(void) {\n')
106 106 f.write(' %s();\n' % funcname)
107 107 f.write('}\n')
108 108 f.close()
109 109 # Redirect stderr to /dev/null to hide any error messages
110 110 # from the compiler.
111 111 # This will have to be changed if we ever have to check
112 112 # for a function on Windows.
113 113 devnull = open('/dev/null', 'w')
114 114 oldstderr = os.dup(sys.stderr.fileno())
115 115 os.dup2(devnull.fileno(), sys.stderr.fileno())
116 116 objects = cc.compile([fname], output_dir=tmpdir)
117 117 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
118 118 return True
119 119 except Exception:
120 120 return False
121 121 finally:
122 122 if oldstderr is not None:
123 123 os.dup2(oldstderr, sys.stderr.fileno())
124 124 if devnull is not None:
125 125 devnull.close()
126 126 shutil.rmtree(tmpdir)
127 127
128 128 # py2exe needs to be installed to work
129 129 try:
130 130 import py2exe
131 131 py2exe.Distribution # silence unused import warning
132 132 py2exeloaded = True
133 133 # import py2exe's patched Distribution class
134 134 from distutils.core import Distribution
135 135 except ImportError:
136 136 py2exeloaded = False
137 137
138 138 def runcmd(cmd, env):
139 139 if (sys.platform == 'plan9'
140 140 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
141 141 # subprocess kludge to work around issues in half-baked Python
142 142 # ports, notably bichued/python:
143 143 _, out, err = os.popen3(cmd)
144 144 return str(out), str(err)
145 145 else:
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 # Copy SystemRoot into the custom environment for Python 2.6
180 180 # under Windows. Otherwise, the subprocess will fail with
181 181 # error 0xc0150004. See: http://bugs.python.org/issue3440
182 182 env['SystemRoot'] = os.environ['SystemRoot']
183 183
184 184 if os.path.isdir('.hg'):
185 185 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
186 186 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
187 187 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
188 188 if numerictags: # tag(s) found
189 189 version = numerictags[-1]
190 190 if hgid.endswith('+'): # propagate the dirty status to the tag
191 191 version += '+'
192 192 else: # no tag found
193 193 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
194 194 '{latesttag}']
195 195 ltag = runhg(ltagcmd, env)
196 196 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
197 197 "only(.,'%s')" % ltag]
198 198 changessince = len(runhg(changessincecmd, env).splitlines())
199 199 version = '%s+%s-%s' % (ltag, changessince, hgid)
200 200 if version.endswith('+'):
201 201 version += time.strftime('%Y%m%d')
202 202 elif os.path.exists('.hg_archival.txt'):
203 203 kw = dict([[t.strip() for t in l.split(':', 1)]
204 204 for l in open('.hg_archival.txt')])
205 205 if 'tag' in kw:
206 206 version = kw['tag']
207 207 elif 'latesttag' in kw:
208 208 if 'changessincelatesttag' in kw:
209 209 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
210 210 else:
211 211 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
212 212 else:
213 213 version = kw.get('node', '')[:12]
214 214
215 215 if version:
216 216 with open("mercurial/__version__.py", "w") as f:
217 217 f.write('# this file is autogenerated by setup.py\n')
218 218 f.write('version = "%s"\n' % version)
219 219
220 220 try:
221 221 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
222 222 os.environ['HGMODULEPOLICY'] = 'py'
223 223 from mercurial import __version__
224 224 version = __version__.version
225 225 except ImportError:
226 226 version = 'unknown'
227 227 finally:
228 228 if oldpolicy is None:
229 229 del os.environ['HGMODULEPOLICY']
230 230 else:
231 231 os.environ['HGMODULEPOLICY'] = oldpolicy
232 232
233 233 class hgbuild(build):
234 234 # Insert hgbuildmo first so that files in mercurial/locale/ are found
235 235 # when build_py is run next.
236 236 sub_commands = [('build_mo', None)] + build.sub_commands
237 237
238 238 class hgbuildmo(build):
239 239
240 240 description = "build translations (.mo files)"
241 241
242 242 def run(self):
243 243 if not find_executable('msgfmt'):
244 244 self.warn("could not find msgfmt executable, no translations "
245 245 "will be built")
246 246 return
247 247
248 248 podir = 'i18n'
249 249 if not os.path.isdir(podir):
250 250 self.warn("could not find %s/ directory" % podir)
251 251 return
252 252
253 253 join = os.path.join
254 254 for po in os.listdir(podir):
255 255 if not po.endswith('.po'):
256 256 continue
257 257 pofile = join(podir, po)
258 258 modir = join('locale', po[:-3], 'LC_MESSAGES')
259 259 mofile = join(modir, 'hg.mo')
260 260 mobuildfile = join('mercurial', mofile)
261 261 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
262 262 if sys.platform != 'sunos5':
263 263 # msgfmt on Solaris does not know about -c
264 264 cmd.append('-c')
265 265 self.mkpath(join('mercurial', modir))
266 266 self.make_file([pofile], mobuildfile, spawn, (cmd,))
267 267
268 268
269 269 class hgdist(Distribution):
270 270 pure = False
271 271 cffi = ispypy
272 272
273 273 global_options = Distribution.global_options + \
274 274 [('pure', None, "use pure (slow) Python "
275 275 "code instead of C extensions"),
276 276 ]
277 277
278 278 def has_ext_modules(self):
279 279 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
280 280 # too late for some cases
281 281 return not self.pure and Distribution.has_ext_modules(self)
282 282
283 283 # This is ugly as a one-liner. So use a variable.
284 284 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
285 285 buildextnegops['no-zstd'] = 'zstd'
286 286
287 287 class hgbuildext(build_ext):
288 288 user_options = build_ext.user_options + [
289 289 ('zstd', None, 'compile zstd bindings [default]'),
290 290 ('no-zstd', None, 'do not compile zstd bindings'),
291 291 ]
292 292
293 293 boolean_options = build_ext.boolean_options + ['zstd']
294 294 negative_opt = buildextnegops
295 295
296 296 def initialize_options(self):
297 297 self.zstd = True
298 298 return build_ext.initialize_options(self)
299 299
300 300 def build_extensions(self):
301 301 # Filter out zstd if disabled via argument.
302 302 if not self.zstd:
303 303 self.extensions = [e for e in self.extensions
304 304 if e.name != 'mercurial.zstd']
305 305
306 306 return build_ext.build_extensions(self)
307 307
308 308 def build_extension(self, ext):
309 309 try:
310 310 build_ext.build_extension(self, ext)
311 311 except CCompilerError:
312 312 if not getattr(ext, 'optional', False):
313 313 raise
314 314 log.warn("Failed to build optional extension '%s' (skipping)",
315 315 ext.name)
316 316
317 317 class hgbuildscripts(build_scripts):
318 318 def run(self):
319 319 if os.name != 'nt' or self.distribution.pure:
320 320 return build_scripts.run(self)
321 321
322 322 exebuilt = False
323 323 try:
324 324 self.run_command('build_hgexe')
325 325 exebuilt = True
326 326 except (DistutilsError, CCompilerError):
327 327 log.warn('failed to build optional hg.exe')
328 328
329 329 if exebuilt:
330 330 # Copying hg.exe to the scripts build directory ensures it is
331 331 # installed by the install_scripts command.
332 332 hgexecommand = self.get_finalized_command('build_hgexe')
333 333 dest = os.path.join(self.build_dir, 'hg.exe')
334 334 self.mkpath(self.build_dir)
335 335 self.copy_file(hgexecommand.hgexepath, dest)
336 336
337 337 # Remove hg.bat because it is redundant with hg.exe.
338 338 self.scripts.remove('contrib/win32/hg.bat')
339 339
340 340 return build_scripts.run(self)
341 341
342 342 class hgbuildpy(build_py):
343 343 def finalize_options(self):
344 344 build_py.finalize_options(self)
345 345
346 346 if self.distribution.pure:
347 347 self.distribution.ext_modules = []
348 348 elif self.distribution.cffi:
349 349 from mercurial.cffi import (
350 350 bdiff,
351 351 mpatch,
352 352 )
353 353 exts = [mpatch.ffi.distutils_extension(),
354 354 bdiff.ffi.distutils_extension()]
355 355 # cffi modules go here
356 356 if sys.platform == 'darwin':
357 357 from mercurial.cffi import osutil
358 358 exts.append(osutil.ffi.distutils_extension())
359 359 self.distribution.ext_modules = exts
360 360 else:
361 361 h = os.path.join(get_python_inc(), 'Python.h')
362 362 if not os.path.exists(h):
363 363 raise SystemExit('Python headers are required to build '
364 364 'Mercurial but weren\'t found in %s' % h)
365 365
366 366 def run(self):
367 367 if self.distribution.pure:
368 368 modulepolicy = 'py'
369 369 else:
370 370 modulepolicy = 'c'
371 371 with open("mercurial/__modulepolicy__.py", "w") as f:
372 372 f.write('# this file is autogenerated by setup.py\n')
373 f.write('modulepolicy = "%s"\n' % modulepolicy)
373 f.write('modulepolicy = b"%s"\n' % modulepolicy)
374 374
375 375 build_py.run(self)
376 376
377 377 class buildhgextindex(Command):
378 378 description = 'generate prebuilt index of hgext (for frozen package)'
379 379 user_options = []
380 380 _indexfilename = 'hgext/__index__.py'
381 381
382 382 def initialize_options(self):
383 383 pass
384 384
385 385 def finalize_options(self):
386 386 pass
387 387
388 388 def run(self):
389 389 if os.path.exists(self._indexfilename):
390 390 with open(self._indexfilename, 'w') as f:
391 391 f.write('# empty\n')
392 392
393 393 # here no extension enabled, disabled() lists up everything
394 394 code = ('import pprint; from mercurial import extensions; '
395 395 'pprint.pprint(extensions.disabled())')
396 396 out, err = runcmd([sys.executable, '-c', code], env)
397 397 if err:
398 398 raise DistutilsExecError(err)
399 399
400 400 with open(self._indexfilename, 'w') as f:
401 401 f.write('# this file is autogenerated by setup.py\n')
402 402 f.write('docs = ')
403 403 f.write(out)
404 404
405 405 class buildhgexe(build_ext):
406 406 description = 'compile hg.exe from mercurial/exewrapper.c'
407 407
408 408 def build_extensions(self):
409 409 if os.name != 'nt':
410 410 return
411 411 if isinstance(self.compiler, HackedMingw32CCompiler):
412 412 self.compiler.compiler_so = self.compiler.compiler # no -mdll
413 413 self.compiler.dll_libraries = [] # no -lmsrvc90
414 414
415 415 # Different Python installs can have different Python library
416 416 # names. e.g. the official CPython distribution uses pythonXY.dll
417 417 # and MinGW uses libpythonX.Y.dll.
418 418 _kernel32 = ctypes.windll.kernel32
419 419 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
420 420 ctypes.c_void_p,
421 421 ctypes.c_ulong]
422 422 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
423 423 size = 1000
424 424 buf = ctypes.create_string_buffer(size + 1)
425 425 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
426 426 size)
427 427
428 428 if filelen > 0 and filelen != size:
429 429 dllbasename = os.path.basename(buf.value)
430 430 if not dllbasename.lower().endswith('.dll'):
431 431 raise SystemExit('Python DLL does not end with .dll: %s' %
432 432 dllbasename)
433 433 pythonlib = dllbasename[:-4]
434 434 else:
435 435 log.warn('could not determine Python DLL filename; '
436 436 'assuming pythonXY')
437 437
438 438 hv = sys.hexversion
439 439 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
440 440
441 441 log.info('using %s as Python library name' % pythonlib)
442 442 with open('mercurial/hgpythonlib.h', 'wb') as f:
443 443 f.write('/* this file is autogenerated by setup.py */\n')
444 444 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
445 445 objects = self.compiler.compile(['mercurial/exewrapper.c'],
446 446 output_dir=self.build_temp)
447 447 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
448 448 target = os.path.join(dir, 'hg')
449 449 self.compiler.link_executable(objects, target,
450 450 libraries=[],
451 451 output_dir=self.build_temp)
452 452
453 453 @property
454 454 def hgexepath(self):
455 455 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
456 456 return os.path.join(self.build_temp, dir, 'hg.exe')
457 457
458 458 class hginstalllib(install_lib):
459 459 '''
460 460 This is a specialization of install_lib that replaces the copy_file used
461 461 there so that it supports setting the mode of files after copying them,
462 462 instead of just preserving the mode that the files originally had. If your
463 463 system has a umask of something like 027, preserving the permissions when
464 464 copying will lead to a broken install.
465 465
466 466 Note that just passing keep_permissions=False to copy_file would be
467 467 insufficient, as it might still be applying a umask.
468 468 '''
469 469
470 470 def run(self):
471 471 realcopyfile = file_util.copy_file
472 472 def copyfileandsetmode(*args, **kwargs):
473 473 src, dst = args[0], args[1]
474 474 dst, copied = realcopyfile(*args, **kwargs)
475 475 if copied:
476 476 st = os.stat(src)
477 477 # Persist executable bit (apply it to group and other if user
478 478 # has it)
479 479 if st[stat.ST_MODE] & stat.S_IXUSR:
480 480 setmode = int('0755', 8)
481 481 else:
482 482 setmode = int('0644', 8)
483 483 m = stat.S_IMODE(st[stat.ST_MODE])
484 484 m = (m & ~int('0777', 8)) | setmode
485 485 os.chmod(dst, m)
486 486 file_util.copy_file = copyfileandsetmode
487 487 try:
488 488 install_lib.run(self)
489 489 finally:
490 490 file_util.copy_file = realcopyfile
491 491
492 492 class hginstallscripts(install_scripts):
493 493 '''
494 494 This is a specialization of install_scripts that replaces the @LIBDIR@ with
495 495 the configured directory for modules. If possible, the path is made relative
496 496 to the directory for scripts.
497 497 '''
498 498
499 499 def initialize_options(self):
500 500 install_scripts.initialize_options(self)
501 501
502 502 self.install_lib = None
503 503
504 504 def finalize_options(self):
505 505 install_scripts.finalize_options(self)
506 506 self.set_undefined_options('install',
507 507 ('install_lib', 'install_lib'))
508 508
509 509 def run(self):
510 510 install_scripts.run(self)
511 511
512 512 # It only makes sense to replace @LIBDIR@ with the install path if
513 513 # the install path is known. For wheels, the logic below calculates
514 514 # the libdir to be "../..". This is because the internal layout of a
515 515 # wheel archive looks like:
516 516 #
517 517 # mercurial-3.6.1.data/scripts/hg
518 518 # mercurial/__init__.py
519 519 #
520 520 # When installing wheels, the subdirectories of the "<pkg>.data"
521 521 # directory are translated to system local paths and files therein
522 522 # are copied in place. The mercurial/* files are installed into the
523 523 # site-packages directory. However, the site-packages directory
524 524 # isn't known until wheel install time. This means we have no clue
525 525 # at wheel generation time what the installed site-packages directory
526 526 # will be. And, wheels don't appear to provide the ability to register
527 527 # custom code to run during wheel installation. This all means that
528 528 # we can't reliably set the libdir in wheels: the default behavior
529 529 # of looking in sys.path must do.
530 530
531 531 if (os.path.splitdrive(self.install_dir)[0] !=
532 532 os.path.splitdrive(self.install_lib)[0]):
533 533 # can't make relative paths from one drive to another, so use an
534 534 # absolute path instead
535 535 libdir = self.install_lib
536 536 else:
537 537 common = os.path.commonprefix((self.install_dir, self.install_lib))
538 538 rest = self.install_dir[len(common):]
539 539 uplevel = len([n for n in os.path.split(rest) if n])
540 540
541 541 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
542 542
543 543 for outfile in self.outfiles:
544 544 with open(outfile, 'rb') as fp:
545 545 data = fp.read()
546 546
547 547 # skip binary files
548 548 if b'\0' in data:
549 549 continue
550 550
551 551 # During local installs, the shebang will be rewritten to the final
552 552 # install path. During wheel packaging, the shebang has a special
553 553 # value.
554 554 if data.startswith(b'#!python'):
555 555 log.info('not rewriting @LIBDIR@ in %s because install path '
556 556 'not known' % outfile)
557 557 continue
558 558
559 559 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
560 560 with open(outfile, 'wb') as fp:
561 561 fp.write(data)
562 562
563 563 cmdclass = {'build': hgbuild,
564 564 'build_mo': hgbuildmo,
565 565 'build_ext': hgbuildext,
566 566 'build_py': hgbuildpy,
567 567 'build_scripts': hgbuildscripts,
568 568 'build_hgextindex': buildhgextindex,
569 569 'install_lib': hginstalllib,
570 570 'install_scripts': hginstallscripts,
571 571 'build_hgexe': buildhgexe,
572 572 }
573 573
574 574 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
575 575 'mercurial.pure',
576 576 'hgext', 'hgext.convert', 'hgext.fsmonitor',
577 577 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
578 578 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
579 579
580 580 common_depends = ['mercurial/bitmanipulation.h',
581 581 'mercurial/compat.h',
582 582 'mercurial/util.h']
583 583
584 584 osutil_cflags = []
585 585 osutil_ldflags = []
586 586
587 587 # platform specific macros: HAVE_SETPROCTITLE
588 588 for plat, func in [(re.compile('freebsd'), 'setproctitle')]:
589 589 if plat.search(sys.platform) and hasfunction(new_compiler(), func):
590 590 osutil_cflags.append('-DHAVE_%s' % func.upper())
591 591
592 592 if sys.platform == 'darwin':
593 593 osutil_ldflags += ['-framework', 'ApplicationServices']
594 594
595 595 extmodules = [
596 596 Extension('mercurial.base85', ['mercurial/base85.c'],
597 597 depends=common_depends),
598 598 Extension('mercurial.bdiff', ['mercurial/bdiff.c',
599 599 'mercurial/bdiff_module.c'],
600 600 depends=common_depends + ['mercurial/bdiff.h']),
601 601 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
602 602 depends=common_depends),
603 603 Extension('mercurial.mpatch', ['mercurial/mpatch.c',
604 604 'mercurial/mpatch_module.c'],
605 605 depends=common_depends),
606 606 Extension('mercurial.parsers', ['mercurial/dirs.c',
607 607 'mercurial/manifest.c',
608 608 'mercurial/parsers.c',
609 609 'mercurial/pathencode.c'],
610 610 depends=common_depends),
611 611 Extension('mercurial.osutil', ['mercurial/osutil.c'],
612 612 extra_compile_args=osutil_cflags,
613 613 extra_link_args=osutil_ldflags,
614 614 depends=common_depends),
615 615 Extension('hgext.fsmonitor.pywatchman.bser',
616 616 ['hgext/fsmonitor/pywatchman/bser.c']),
617 617 ]
618 618
619 619 sys.path.insert(0, 'contrib/python-zstandard')
620 620 import setup_zstd
621 621 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
622 622
623 623 try:
624 624 from distutils import cygwinccompiler
625 625
626 626 # the -mno-cygwin option has been deprecated for years
627 627 compiler = cygwinccompiler.Mingw32CCompiler
628 628
629 629 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
630 630 def __init__(self, *args, **kwargs):
631 631 compiler.__init__(self, *args, **kwargs)
632 632 for i in 'compiler compiler_so linker_exe linker_so'.split():
633 633 try:
634 634 getattr(self, i).remove('-mno-cygwin')
635 635 except ValueError:
636 636 pass
637 637
638 638 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
639 639 except ImportError:
640 640 # the cygwinccompiler package is not available on some Python
641 641 # distributions like the ones from the optware project for Synology
642 642 # DiskStation boxes
643 643 class HackedMingw32CCompiler(object):
644 644 pass
645 645
646 646 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
647 647 'help/*.txt',
648 648 'help/internals/*.txt',
649 649 'default.d/*.rc',
650 650 'dummycert.pem']}
651 651
652 652 def ordinarypath(p):
653 653 return p and p[0] != '.' and p[-1] != '~'
654 654
655 655 for root in ('templates',):
656 656 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
657 657 curdir = curdir.split(os.sep, 1)[1]
658 658 dirs[:] = filter(ordinarypath, dirs)
659 659 for f in filter(ordinarypath, files):
660 660 f = os.path.join(curdir, f)
661 661 packagedata['mercurial'].append(f)
662 662
663 663 datafiles = []
664 664 setupversion = version
665 665 extra = {}
666 666
667 667 if py2exeloaded:
668 668 extra['console'] = [
669 669 {'script':'hg',
670 670 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
671 671 'product_version':version}]
672 672 # sub command of 'build' because 'py2exe' does not handle sub_commands
673 673 build.sub_commands.insert(0, ('build_hgextindex', None))
674 674 # put dlls in sub directory so that they won't pollute PATH
675 675 extra['zipfile'] = 'lib/library.zip'
676 676
677 677 if os.name == 'nt':
678 678 # Windows binary file versions for exe/dll files must have the
679 679 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
680 680 setupversion = version.split('+', 1)[0]
681 681
682 682 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
683 683 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
684 684 if version:
685 685 version = version[0]
686 686 if sys.version_info[0] == 3:
687 687 version = version.decode('utf-8')
688 688 xcode4 = (version.startswith('Xcode') and
689 689 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
690 690 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
691 691 else:
692 692 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
693 693 # installed, but instead with only command-line tools. Assume
694 694 # that only happens on >= Lion, thus no PPC support.
695 695 xcode4 = True
696 696 xcode51 = False
697 697
698 698 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
699 699 # distutils.sysconfig
700 700 if xcode4:
701 701 os.environ['ARCHFLAGS'] = ''
702 702
703 703 # XCode 5.1 changes clang such that it now fails to compile if the
704 704 # -mno-fused-madd flag is passed, but the version of Python shipped with
705 705 # OS X 10.9 Mavericks includes this flag. This causes problems in all
706 706 # C extension modules, and a bug has been filed upstream at
707 707 # http://bugs.python.org/issue21244. We also need to patch this here
708 708 # so Mercurial can continue to compile in the meantime.
709 709 if xcode51:
710 710 cflags = get_config_var('CFLAGS')
711 711 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
712 712 os.environ['CFLAGS'] = (
713 713 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
714 714
715 715 setup(name='mercurial',
716 716 version=setupversion,
717 717 author='Matt Mackall and many others',
718 718 author_email='mercurial@mercurial-scm.org',
719 719 url='https://mercurial-scm.org/',
720 720 download_url='https://mercurial-scm.org/release/',
721 721 description=('Fast scalable distributed SCM (revision control, version '
722 722 'control) system'),
723 723 long_description=('Mercurial is a distributed SCM tool written in Python.'
724 724 ' It is used by a number of large projects that require'
725 725 ' fast, reliable distributed revision control, such as '
726 726 'Mozilla.'),
727 727 license='GNU GPLv2 or any later version',
728 728 classifiers=[
729 729 'Development Status :: 6 - Mature',
730 730 'Environment :: Console',
731 731 'Intended Audience :: Developers',
732 732 'Intended Audience :: System Administrators',
733 733 'License :: OSI Approved :: GNU General Public License (GPL)',
734 734 'Natural Language :: Danish',
735 735 'Natural Language :: English',
736 736 'Natural Language :: German',
737 737 'Natural Language :: Italian',
738 738 'Natural Language :: Japanese',
739 739 'Natural Language :: Portuguese (Brazilian)',
740 740 'Operating System :: Microsoft :: Windows',
741 741 'Operating System :: OS Independent',
742 742 'Operating System :: POSIX',
743 743 'Programming Language :: C',
744 744 'Programming Language :: Python',
745 745 'Topic :: Software Development :: Version Control',
746 746 ],
747 747 scripts=scripts,
748 748 packages=packages,
749 749 ext_modules=extmodules,
750 750 data_files=datafiles,
751 751 package_data=packagedata,
752 752 cmdclass=cmdclass,
753 753 distclass=hgdist,
754 754 options={'py2exe': {'packages': ['hgext', 'email']},
755 755 'bdist_mpkg': {'zipdist': False,
756 756 'license': 'COPYING',
757 757 'readme': 'contrib/macosx/Readme.html',
758 758 'welcome': 'contrib/macosx/Welcome.html',
759 759 },
760 760 },
761 761 **extra)
@@ -1,25 +1,25
1 1 #require py3exe
2 2
3 3 This test helps in keeping a track on which commands we can run on
4 4 Python 3 and see what kind of errors are coming up.
5 5 The full traceback is hidden to have a stable output.
6 6
7 7 $ for cmd in version debuginstall ; do
8 8 > echo $cmd
9 9 > $PYTHON3 `which hg` $cmd 2>&1 2>&1 | tail -1
10 10 > done
11 11 version
12 12 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 13 debuginstall
14 TypeError: Can't convert 'bytes' object to str implicitly
14 no problems detected
15 15
16 16 $ cat > included-hgrc <<EOF
17 17 > [extensions]
18 18 > babar = imaginary_elephant
19 19 > EOF
20 20 $ cat >> $HGRCPATH <<EOF
21 21 > %include $TESTTMP/included-hgrc
22 22 > EOF
23 23 $ $PYTHON3 `which hg` version | tail -1
24 24 *** failed to import extension babar from imaginary_elephant: *: 'imaginary_elephant' (glob)
25 25 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
General Comments 0
You need to be logged in to leave comments. Login now