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