|
@@
-1,1756
+1,1750
b''
|
|
1
|
#
|
|
1
|
#
|
|
2
|
# This is the mercurial setup script.
|
|
2
|
# This is the mercurial setup script.
|
|
3
|
#
|
|
3
|
#
|
|
4
|
# 'python setup.py install', or
|
|
4
|
# 'python setup.py install', or
|
|
5
|
# 'python setup.py --help' for more options
|
|
5
|
# 'python setup.py --help' for more options
|
|
6
|
import os
|
|
6
|
import os
|
|
7
|
|
|
7
|
|
|
8
|
# Mercurial will never work on Python 3 before 3.5 due to a lack
|
|
8
|
# Mercurial will never work on Python 3 before 3.5 due to a lack
|
|
9
|
# of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
|
|
9
|
# of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
|
|
10
|
# due to a bug in % formatting in bytestrings.
|
|
10
|
# due to a bug in % formatting in bytestrings.
|
|
11
|
# We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
|
|
11
|
# We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
|
|
12
|
# codecs.escape_encode() where it raises SystemError on empty bytestring
|
|
12
|
# codecs.escape_encode() where it raises SystemError on empty bytestring
|
|
13
|
# bug link: https://bugs.python.org/issue25270
|
|
13
|
# bug link: https://bugs.python.org/issue25270
|
|
14
|
supportedpy = ','.join(
|
|
14
|
supportedpy = ','.join(
|
|
15
|
[
|
|
15
|
[
|
|
16
|
'>=3.5.3',
|
|
16
|
'>=3.5.3',
|
|
17
|
'!=3.6.0',
|
|
17
|
'!=3.6.0',
|
|
18
|
'!=3.6.1',
|
|
18
|
'!=3.6.1',
|
|
19
|
]
|
|
19
|
]
|
|
20
|
)
|
|
20
|
)
|
|
21
|
|
|
21
|
|
|
22
|
import sys, platform
|
|
22
|
import sys, platform
|
|
23
|
import sysconfig
|
|
23
|
import sysconfig
|
|
24
|
|
|
24
|
|
|
25
|
|
|
25
|
|
|
26
|
def sysstr(s):
|
|
26
|
def sysstr(s):
|
|
27
|
return s.decode('latin-1')
|
|
27
|
return s.decode('latin-1')
|
|
28
|
|
|
28
|
|
|
29
|
|
|
29
|
|
|
30
|
import ssl
|
|
30
|
import ssl
|
|
31
|
|
|
31
|
|
|
32
|
# ssl.HAS_TLSv1* are preferred to check support but they were added in Python
|
|
32
|
# ssl.HAS_TLSv1* are preferred to check support but they were added in Python
|
|
33
|
# 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98
|
|
33
|
# 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98
|
|
34
|
# (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2
|
|
34
|
# (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2
|
|
35
|
# were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2
|
|
35
|
# were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2
|
|
36
|
# support. At the mentioned commit, they were unconditionally defined.
|
|
36
|
# support. At the mentioned commit, they were unconditionally defined.
|
|
37
|
_notset = object()
|
|
37
|
_notset = object()
|
|
38
|
has_tlsv1_1 = getattr(ssl, 'HAS_TLSv1_1', _notset)
|
|
38
|
has_tlsv1_1 = getattr(ssl, 'HAS_TLSv1_1', _notset)
|
|
39
|
if has_tlsv1_1 is _notset:
|
|
39
|
if has_tlsv1_1 is _notset:
|
|
40
|
has_tlsv1_1 = getattr(ssl, 'PROTOCOL_TLSv1_1', _notset) is not _notset
|
|
40
|
has_tlsv1_1 = getattr(ssl, 'PROTOCOL_TLSv1_1', _notset) is not _notset
|
|
41
|
has_tlsv1_2 = getattr(ssl, 'HAS_TLSv1_2', _notset)
|
|
41
|
has_tlsv1_2 = getattr(ssl, 'HAS_TLSv1_2', _notset)
|
|
42
|
if has_tlsv1_2 is _notset:
|
|
42
|
if has_tlsv1_2 is _notset:
|
|
43
|
has_tlsv1_2 = getattr(ssl, 'PROTOCOL_TLSv1_2', _notset) is not _notset
|
|
43
|
has_tlsv1_2 = getattr(ssl, 'PROTOCOL_TLSv1_2', _notset) is not _notset
|
|
44
|
if not (has_tlsv1_1 or has_tlsv1_2):
|
|
44
|
if not (has_tlsv1_1 or has_tlsv1_2):
|
|
45
|
error = """
|
|
45
|
error = """
|
|
46
|
The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2.
|
|
46
|
The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2.
|
|
47
|
Please make sure that your Python installation was compiled against an OpenSSL
|
|
47
|
Please make sure that your Python installation was compiled against an OpenSSL
|
|
48
|
version enabling these features (likely this requires the OpenSSL version to
|
|
48
|
version enabling these features (likely this requires the OpenSSL version to
|
|
49
|
be at least 1.0.1).
|
|
49
|
be at least 1.0.1).
|
|
50
|
"""
|
|
50
|
"""
|
|
51
|
print(error, file=sys.stderr)
|
|
51
|
print(error, file=sys.stderr)
|
|
52
|
sys.exit(1)
|
|
52
|
sys.exit(1)
|
|
53
|
|
|
53
|
|
|
54
|
DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
|
|
54
|
DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
|
|
55
|
|
|
55
|
|
|
56
|
# Solaris Python packaging brain damage
|
|
56
|
# Solaris Python packaging brain damage
|
|
57
|
try:
|
|
57
|
try:
|
|
58
|
import hashlib
|
|
58
|
import hashlib
|
|
59
|
|
|
59
|
|
|
60
|
sha = hashlib.sha1()
|
|
60
|
sha = hashlib.sha1()
|
|
61
|
except ImportError:
|
|
61
|
except ImportError:
|
|
62
|
try:
|
|
62
|
try:
|
|
63
|
import sha
|
|
63
|
import sha
|
|
64
|
|
|
64
|
|
|
65
|
sha.sha # silence unused import warning
|
|
65
|
sha.sha # silence unused import warning
|
|
66
|
except ImportError:
|
|
66
|
except ImportError:
|
|
67
|
raise SystemExit(
|
|
67
|
raise SystemExit(
|
|
68
|
"Couldn't import standard hashlib (incomplete Python install)."
|
|
68
|
"Couldn't import standard hashlib (incomplete Python install)."
|
|
69
|
)
|
|
69
|
)
|
|
70
|
|
|
70
|
|
|
71
|
try:
|
|
71
|
try:
|
|
72
|
import zlib
|
|
72
|
import zlib
|
|
73
|
|
|
73
|
|
|
74
|
zlib.compressobj # silence unused import warning
|
|
74
|
zlib.compressobj # silence unused import warning
|
|
75
|
except ImportError:
|
|
75
|
except ImportError:
|
|
76
|
raise SystemExit(
|
|
76
|
raise SystemExit(
|
|
77
|
"Couldn't import standard zlib (incomplete Python install)."
|
|
77
|
"Couldn't import standard zlib (incomplete Python install)."
|
|
78
|
)
|
|
78
|
)
|
|
79
|
|
|
79
|
|
|
80
|
# The base IronPython distribution (as of 2.7.1) doesn't support bz2
|
|
80
|
# The base IronPython distribution (as of 2.7.1) doesn't support bz2
|
|
81
|
isironpython = False
|
|
81
|
isironpython = False
|
|
82
|
try:
|
|
82
|
try:
|
|
83
|
isironpython = (
|
|
83
|
isironpython = (
|
|
84
|
platform.python_implementation().lower().find("ironpython") != -1
|
|
84
|
platform.python_implementation().lower().find("ironpython") != -1
|
|
85
|
)
|
|
85
|
)
|
|
86
|
except AttributeError:
|
|
86
|
except AttributeError:
|
|
87
|
pass
|
|
87
|
pass
|
|
88
|
|
|
88
|
|
|
89
|
if isironpython:
|
|
89
|
if isironpython:
|
|
90
|
sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
|
|
90
|
sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
|
|
91
|
else:
|
|
91
|
else:
|
|
92
|
try:
|
|
92
|
try:
|
|
93
|
import bz2
|
|
93
|
import bz2
|
|
94
|
|
|
94
|
|
|
95
|
bz2.BZ2Compressor # silence unused import warning
|
|
95
|
bz2.BZ2Compressor # silence unused import warning
|
|
96
|
except ImportError:
|
|
96
|
except ImportError:
|
|
97
|
raise SystemExit(
|
|
97
|
raise SystemExit(
|
|
98
|
"Couldn't import standard bz2 (incomplete Python install)."
|
|
98
|
"Couldn't import standard bz2 (incomplete Python install)."
|
|
99
|
)
|
|
99
|
)
|
|
100
|
|
|
100
|
|
|
101
|
ispypy = "PyPy" in sys.version
|
|
101
|
ispypy = "PyPy" in sys.version
|
|
102
|
|
|
102
|
|
|
103
|
import ctypes
|
|
103
|
import ctypes
|
|
104
|
import errno
|
|
104
|
import errno
|
|
105
|
import stat, subprocess, time
|
|
105
|
import stat, subprocess, time
|
|
106
|
import re
|
|
106
|
import re
|
|
107
|
import shutil
|
|
107
|
import shutil
|
|
108
|
import tempfile
|
|
108
|
import tempfile
|
|
109
|
|
|
109
|
|
|
110
|
# We have issues with setuptools on some platforms and builders. Until
|
|
110
|
# We have issues with setuptools on some platforms and builders. Until
|
|
111
|
# those are resolved, setuptools is opt-in except for platforms where
|
|
111
|
# those are resolved, setuptools is opt-in except for platforms where
|
|
112
|
# we don't have issues.
|
|
112
|
# we don't have issues.
|
|
113
|
issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
|
|
113
|
issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
|
|
114
|
if issetuptools:
|
|
114
|
if issetuptools:
|
|
115
|
from setuptools import setup
|
|
115
|
from setuptools import setup
|
|
116
|
else:
|
|
116
|
else:
|
|
117
|
from distutils.core import setup
|
|
117
|
from distutils.core import setup
|
|
118
|
from distutils.ccompiler import new_compiler
|
|
118
|
from distutils.ccompiler import new_compiler
|
|
119
|
from distutils.core import Command, Extension
|
|
119
|
from distutils.core import Command, Extension
|
|
120
|
from distutils.dist import Distribution
|
|
120
|
from distutils.dist import Distribution
|
|
121
|
from distutils.command.build import build
|
|
121
|
from distutils.command.build import build
|
|
122
|
from distutils.command.build_ext import build_ext
|
|
122
|
from distutils.command.build_ext import build_ext
|
|
123
|
from distutils.command.build_py import build_py
|
|
123
|
from distutils.command.build_py import build_py
|
|
124
|
from distutils.command.build_scripts import build_scripts
|
|
124
|
from distutils.command.build_scripts import build_scripts
|
|
125
|
from distutils.command.install import install
|
|
125
|
from distutils.command.install import install
|
|
126
|
from distutils.command.install_lib import install_lib
|
|
126
|
from distutils.command.install_lib import install_lib
|
|
127
|
from distutils.command.install_scripts import install_scripts
|
|
127
|
from distutils.command.install_scripts import install_scripts
|
|
128
|
from distutils import log
|
|
128
|
from distutils import log
|
|
129
|
from distutils.spawn import spawn, find_executable
|
|
129
|
from distutils.spawn import spawn, find_executable
|
|
130
|
from distutils import file_util
|
|
130
|
from distutils import file_util
|
|
131
|
from distutils.errors import (
|
|
131
|
from distutils.errors import (
|
|
132
|
CCompilerError,
|
|
132
|
CCompilerError,
|
|
133
|
DistutilsError,
|
|
133
|
DistutilsError,
|
|
134
|
DistutilsExecError,
|
|
134
|
DistutilsExecError,
|
|
135
|
)
|
|
135
|
)
|
|
136
|
from distutils.sysconfig import get_python_inc, get_config_var
|
|
136
|
from distutils.sysconfig import get_python_inc, get_config_var
|
|
137
|
from distutils.version import StrictVersion
|
|
137
|
from distutils.version import StrictVersion
|
|
138
|
|
|
138
|
|
|
139
|
# Explain to distutils.StrictVersion how our release candidates are versioned
|
|
139
|
# Explain to distutils.StrictVersion how our release candidates are versioned
|
|
140
|
StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$')
|
|
140
|
StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$')
|
|
141
|
|
|
141
|
|
|
142
|
|
|
142
|
|
|
143
|
def write_if_changed(path, content):
|
|
143
|
def write_if_changed(path, content):
|
|
144
|
"""Write content to a file iff the content hasn't changed."""
|
|
144
|
"""Write content to a file iff the content hasn't changed."""
|
|
145
|
if os.path.exists(path):
|
|
145
|
if os.path.exists(path):
|
|
146
|
with open(path, 'rb') as fh:
|
|
146
|
with open(path, 'rb') as fh:
|
|
147
|
current = fh.read()
|
|
147
|
current = fh.read()
|
|
148
|
else:
|
|
148
|
else:
|
|
149
|
current = b''
|
|
149
|
current = b''
|
|
150
|
|
|
150
|
|
|
151
|
if current != content:
|
|
151
|
if current != content:
|
|
152
|
with open(path, 'wb') as fh:
|
|
152
|
with open(path, 'wb') as fh:
|
|
153
|
fh.write(content)
|
|
153
|
fh.write(content)
|
|
154
|
|
|
154
|
|
|
155
|
|
|
155
|
|
|
156
|
scripts = ['hg']
|
|
156
|
scripts = ['hg']
|
|
157
|
if os.name == 'nt':
|
|
157
|
if os.name == 'nt':
|
|
158
|
# We remove hg.bat if we are able to build hg.exe.
|
|
158
|
# We remove hg.bat if we are able to build hg.exe.
|
|
159
|
scripts.append('contrib/win32/hg.bat')
|
|
159
|
scripts.append('contrib/win32/hg.bat')
|
|
160
|
|
|
160
|
|
|
161
|
|
|
161
|
|
|
162
|
def cancompile(cc, code):
|
|
162
|
def cancompile(cc, code):
|
|
163
|
tmpdir = tempfile.mkdtemp(prefix='hg-install-')
|
|
163
|
tmpdir = tempfile.mkdtemp(prefix='hg-install-')
|
|
164
|
devnull = oldstderr = None
|
|
164
|
devnull = oldstderr = None
|
|
165
|
try:
|
|
165
|
try:
|
|
166
|
fname = os.path.join(tmpdir, 'testcomp.c')
|
|
166
|
fname = os.path.join(tmpdir, 'testcomp.c')
|
|
167
|
f = open(fname, 'w')
|
|
167
|
f = open(fname, 'w')
|
|
168
|
f.write(code)
|
|
168
|
f.write(code)
|
|
169
|
f.close()
|
|
169
|
f.close()
|
|
170
|
# Redirect stderr to /dev/null to hide any error messages
|
|
170
|
# Redirect stderr to /dev/null to hide any error messages
|
|
171
|
# from the compiler.
|
|
171
|
# from the compiler.
|
|
172
|
# This will have to be changed if we ever have to check
|
|
172
|
# This will have to be changed if we ever have to check
|
|
173
|
# for a function on Windows.
|
|
173
|
# for a function on Windows.
|
|
174
|
devnull = open('/dev/null', 'w')
|
|
174
|
devnull = open('/dev/null', 'w')
|
|
175
|
oldstderr = os.dup(sys.stderr.fileno())
|
|
175
|
oldstderr = os.dup(sys.stderr.fileno())
|
|
176
|
os.dup2(devnull.fileno(), sys.stderr.fileno())
|
|
176
|
os.dup2(devnull.fileno(), sys.stderr.fileno())
|
|
177
|
objects = cc.compile([fname], output_dir=tmpdir)
|
|
177
|
objects = cc.compile([fname], output_dir=tmpdir)
|
|
178
|
cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
|
|
178
|
cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
|
|
179
|
return True
|
|
179
|
return True
|
|
180
|
except Exception:
|
|
180
|
except Exception:
|
|
181
|
return False
|
|
181
|
return False
|
|
182
|
finally:
|
|
182
|
finally:
|
|
183
|
if oldstderr is not None:
|
|
183
|
if oldstderr is not None:
|
|
184
|
os.dup2(oldstderr, sys.stderr.fileno())
|
|
184
|
os.dup2(oldstderr, sys.stderr.fileno())
|
|
185
|
if devnull is not None:
|
|
185
|
if devnull is not None:
|
|
186
|
devnull.close()
|
|
186
|
devnull.close()
|
|
187
|
shutil.rmtree(tmpdir)
|
|
187
|
shutil.rmtree(tmpdir)
|
|
188
|
|
|
188
|
|
|
189
|
|
|
189
|
|
|
190
|
# simplified version of distutils.ccompiler.CCompiler.has_function
|
|
190
|
# simplified version of distutils.ccompiler.CCompiler.has_function
|
|
191
|
# that actually removes its temporary files.
|
|
191
|
# that actually removes its temporary files.
|
|
192
|
def hasfunction(cc, funcname):
|
|
192
|
def hasfunction(cc, funcname):
|
|
193
|
code = 'int main(void) { %s(); }\n' % funcname
|
|
193
|
code = 'int main(void) { %s(); }\n' % funcname
|
|
194
|
return cancompile(cc, code)
|
|
194
|
return cancompile(cc, code)
|
|
195
|
|
|
195
|
|
|
196
|
|
|
196
|
|
|
197
|
def hasheader(cc, headername):
|
|
197
|
def hasheader(cc, headername):
|
|
198
|
code = '#include <%s>\nint main(void) { return 0; }\n' % headername
|
|
198
|
code = '#include <%s>\nint main(void) { return 0; }\n' % headername
|
|
199
|
return cancompile(cc, code)
|
|
199
|
return cancompile(cc, code)
|
|
200
|
|
|
200
|
|
|
201
|
|
|
201
|
|
|
202
|
# py2exe needs to be installed to work
|
|
202
|
# py2exe needs to be installed to work
|
|
203
|
try:
|
|
203
|
try:
|
|
204
|
import py2exe
|
|
204
|
import py2exe
|
|
205
|
|
|
205
|
|
|
206
|
py2exe.Distribution # silence unused import warning
|
|
206
|
py2exe.Distribution # silence unused import warning
|
|
207
|
py2exeloaded = True
|
|
207
|
py2exeloaded = True
|
|
208
|
# import py2exe's patched Distribution class
|
|
208
|
# import py2exe's patched Distribution class
|
|
209
|
from distutils.core import Distribution
|
|
209
|
from distutils.core import Distribution
|
|
210
|
except ImportError:
|
|
210
|
except ImportError:
|
|
211
|
py2exeloaded = False
|
|
211
|
py2exeloaded = False
|
|
212
|
|
|
212
|
|
|
213
|
|
|
213
|
|
|
214
|
def runcmd(cmd, env, cwd=None):
|
|
214
|
def runcmd(cmd, env, cwd=None):
|
|
215
|
p = subprocess.Popen(
|
|
215
|
p = subprocess.Popen(
|
|
216
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
|
|
216
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
|
|
217
|
)
|
|
217
|
)
|
|
218
|
out, err = p.communicate()
|
|
218
|
out, err = p.communicate()
|
|
219
|
return p.returncode, out, err
|
|
219
|
return p.returncode, out, err
|
|
220
|
|
|
220
|
|
|
221
|
|
|
221
|
|
|
222
|
class hgcommand(object):
|
|
222
|
class hgcommand(object):
|
|
223
|
def __init__(self, cmd, env):
|
|
223
|
def __init__(self, cmd, env):
|
|
224
|
self.cmd = cmd
|
|
224
|
self.cmd = cmd
|
|
225
|
self.env = env
|
|
225
|
self.env = env
|
|
226
|
|
|
226
|
|
|
227
|
def run(self, args):
|
|
227
|
def run(self, args):
|
|
228
|
cmd = self.cmd + args
|
|
228
|
cmd = self.cmd + args
|
|
229
|
returncode, out, err = runcmd(cmd, self.env)
|
|
229
|
returncode, out, err = runcmd(cmd, self.env)
|
|
230
|
err = filterhgerr(err)
|
|
230
|
err = filterhgerr(err)
|
|
231
|
if err or returncode != 0:
|
|
231
|
if err or returncode != 0:
|
|
232
|
print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
|
|
232
|
print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
|
|
233
|
print(err, file=sys.stderr)
|
|
233
|
print(err, file=sys.stderr)
|
|
234
|
return b''
|
|
234
|
return b''
|
|
235
|
return out
|
|
235
|
return out
|
|
236
|
|
|
236
|
|
|
237
|
|
|
237
|
|
|
238
|
def filterhgerr(err):
|
|
238
|
def filterhgerr(err):
|
|
239
|
# If root is executing setup.py, but the repository is owned by
|
|
239
|
# If root is executing setup.py, but the repository is owned by
|
|
240
|
# another user (as in "sudo python setup.py install") we will get
|
|
240
|
# another user (as in "sudo python setup.py install") we will get
|
|
241
|
# trust warnings since the .hg/hgrc file is untrusted. That is
|
|
241
|
# trust warnings since the .hg/hgrc file is untrusted. That is
|
|
242
|
# fine, we don't want to load it anyway. Python may warn about
|
|
242
|
# fine, we don't want to load it anyway. Python may warn about
|
|
243
|
# a missing __init__.py in mercurial/locale, we also ignore that.
|
|
243
|
# a missing __init__.py in mercurial/locale, we also ignore that.
|
|
244
|
err = [
|
|
244
|
err = [
|
|
245
|
e
|
|
245
|
e
|
|
246
|
for e in err.splitlines()
|
|
246
|
for e in err.splitlines()
|
|
247
|
if (
|
|
247
|
if (
|
|
248
|
not e.startswith(b'not trusting file')
|
|
248
|
not e.startswith(b'not trusting file')
|
|
249
|
and not e.startswith(b'warning: Not importing')
|
|
249
|
and not e.startswith(b'warning: Not importing')
|
|
250
|
and not e.startswith(b'obsolete feature not enabled')
|
|
250
|
and not e.startswith(b'obsolete feature not enabled')
|
|
251
|
and not e.startswith(b'*** failed to import extension')
|
|
251
|
and not e.startswith(b'*** failed to import extension')
|
|
252
|
and not e.startswith(b'devel-warn:')
|
|
252
|
and not e.startswith(b'devel-warn:')
|
|
253
|
and not (
|
|
253
|
and not (
|
|
254
|
e.startswith(b'(third party extension')
|
|
254
|
e.startswith(b'(third party extension')
|
|
255
|
and e.endswith(b'or newer of Mercurial; disabling)')
|
|
255
|
and e.endswith(b'or newer of Mercurial; disabling)')
|
|
256
|
)
|
|
256
|
)
|
|
257
|
)
|
|
257
|
)
|
|
258
|
]
|
|
258
|
]
|
|
259
|
return b'\n'.join(b' ' + e for e in err)
|
|
259
|
return b'\n'.join(b' ' + e for e in err)
|
|
260
|
|
|
260
|
|
|
261
|
|
|
261
|
|
|
262
|
def findhg():
|
|
262
|
def findhg():
|
|
263
|
"""Try to figure out how we should invoke hg for examining the local
|
|
263
|
"""Try to figure out how we should invoke hg for examining the local
|
|
264
|
repository contents.
|
|
264
|
repository contents.
|
|
265
|
|
|
265
|
|
|
266
|
Returns an hgcommand object."""
|
|
266
|
Returns an hgcommand object."""
|
|
267
|
# By default, prefer the "hg" command in the user's path. This was
|
|
267
|
# By default, prefer the "hg" command in the user's path. This was
|
|
268
|
# presumably the hg command that the user used to create this repository.
|
|
268
|
# presumably the hg command that the user used to create this repository.
|
|
269
|
#
|
|
269
|
#
|
|
270
|
# This repository may require extensions or other settings that would not
|
|
270
|
# This repository may require extensions or other settings that would not
|
|
271
|
# be enabled by running the hg script directly from this local repository.
|
|
271
|
# be enabled by running the hg script directly from this local repository.
|
|
272
|
hgenv = os.environ.copy()
|
|
272
|
hgenv = os.environ.copy()
|
|
273
|
# Use HGPLAIN to disable hgrc settings that would change output formatting,
|
|
273
|
# Use HGPLAIN to disable hgrc settings that would change output formatting,
|
|
274
|
# and disable localization for the same reasons.
|
|
274
|
# and disable localization for the same reasons.
|
|
275
|
hgenv['HGPLAIN'] = '1'
|
|
275
|
hgenv['HGPLAIN'] = '1'
|
|
276
|
hgenv['LANGUAGE'] = 'C'
|
|
276
|
hgenv['LANGUAGE'] = 'C'
|
|
277
|
hgcmd = ['hg']
|
|
277
|
hgcmd = ['hg']
|
|
278
|
# Run a simple "hg log" command just to see if using hg from the user's
|
|
278
|
# Run a simple "hg log" command just to see if using hg from the user's
|
|
279
|
# path works and can successfully interact with this repository. Windows
|
|
279
|
# path works and can successfully interact with this repository. Windows
|
|
280
|
# gives precedence to hg.exe in the current directory, so fall back to the
|
|
280
|
# gives precedence to hg.exe in the current directory, so fall back to the
|
|
281
|
# python invocation of local hg, where pythonXY.dll can always be found.
|
|
281
|
# python invocation of local hg, where pythonXY.dll can always be found.
|
|
282
|
check_cmd = ['log', '-r.', '-Ttest']
|
|
282
|
check_cmd = ['log', '-r.', '-Ttest']
|
|
283
|
if os.name != 'nt' or not os.path.exists("hg.exe"):
|
|
283
|
if os.name != 'nt' or not os.path.exists("hg.exe"):
|
|
284
|
try:
|
|
284
|
try:
|
|
285
|
retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
|
|
285
|
retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
|
|
286
|
except EnvironmentError:
|
|
286
|
except EnvironmentError:
|
|
287
|
retcode = -1
|
|
287
|
retcode = -1
|
|
288
|
if retcode == 0 and not filterhgerr(err):
|
|
288
|
if retcode == 0 and not filterhgerr(err):
|
|
289
|
return hgcommand(hgcmd, hgenv)
|
|
289
|
return hgcommand(hgcmd, hgenv)
|
|
290
|
|
|
290
|
|
|
291
|
# Fall back to trying the local hg installation.
|
|
291
|
# Fall back to trying the local hg installation.
|
|
292
|
hgenv = localhgenv()
|
|
292
|
hgenv = localhgenv()
|
|
293
|
hgcmd = [sys.executable, 'hg']
|
|
293
|
hgcmd = [sys.executable, 'hg']
|
|
294
|
try:
|
|
294
|
try:
|
|
295
|
retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
|
|
295
|
retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
|
|
296
|
except EnvironmentError:
|
|
296
|
except EnvironmentError:
|
|
297
|
retcode = -1
|
|
297
|
retcode = -1
|
|
298
|
if retcode == 0 and not filterhgerr(err):
|
|
298
|
if retcode == 0 and not filterhgerr(err):
|
|
299
|
return hgcommand(hgcmd, hgenv)
|
|
299
|
return hgcommand(hgcmd, hgenv)
|
|
300
|
|
|
300
|
|
|
301
|
raise SystemExit(
|
|
301
|
raise SystemExit(
|
|
302
|
'Unable to find a working hg binary to extract the '
|
|
302
|
'Unable to find a working hg binary to extract the '
|
|
303
|
'version from the repository tags'
|
|
303
|
'version from the repository tags'
|
|
304
|
)
|
|
304
|
)
|
|
305
|
|
|
305
|
|
|
306
|
|
|
306
|
|
|
307
|
def localhgenv():
|
|
307
|
def localhgenv():
|
|
308
|
"""Get an environment dictionary to use for invoking or importing
|
|
308
|
"""Get an environment dictionary to use for invoking or importing
|
|
309
|
mercurial from the local repository."""
|
|
309
|
mercurial from the local repository."""
|
|
310
|
# Execute hg out of this directory with a custom environment which takes
|
|
310
|
# Execute hg out of this directory with a custom environment which takes
|
|
311
|
# care to not use any hgrc files and do no localization.
|
|
311
|
# care to not use any hgrc files and do no localization.
|
|
312
|
env = {
|
|
312
|
env = {
|
|
313
|
'HGMODULEPOLICY': 'py',
|
|
313
|
'HGMODULEPOLICY': 'py',
|
|
314
|
'HGRCPATH': '',
|
|
314
|
'HGRCPATH': '',
|
|
315
|
'LANGUAGE': 'C',
|
|
315
|
'LANGUAGE': 'C',
|
|
316
|
'PATH': '',
|
|
316
|
'PATH': '',
|
|
317
|
} # make pypi modules that use os.environ['PATH'] happy
|
|
317
|
} # make pypi modules that use os.environ['PATH'] happy
|
|
318
|
if 'LD_LIBRARY_PATH' in os.environ:
|
|
318
|
if 'LD_LIBRARY_PATH' in os.environ:
|
|
319
|
env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
|
|
319
|
env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
|
|
320
|
if 'SystemRoot' in os.environ:
|
|
320
|
if 'SystemRoot' in os.environ:
|
|
321
|
# SystemRoot is required by Windows to load various DLLs. See:
|
|
321
|
# SystemRoot is required by Windows to load various DLLs. See:
|
|
322
|
# https://bugs.python.org/issue13524#msg148850
|
|
322
|
# https://bugs.python.org/issue13524#msg148850
|
|
323
|
env['SystemRoot'] = os.environ['SystemRoot']
|
|
323
|
env['SystemRoot'] = os.environ['SystemRoot']
|
|
324
|
return env
|
|
324
|
return env
|
|
325
|
|
|
325
|
|
|
326
|
|
|
326
|
|
|
327
|
version = ''
|
|
327
|
version = ''
|
|
328
|
|
|
328
|
|
|
329
|
if os.path.isdir('.hg'):
|
|
329
|
if os.path.isdir('.hg'):
|
|
330
|
hg = findhg()
|
|
330
|
hg = findhg()
|
|
331
|
cmd = ['log', '-r', '.', '--template', '{tags}\n']
|
|
331
|
cmd = ['log', '-r', '.', '--template', '{tags}\n']
|
|
332
|
numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
|
|
332
|
numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
|
|
333
|
hgid = sysstr(hg.run(['id', '-i'])).strip()
|
|
333
|
hgid = sysstr(hg.run(['id', '-i'])).strip()
|
|
334
|
if not hgid:
|
|
334
|
if not hgid:
|
|
335
|
# Bail out if hg is having problems interacting with this repository,
|
|
335
|
# Bail out if hg is having problems interacting with this repository,
|
|
336
|
# rather than falling through and producing a bogus version number.
|
|
336
|
# rather than falling through and producing a bogus version number.
|
|
337
|
# Continuing with an invalid version number will break extensions
|
|
337
|
# Continuing with an invalid version number will break extensions
|
|
338
|
# that define minimumhgversion.
|
|
338
|
# that define minimumhgversion.
|
|
339
|
raise SystemExit('Unable to determine hg version from local repository')
|
|
339
|
raise SystemExit('Unable to determine hg version from local repository')
|
|
340
|
if numerictags: # tag(s) found
|
|
340
|
if numerictags: # tag(s) found
|
|
341
|
version = numerictags[-1]
|
|
341
|
version = numerictags[-1]
|
|
342
|
if hgid.endswith('+'): # propagate the dirty status to the tag
|
|
342
|
if hgid.endswith('+'): # propagate the dirty status to the tag
|
|
343
|
version += '+'
|
|
343
|
version += '+'
|
|
344
|
else: # no tag found
|
|
344
|
else: # no tag found
|
|
345
|
ltagcmd = ['parents', '--template', '{latesttag}']
|
|
345
|
ltagcmd = ['parents', '--template', '{latesttag}']
|
|
346
|
ltag = sysstr(hg.run(ltagcmd))
|
|
346
|
ltag = sysstr(hg.run(ltagcmd))
|
|
347
|
changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
|
|
347
|
changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
|
|
348
|
changessince = len(hg.run(changessincecmd).splitlines())
|
|
348
|
changessince = len(hg.run(changessincecmd).splitlines())
|
|
349
|
version = '%s+hg%s.%s' % (ltag, changessince, hgid)
|
|
349
|
version = '%s+hg%s.%s' % (ltag, changessince, hgid)
|
|
350
|
if version.endswith('+'):
|
|
350
|
if version.endswith('+'):
|
|
351
|
version = version[:-1] + 'local' + time.strftime('%Y%m%d')
|
|
351
|
version = version[:-1] + 'local' + time.strftime('%Y%m%d')
|
|
352
|
elif os.path.exists('.hg_archival.txt'):
|
|
352
|
elif os.path.exists('.hg_archival.txt'):
|
|
353
|
kw = dict(
|
|
353
|
kw = dict(
|
|
354
|
[[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
|
|
354
|
[[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
|
|
355
|
)
|
|
355
|
)
|
|
356
|
if 'tag' in kw:
|
|
356
|
if 'tag' in kw:
|
|
357
|
version = kw['tag']
|
|
357
|
version = kw['tag']
|
|
358
|
elif 'latesttag' in kw:
|
|
358
|
elif 'latesttag' in kw:
|
|
359
|
if 'changessincelatesttag' in kw:
|
|
359
|
if 'changessincelatesttag' in kw:
|
|
360
|
version = (
|
|
360
|
version = (
|
|
361
|
'%(latesttag)s+hg%(changessincelatesttag)s.%(node).12s' % kw
|
|
361
|
'%(latesttag)s+hg%(changessincelatesttag)s.%(node).12s' % kw
|
|
362
|
)
|
|
362
|
)
|
|
363
|
else:
|
|
363
|
else:
|
|
364
|
version = '%(latesttag)s+hg%(latesttagdistance)s.%(node).12s' % kw
|
|
364
|
version = '%(latesttag)s+hg%(latesttagdistance)s.%(node).12s' % kw
|
|
365
|
else:
|
|
365
|
else:
|
|
366
|
version = '0+hg' + kw.get('node', '')[:12]
|
|
366
|
version = '0+hg' + kw.get('node', '')[:12]
|
|
367
|
elif os.path.exists('mercurial/__version__.py'):
|
|
367
|
elif os.path.exists('mercurial/__version__.py'):
|
|
368
|
with open('mercurial/__version__.py') as f:
|
|
368
|
with open('mercurial/__version__.py') as f:
|
|
369
|
data = f.read()
|
|
369
|
data = f.read()
|
|
370
|
version = re.search('version = b"(.*)"', data).group(1)
|
|
370
|
version = re.search('version = b"(.*)"', data).group(1)
|
|
371
|
|
|
371
|
|
|
372
|
if version:
|
|
372
|
if version:
|
|
373
|
versionb = version
|
|
373
|
versionb = version
|
|
374
|
if not isinstance(versionb, bytes):
|
|
374
|
if not isinstance(versionb, bytes):
|
|
375
|
versionb = versionb.encode('ascii')
|
|
375
|
versionb = versionb.encode('ascii')
|
|
376
|
|
|
376
|
|
|
377
|
write_if_changed(
|
|
377
|
write_if_changed(
|
|
378
|
'mercurial/__version__.py',
|
|
378
|
'mercurial/__version__.py',
|
|
379
|
b''.join(
|
|
379
|
b''.join(
|
|
380
|
[
|
|
380
|
[
|
|
381
|
b'# this file is autogenerated by setup.py\n'
|
|
381
|
b'# this file is autogenerated by setup.py\n'
|
|
382
|
b'version = b"%s"\n' % versionb,
|
|
382
|
b'version = b"%s"\n' % versionb,
|
|
383
|
]
|
|
383
|
]
|
|
384
|
),
|
|
384
|
),
|
|
385
|
)
|
|
385
|
)
|
|
386
|
|
|
386
|
|
|
387
|
|
|
387
|
|
|
388
|
class hgbuild(build):
|
|
388
|
class hgbuild(build):
|
|
389
|
# Insert hgbuildmo first so that files in mercurial/locale/ are found
|
|
389
|
# Insert hgbuildmo first so that files in mercurial/locale/ are found
|
|
390
|
# when build_py is run next.
|
|
390
|
# when build_py is run next.
|
|
391
|
sub_commands = [('build_mo', None)] + build.sub_commands
|
|
391
|
sub_commands = [('build_mo', None)] + build.sub_commands
|
|
392
|
|
|
392
|
|
|
393
|
|
|
393
|
|
|
394
|
class hgbuildmo(build):
|
|
394
|
class hgbuildmo(build):
|
|
395
|
|
|
395
|
|
|
396
|
description = "build translations (.mo files)"
|
|
396
|
description = "build translations (.mo files)"
|
|
397
|
|
|
397
|
|
|
398
|
def run(self):
|
|
398
|
def run(self):
|
|
399
|
if not find_executable('msgfmt'):
|
|
399
|
if not find_executable('msgfmt'):
|
|
400
|
self.warn(
|
|
400
|
self.warn(
|
|
401
|
"could not find msgfmt executable, no translations "
|
|
401
|
"could not find msgfmt executable, no translations "
|
|
402
|
"will be built"
|
|
402
|
"will be built"
|
|
403
|
)
|
|
403
|
)
|
|
404
|
return
|
|
404
|
return
|
|
405
|
|
|
405
|
|
|
406
|
podir = 'i18n'
|
|
406
|
podir = 'i18n'
|
|
407
|
if not os.path.isdir(podir):
|
|
407
|
if not os.path.isdir(podir):
|
|
408
|
self.warn("could not find %s/ directory" % podir)
|
|
408
|
self.warn("could not find %s/ directory" % podir)
|
|
409
|
return
|
|
409
|
return
|
|
410
|
|
|
410
|
|
|
411
|
join = os.path.join
|
|
411
|
join = os.path.join
|
|
412
|
for po in os.listdir(podir):
|
|
412
|
for po in os.listdir(podir):
|
|
413
|
if not po.endswith('.po'):
|
|
413
|
if not po.endswith('.po'):
|
|
414
|
continue
|
|
414
|
continue
|
|
415
|
pofile = join(podir, po)
|
|
415
|
pofile = join(podir, po)
|
|
416
|
modir = join('locale', po[:-3], 'LC_MESSAGES')
|
|
416
|
modir = join('locale', po[:-3], 'LC_MESSAGES')
|
|
417
|
mofile = join(modir, 'hg.mo')
|
|
417
|
mofile = join(modir, 'hg.mo')
|
|
418
|
mobuildfile = join('mercurial', mofile)
|
|
418
|
mobuildfile = join('mercurial', mofile)
|
|
419
|
cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
|
|
419
|
cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
|
|
420
|
if sys.platform != 'sunos5':
|
|
420
|
if sys.platform != 'sunos5':
|
|
421
|
# msgfmt on Solaris does not know about -c
|
|
421
|
# msgfmt on Solaris does not know about -c
|
|
422
|
cmd.append('-c')
|
|
422
|
cmd.append('-c')
|
|
423
|
self.mkpath(join('mercurial', modir))
|
|
423
|
self.mkpath(join('mercurial', modir))
|
|
424
|
self.make_file([pofile], mobuildfile, spawn, (cmd,))
|
|
424
|
self.make_file([pofile], mobuildfile, spawn, (cmd,))
|
|
425
|
|
|
425
|
|
|
426
|
|
|
426
|
|
|
427
|
class hgdist(Distribution):
|
|
427
|
class hgdist(Distribution):
|
|
428
|
pure = False
|
|
428
|
pure = False
|
|
429
|
rust = False
|
|
429
|
rust = False
|
|
430
|
no_rust = False
|
|
430
|
no_rust = False
|
|
431
|
cffi = ispypy
|
|
431
|
cffi = ispypy
|
|
432
|
|
|
432
|
|
|
433
|
global_options = Distribution.global_options + [
|
|
433
|
global_options = Distribution.global_options + [
|
|
434
|
('pure', None, "use pure (slow) Python code instead of C extensions"),
|
|
434
|
('pure', None, "use pure (slow) Python code instead of C extensions"),
|
|
435
|
('rust', None, "use Rust extensions additionally to C extensions"),
|
|
435
|
('rust', None, "use Rust extensions additionally to C extensions"),
|
|
436
|
(
|
|
436
|
(
|
|
437
|
'no-rust',
|
|
437
|
'no-rust',
|
|
438
|
None,
|
|
438
|
None,
|
|
439
|
"do not use Rust extensions additionally to C extensions",
|
|
439
|
"do not use Rust extensions additionally to C extensions",
|
|
440
|
),
|
|
440
|
),
|
|
441
|
]
|
|
441
|
]
|
|
442
|
|
|
442
|
|
|
443
|
negative_opt = Distribution.negative_opt.copy()
|
|
443
|
negative_opt = Distribution.negative_opt.copy()
|
|
444
|
boolean_options = ['pure', 'rust', 'no-rust']
|
|
444
|
boolean_options = ['pure', 'rust', 'no-rust']
|
|
445
|
negative_opt['no-rust'] = 'rust'
|
|
445
|
negative_opt['no-rust'] = 'rust'
|
|
446
|
|
|
446
|
|
|
447
|
def _set_command_options(self, command_obj, option_dict=None):
|
|
447
|
def _set_command_options(self, command_obj, option_dict=None):
|
|
448
|
# Not all distutils versions in the wild have boolean_options.
|
|
448
|
# Not all distutils versions in the wild have boolean_options.
|
|
449
|
# This should be cleaned up when we're Python 3 only.
|
|
449
|
# This should be cleaned up when we're Python 3 only.
|
|
450
|
command_obj.boolean_options = (
|
|
450
|
command_obj.boolean_options = (
|
|
451
|
getattr(command_obj, 'boolean_options', []) + self.boolean_options
|
|
451
|
getattr(command_obj, 'boolean_options', []) + self.boolean_options
|
|
452
|
)
|
|
452
|
)
|
|
453
|
return Distribution._set_command_options(
|
|
453
|
return Distribution._set_command_options(
|
|
454
|
self, command_obj, option_dict=option_dict
|
|
454
|
self, command_obj, option_dict=option_dict
|
|
455
|
)
|
|
455
|
)
|
|
456
|
|
|
456
|
|
|
457
|
def parse_command_line(self):
|
|
457
|
def parse_command_line(self):
|
|
458
|
ret = Distribution.parse_command_line(self)
|
|
458
|
ret = Distribution.parse_command_line(self)
|
|
459
|
if not (self.rust or self.no_rust):
|
|
459
|
if not (self.rust or self.no_rust):
|
|
460
|
hgrustext = os.environ.get('HGWITHRUSTEXT')
|
|
460
|
hgrustext = os.environ.get('HGWITHRUSTEXT')
|
|
461
|
# TODO record it for proper rebuild upon changes
|
|
461
|
# TODO record it for proper rebuild upon changes
|
|
462
|
# (see mercurial/__modulepolicy__.py)
|
|
462
|
# (see mercurial/__modulepolicy__.py)
|
|
463
|
if hgrustext != 'cpython' and hgrustext is not None:
|
|
463
|
if hgrustext != 'cpython' and hgrustext is not None:
|
|
464
|
if hgrustext:
|
|
464
|
if hgrustext:
|
|
465
|
msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext
|
|
465
|
msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext
|
|
466
|
print(msg, file=sys.stderr)
|
|
466
|
print(msg, file=sys.stderr)
|
|
467
|
hgrustext = None
|
|
467
|
hgrustext = None
|
|
468
|
self.rust = hgrustext is not None
|
|
468
|
self.rust = hgrustext is not None
|
|
469
|
self.no_rust = not self.rust
|
|
469
|
self.no_rust = not self.rust
|
|
470
|
return ret
|
|
470
|
return ret
|
|
471
|
|
|
471
|
|
|
472
|
def has_ext_modules(self):
|
|
472
|
def has_ext_modules(self):
|
|
473
|
# self.ext_modules is emptied in hgbuildpy.finalize_options which is
|
|
473
|
# self.ext_modules is emptied in hgbuildpy.finalize_options which is
|
|
474
|
# too late for some cases
|
|
474
|
# too late for some cases
|
|
475
|
return not self.pure and Distribution.has_ext_modules(self)
|
|
475
|
return not self.pure and Distribution.has_ext_modules(self)
|
|
476
|
|
|
476
|
|
|
477
|
|
|
477
|
|
|
478
|
# This is ugly as a one-liner. So use a variable.
|
|
478
|
# This is ugly as a one-liner. So use a variable.
|
|
479
|
buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
|
|
479
|
buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
|
|
480
|
buildextnegops['no-zstd'] = 'zstd'
|
|
480
|
buildextnegops['no-zstd'] = 'zstd'
|
|
481
|
buildextnegops['no-rust'] = 'rust'
|
|
481
|
buildextnegops['no-rust'] = 'rust'
|
|
482
|
|
|
482
|
|
|
483
|
|
|
483
|
|
|
484
|
class hgbuildext(build_ext):
|
|
484
|
class hgbuildext(build_ext):
|
|
485
|
user_options = build_ext.user_options + [
|
|
485
|
user_options = build_ext.user_options + [
|
|
486
|
('zstd', None, 'compile zstd bindings [default]'),
|
|
486
|
('zstd', None, 'compile zstd bindings [default]'),
|
|
487
|
('no-zstd', None, 'do not compile zstd bindings'),
|
|
487
|
('no-zstd', None, 'do not compile zstd bindings'),
|
|
488
|
(
|
|
488
|
(
|
|
489
|
'rust',
|
|
489
|
'rust',
|
|
490
|
None,
|
|
490
|
None,
|
|
491
|
'compile Rust extensions if they are in use '
|
|
491
|
'compile Rust extensions if they are in use '
|
|
492
|
'(requires Cargo) [default]',
|
|
492
|
'(requires Cargo) [default]',
|
|
493
|
),
|
|
493
|
),
|
|
494
|
('no-rust', None, 'do not compile Rust extensions'),
|
|
494
|
('no-rust', None, 'do not compile Rust extensions'),
|
|
495
|
]
|
|
495
|
]
|
|
496
|
|
|
496
|
|
|
497
|
boolean_options = build_ext.boolean_options + ['zstd', 'rust']
|
|
497
|
boolean_options = build_ext.boolean_options + ['zstd', 'rust']
|
|
498
|
negative_opt = buildextnegops
|
|
498
|
negative_opt = buildextnegops
|
|
499
|
|
|
499
|
|
|
500
|
def initialize_options(self):
|
|
500
|
def initialize_options(self):
|
|
501
|
self.zstd = True
|
|
501
|
self.zstd = True
|
|
502
|
self.rust = True
|
|
502
|
self.rust = True
|
|
503
|
|
|
503
|
|
|
504
|
return build_ext.initialize_options(self)
|
|
504
|
return build_ext.initialize_options(self)
|
|
505
|
|
|
505
|
|
|
506
|
def finalize_options(self):
|
|
506
|
def finalize_options(self):
|
|
507
|
# Unless overridden by the end user, build extensions in parallel.
|
|
507
|
# Unless overridden by the end user, build extensions in parallel.
|
|
508
|
# Only influences behavior on Python 3.5+.
|
|
508
|
# Only influences behavior on Python 3.5+.
|
|
509
|
if getattr(self, 'parallel', None) is None:
|
|
509
|
if getattr(self, 'parallel', None) is None:
|
|
510
|
self.parallel = True
|
|
510
|
self.parallel = True
|
|
511
|
|
|
511
|
|
|
512
|
return build_ext.finalize_options(self)
|
|
512
|
return build_ext.finalize_options(self)
|
|
513
|
|
|
513
|
|
|
514
|
def build_extensions(self):
|
|
514
|
def build_extensions(self):
|
|
515
|
ruststandalones = [
|
|
515
|
ruststandalones = [
|
|
516
|
e for e in self.extensions if isinstance(e, RustStandaloneExtension)
|
|
516
|
e for e in self.extensions if isinstance(e, RustStandaloneExtension)
|
|
517
|
]
|
|
517
|
]
|
|
518
|
self.extensions = [
|
|
518
|
self.extensions = [
|
|
519
|
e for e in self.extensions if e not in ruststandalones
|
|
519
|
e for e in self.extensions if e not in ruststandalones
|
|
520
|
]
|
|
520
|
]
|
|
521
|
# Filter out zstd if disabled via argument.
|
|
521
|
# Filter out zstd if disabled via argument.
|
|
522
|
if not self.zstd:
|
|
522
|
if not self.zstd:
|
|
523
|
self.extensions = [
|
|
523
|
self.extensions = [
|
|
524
|
e for e in self.extensions if e.name != 'mercurial.zstd'
|
|
524
|
e for e in self.extensions if e.name != 'mercurial.zstd'
|
|
525
|
]
|
|
525
|
]
|
|
526
|
|
|
526
|
|
|
527
|
# Build Rust standalone extensions if it'll be used
|
|
527
|
# Build Rust standalone extensions if it'll be used
|
|
528
|
# and its build is not explicitly disabled (for external build
|
|
528
|
# and its build is not explicitly disabled (for external build
|
|
529
|
# as Linux distributions would do)
|
|
529
|
# as Linux distributions would do)
|
|
530
|
if self.distribution.rust and self.rust:
|
|
530
|
if self.distribution.rust and self.rust:
|
|
531
|
if not sys.platform.startswith('linux'):
|
|
531
|
if not sys.platform.startswith('linux'):
|
|
532
|
self.warn(
|
|
532
|
self.warn(
|
|
533
|
"rust extensions have only been tested on Linux "
|
|
533
|
"rust extensions have only been tested on Linux "
|
|
534
|
"and may not behave correctly on other platforms"
|
|
534
|
"and may not behave correctly on other platforms"
|
|
535
|
)
|
|
535
|
)
|
|
536
|
|
|
536
|
|
|
537
|
for rustext in ruststandalones:
|
|
537
|
for rustext in ruststandalones:
|
|
538
|
rustext.build('' if self.inplace else self.build_lib)
|
|
538
|
rustext.build('' if self.inplace else self.build_lib)
|
|
539
|
|
|
539
|
|
|
540
|
return build_ext.build_extensions(self)
|
|
540
|
return build_ext.build_extensions(self)
|
|
541
|
|
|
541
|
|
|
542
|
def build_extension(self, ext):
|
|
542
|
def build_extension(self, ext):
|
|
543
|
if (
|
|
543
|
if (
|
|
544
|
self.distribution.rust
|
|
544
|
self.distribution.rust
|
|
545
|
and self.rust
|
|
545
|
and self.rust
|
|
546
|
and isinstance(ext, RustExtension)
|
|
546
|
and isinstance(ext, RustExtension)
|
|
547
|
):
|
|
547
|
):
|
|
548
|
ext.rustbuild()
|
|
548
|
ext.rustbuild()
|
|
549
|
try:
|
|
549
|
try:
|
|
550
|
build_ext.build_extension(self, ext)
|
|
550
|
build_ext.build_extension(self, ext)
|
|
551
|
except CCompilerError:
|
|
551
|
except CCompilerError:
|
|
552
|
if not getattr(ext, 'optional', False):
|
|
552
|
if not getattr(ext, 'optional', False):
|
|
553
|
raise
|
|
553
|
raise
|
|
554
|
log.warn(
|
|
554
|
log.warn(
|
|
555
|
"Failed to build optional extension '%s' (skipping)", ext.name
|
|
555
|
"Failed to build optional extension '%s' (skipping)", ext.name
|
|
556
|
)
|
|
556
|
)
|
|
557
|
|
|
557
|
|
|
558
|
|
|
558
|
|
|
559
|
class hgbuildscripts(build_scripts):
|
|
559
|
class hgbuildscripts(build_scripts):
|
|
560
|
def run(self):
|
|
560
|
def run(self):
|
|
561
|
if os.name != 'nt' or self.distribution.pure:
|
|
561
|
if os.name != 'nt' or self.distribution.pure:
|
|
562
|
return build_scripts.run(self)
|
|
562
|
return build_scripts.run(self)
|
|
563
|
|
|
563
|
|
|
564
|
exebuilt = False
|
|
564
|
exebuilt = False
|
|
565
|
try:
|
|
565
|
try:
|
|
566
|
self.run_command('build_hgexe')
|
|
566
|
self.run_command('build_hgexe')
|
|
567
|
exebuilt = True
|
|
567
|
exebuilt = True
|
|
568
|
except (DistutilsError, CCompilerError):
|
|
568
|
except (DistutilsError, CCompilerError):
|
|
569
|
log.warn('failed to build optional hg.exe')
|
|
569
|
log.warn('failed to build optional hg.exe')
|
|
570
|
|
|
570
|
|
|
571
|
if exebuilt:
|
|
571
|
if exebuilt:
|
|
572
|
# Copying hg.exe to the scripts build directory ensures it is
|
|
572
|
# Copying hg.exe to the scripts build directory ensures it is
|
|
573
|
# installed by the install_scripts command.
|
|
573
|
# installed by the install_scripts command.
|
|
574
|
hgexecommand = self.get_finalized_command('build_hgexe')
|
|
574
|
hgexecommand = self.get_finalized_command('build_hgexe')
|
|
575
|
dest = os.path.join(self.build_dir, 'hg.exe')
|
|
575
|
dest = os.path.join(self.build_dir, 'hg.exe')
|
|
576
|
self.mkpath(self.build_dir)
|
|
576
|
self.mkpath(self.build_dir)
|
|
577
|
self.copy_file(hgexecommand.hgexepath, dest)
|
|
577
|
self.copy_file(hgexecommand.hgexepath, dest)
|
|
578
|
|
|
578
|
|
|
579
|
# Remove hg.bat because it is redundant with hg.exe.
|
|
579
|
# Remove hg.bat because it is redundant with hg.exe.
|
|
580
|
self.scripts.remove('contrib/win32/hg.bat')
|
|
580
|
self.scripts.remove('contrib/win32/hg.bat')
|
|
581
|
|
|
581
|
|
|
582
|
return build_scripts.run(self)
|
|
582
|
return build_scripts.run(self)
|
|
583
|
|
|
583
|
|
|
584
|
|
|
584
|
|
|
585
|
class hgbuildpy(build_py):
|
|
585
|
class hgbuildpy(build_py):
|
|
586
|
def finalize_options(self):
|
|
586
|
def finalize_options(self):
|
|
587
|
build_py.finalize_options(self)
|
|
587
|
build_py.finalize_options(self)
|
|
588
|
|
|
588
|
|
|
589
|
if self.distribution.pure:
|
|
589
|
if self.distribution.pure:
|
|
590
|
self.distribution.ext_modules = []
|
|
590
|
self.distribution.ext_modules = []
|
|
591
|
elif self.distribution.cffi:
|
|
591
|
elif self.distribution.cffi:
|
|
592
|
from mercurial.cffi import (
|
|
592
|
from mercurial.cffi import (
|
|
593
|
bdiffbuild,
|
|
593
|
bdiffbuild,
|
|
594
|
mpatchbuild,
|
|
594
|
mpatchbuild,
|
|
595
|
)
|
|
595
|
)
|
|
596
|
|
|
596
|
|
|
597
|
exts = [
|
|
597
|
exts = [
|
|
598
|
mpatchbuild.ffi.distutils_extension(),
|
|
598
|
mpatchbuild.ffi.distutils_extension(),
|
|
599
|
bdiffbuild.ffi.distutils_extension(),
|
|
599
|
bdiffbuild.ffi.distutils_extension(),
|
|
600
|
]
|
|
600
|
]
|
|
601
|
# cffi modules go here
|
|
601
|
# cffi modules go here
|
|
602
|
if sys.platform == 'darwin':
|
|
602
|
if sys.platform == 'darwin':
|
|
603
|
from mercurial.cffi import osutilbuild
|
|
603
|
from mercurial.cffi import osutilbuild
|
|
604
|
|
|
604
|
|
|
605
|
exts.append(osutilbuild.ffi.distutils_extension())
|
|
605
|
exts.append(osutilbuild.ffi.distutils_extension())
|
|
606
|
self.distribution.ext_modules = exts
|
|
606
|
self.distribution.ext_modules = exts
|
|
607
|
else:
|
|
607
|
else:
|
|
608
|
h = os.path.join(get_python_inc(), 'Python.h')
|
|
608
|
h = os.path.join(get_python_inc(), 'Python.h')
|
|
609
|
if not os.path.exists(h):
|
|
609
|
if not os.path.exists(h):
|
|
610
|
raise SystemExit(
|
|
610
|
raise SystemExit(
|
|
611
|
'Python headers are required to build '
|
|
611
|
'Python headers are required to build '
|
|
612
|
'Mercurial but weren\'t found in %s' % h
|
|
612
|
'Mercurial but weren\'t found in %s' % h
|
|
613
|
)
|
|
613
|
)
|
|
614
|
|
|
614
|
|
|
615
|
def run(self):
|
|
615
|
def run(self):
|
|
616
|
basepath = os.path.join(self.build_lib, 'mercurial')
|
|
616
|
basepath = os.path.join(self.build_lib, 'mercurial')
|
|
617
|
self.mkpath(basepath)
|
|
617
|
self.mkpath(basepath)
|
|
618
|
|
|
618
|
|
|
619
|
rust = self.distribution.rust
|
|
619
|
rust = self.distribution.rust
|
|
620
|
if self.distribution.pure:
|
|
620
|
if self.distribution.pure:
|
|
621
|
modulepolicy = 'py'
|
|
621
|
modulepolicy = 'py'
|
|
622
|
elif self.build_lib == '.':
|
|
622
|
elif self.build_lib == '.':
|
|
623
|
# in-place build should run without rebuilding and Rust extensions
|
|
623
|
# in-place build should run without rebuilding and Rust extensions
|
|
624
|
modulepolicy = 'rust+c-allow' if rust else 'allow'
|
|
624
|
modulepolicy = 'rust+c-allow' if rust else 'allow'
|
|
625
|
else:
|
|
625
|
else:
|
|
626
|
modulepolicy = 'rust+c' if rust else 'c'
|
|
626
|
modulepolicy = 'rust+c' if rust else 'c'
|
|
627
|
|
|
627
|
|
|
628
|
content = b''.join(
|
|
628
|
content = b''.join(
|
|
629
|
[
|
|
629
|
[
|
|
630
|
b'# this file is autogenerated by setup.py\n',
|
|
630
|
b'# this file is autogenerated by setup.py\n',
|
|
631
|
b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
|
|
631
|
b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
|
|
632
|
]
|
|
632
|
]
|
|
633
|
)
|
|
633
|
)
|
|
634
|
write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
|
|
634
|
write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
|
|
635
|
|
|
635
|
|
|
636
|
build_py.run(self)
|
|
636
|
build_py.run(self)
|
|
637
|
|
|
637
|
|
|
638
|
|
|
638
|
|
|
639
|
class buildhgextindex(Command):
|
|
639
|
class buildhgextindex(Command):
|
|
640
|
description = 'generate prebuilt index of hgext (for frozen package)'
|
|
640
|
description = 'generate prebuilt index of hgext (for frozen package)'
|
|
641
|
user_options = []
|
|
641
|
user_options = []
|
|
642
|
_indexfilename = 'hgext/__index__.py'
|
|
642
|
_indexfilename = 'hgext/__index__.py'
|
|
643
|
|
|
643
|
|
|
644
|
def initialize_options(self):
|
|
644
|
def initialize_options(self):
|
|
645
|
pass
|
|
645
|
pass
|
|
646
|
|
|
646
|
|
|
647
|
def finalize_options(self):
|
|
647
|
def finalize_options(self):
|
|
648
|
pass
|
|
648
|
pass
|
|
649
|
|
|
649
|
|
|
650
|
def run(self):
|
|
650
|
def run(self):
|
|
651
|
if os.path.exists(self._indexfilename):
|
|
651
|
if os.path.exists(self._indexfilename):
|
|
652
|
with open(self._indexfilename, 'w') as f:
|
|
652
|
with open(self._indexfilename, 'w') as f:
|
|
653
|
f.write('# empty\n')
|
|
653
|
f.write('# empty\n')
|
|
654
|
|
|
654
|
|
|
655
|
# here no extension enabled, disabled() lists up everything
|
|
655
|
# here no extension enabled, disabled() lists up everything
|
|
656
|
code = (
|
|
656
|
code = (
|
|
657
|
'import pprint; from mercurial import extensions; '
|
|
657
|
'import pprint; from mercurial import extensions; '
|
|
658
|
'ext = extensions.disabled();'
|
|
658
|
'ext = extensions.disabled();'
|
|
659
|
'ext.pop("__index__", None);'
|
|
659
|
'ext.pop("__index__", None);'
|
|
660
|
'pprint.pprint(ext)'
|
|
660
|
'pprint.pprint(ext)'
|
|
661
|
)
|
|
661
|
)
|
|
662
|
returncode, out, err = runcmd(
|
|
662
|
returncode, out, err = runcmd(
|
|
663
|
[sys.executable, '-c', code], localhgenv()
|
|
663
|
[sys.executable, '-c', code], localhgenv()
|
|
664
|
)
|
|
664
|
)
|
|
665
|
if err or returncode != 0:
|
|
665
|
if err or returncode != 0:
|
|
666
|
raise DistutilsExecError(err)
|
|
666
|
raise DistutilsExecError(err)
|
|
667
|
|
|
667
|
|
|
668
|
with open(self._indexfilename, 'wb') as f:
|
|
668
|
with open(self._indexfilename, 'wb') as f:
|
|
669
|
f.write(b'# this file is autogenerated by setup.py\n')
|
|
669
|
f.write(b'# this file is autogenerated by setup.py\n')
|
|
670
|
f.write(b'docs = ')
|
|
670
|
f.write(b'docs = ')
|
|
671
|
f.write(out)
|
|
671
|
f.write(out)
|
|
672
|
|
|
672
|
|
|
673
|
|
|
673
|
|
|
674
|
class buildhgexe(build_ext):
|
|
674
|
class buildhgexe(build_ext):
|
|
675
|
description = 'compile hg.exe from mercurial/exewrapper.c'
|
|
675
|
description = 'compile hg.exe from mercurial/exewrapper.c'
|
|
676
|
user_options = build_ext.user_options + [
|
|
676
|
user_options = build_ext.user_options + [
|
|
677
|
(
|
|
677
|
(
|
|
678
|
'long-paths-support',
|
|
678
|
'long-paths-support',
|
|
679
|
None,
|
|
679
|
None,
|
|
680
|
'enable support for long paths on '
|
|
680
|
'enable support for long paths on '
|
|
681
|
'Windows (off by default and '
|
|
681
|
'Windows (off by default and '
|
|
682
|
'experimental)',
|
|
682
|
'experimental)',
|
|
683
|
),
|
|
683
|
),
|
|
684
|
]
|
|
684
|
]
|
|
685
|
|
|
685
|
|
|
686
|
LONG_PATHS_MANIFEST = """
|
|
686
|
LONG_PATHS_MANIFEST = """
|
|
687
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
687
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
688
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
|
688
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
|
689
|
<application>
|
|
689
|
<application>
|
|
690
|
<windowsSettings
|
|
690
|
<windowsSettings
|
|
691
|
xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
|
691
|
xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
|
692
|
<ws2:longPathAware>true</ws2:longPathAware>
|
|
692
|
<ws2:longPathAware>true</ws2:longPathAware>
|
|
693
|
</windowsSettings>
|
|
693
|
</windowsSettings>
|
|
694
|
</application>
|
|
694
|
</application>
|
|
695
|
</assembly>"""
|
|
695
|
</assembly>"""
|
|
696
|
|
|
696
|
|
|
697
|
def initialize_options(self):
|
|
697
|
def initialize_options(self):
|
|
698
|
build_ext.initialize_options(self)
|
|
698
|
build_ext.initialize_options(self)
|
|
699
|
self.long_paths_support = False
|
|
699
|
self.long_paths_support = False
|
|
700
|
|
|
700
|
|
|
701
|
def build_extensions(self):
|
|
701
|
def build_extensions(self):
|
|
702
|
if os.name != 'nt':
|
|
702
|
if os.name != 'nt':
|
|
703
|
return
|
|
703
|
return
|
|
704
|
if isinstance(self.compiler, HackedMingw32CCompiler):
|
|
704
|
if isinstance(self.compiler, HackedMingw32CCompiler):
|
|
705
|
self.compiler.compiler_so = self.compiler.compiler # no -mdll
|
|
705
|
self.compiler.compiler_so = self.compiler.compiler # no -mdll
|
|
706
|
self.compiler.dll_libraries = [] # no -lmsrvc90
|
|
706
|
self.compiler.dll_libraries = [] # no -lmsrvc90
|
|
707
|
|
|
707
|
|
|
708
|
pythonlib = None
|
|
708
|
pythonlib = None
|
|
709
|
|
|
709
|
|
|
710
|
dir = os.path.dirname(self.get_ext_fullpath('dummy'))
|
|
710
|
dir = os.path.dirname(self.get_ext_fullpath('dummy'))
|
|
711
|
self.hgtarget = os.path.join(dir, 'hg')
|
|
711
|
self.hgtarget = os.path.join(dir, 'hg')
|
|
712
|
|
|
712
|
|
|
713
|
if getattr(sys, 'dllhandle', None):
|
|
713
|
if getattr(sys, 'dllhandle', None):
|
|
714
|
# Different Python installs can have different Python library
|
|
714
|
# Different Python installs can have different Python library
|
|
715
|
# names. e.g. the official CPython distribution uses pythonXY.dll
|
|
715
|
# names. e.g. the official CPython distribution uses pythonXY.dll
|
|
716
|
# and MinGW uses libpythonX.Y.dll.
|
|
716
|
# and MinGW uses libpythonX.Y.dll.
|
|
717
|
_kernel32 = ctypes.windll.kernel32
|
|
717
|
_kernel32 = ctypes.windll.kernel32
|
|
718
|
_kernel32.GetModuleFileNameA.argtypes = [
|
|
718
|
_kernel32.GetModuleFileNameA.argtypes = [
|
|
719
|
ctypes.c_void_p,
|
|
719
|
ctypes.c_void_p,
|
|
720
|
ctypes.c_void_p,
|
|
720
|
ctypes.c_void_p,
|
|
721
|
ctypes.c_ulong,
|
|
721
|
ctypes.c_ulong,
|
|
722
|
]
|
|
722
|
]
|
|
723
|
_kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
|
|
723
|
_kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
|
|
724
|
size = 1000
|
|
724
|
size = 1000
|
|
725
|
buf = ctypes.create_string_buffer(size + 1)
|
|
725
|
buf = ctypes.create_string_buffer(size + 1)
|
|
726
|
filelen = _kernel32.GetModuleFileNameA(
|
|
726
|
filelen = _kernel32.GetModuleFileNameA(
|
|
727
|
sys.dllhandle, ctypes.byref(buf), size
|
|
727
|
sys.dllhandle, ctypes.byref(buf), size
|
|
728
|
)
|
|
728
|
)
|
|
729
|
|
|
729
|
|
|
730
|
if filelen > 0 and filelen != size:
|
|
730
|
if filelen > 0 and filelen != size:
|
|
731
|
dllbasename = os.path.basename(buf.value)
|
|
731
|
dllbasename = os.path.basename(buf.value)
|
|
732
|
if not dllbasename.lower().endswith(b'.dll'):
|
|
732
|
if not dllbasename.lower().endswith(b'.dll'):
|
|
733
|
raise SystemExit(
|
|
733
|
raise SystemExit(
|
|
734
|
'Python DLL does not end with .dll: %s' % dllbasename
|
|
734
|
'Python DLL does not end with .dll: %s' % dllbasename
|
|
735
|
)
|
|
735
|
)
|
|
736
|
pythonlib = dllbasename[:-4]
|
|
736
|
pythonlib = dllbasename[:-4]
|
|
737
|
|
|
737
|
|
|
738
|
# Copy the pythonXY.dll next to the binary so that it runs
|
|
738
|
# Copy the pythonXY.dll next to the binary so that it runs
|
|
739
|
# without tampering with PATH.
|
|
739
|
# without tampering with PATH.
|
|
740
|
dest = os.path.join(
|
|
740
|
dest = os.path.join(
|
|
741
|
os.path.dirname(self.hgtarget),
|
|
741
|
os.path.dirname(self.hgtarget),
|
|
742
|
os.fsdecode(dllbasename),
|
|
742
|
os.fsdecode(dllbasename),
|
|
743
|
)
|
|
743
|
)
|
|
744
|
|
|
744
|
|
|
745
|
if not os.path.exists(dest):
|
|
745
|
if not os.path.exists(dest):
|
|
746
|
shutil.copy(buf.value, dest)
|
|
746
|
shutil.copy(buf.value, dest)
|
|
747
|
|
|
747
|
|
|
748
|
# Also overwrite python3.dll so that hgext.git is usable.
|
|
748
|
# Also overwrite python3.dll so that hgext.git is usable.
|
|
749
|
# TODO: also handle the MSYS flavor
|
|
749
|
# TODO: also handle the MSYS flavor
|
|
750
|
python_x = os.path.join(
|
|
750
|
python_x = os.path.join(
|
|
751
|
os.path.dirname(os.fsdecode(buf.value)),
|
|
751
|
os.path.dirname(os.fsdecode(buf.value)),
|
|
752
|
"python3.dll",
|
|
752
|
"python3.dll",
|
|
753
|
)
|
|
753
|
)
|
|
754
|
|
|
754
|
|
|
755
|
if os.path.exists(python_x):
|
|
755
|
if os.path.exists(python_x):
|
|
756
|
dest = os.path.join(
|
|
756
|
dest = os.path.join(
|
|
757
|
os.path.dirname(self.hgtarget),
|
|
757
|
os.path.dirname(self.hgtarget),
|
|
758
|
os.path.basename(python_x),
|
|
758
|
os.path.basename(python_x),
|
|
759
|
)
|
|
759
|
)
|
|
760
|
|
|
760
|
|
|
761
|
shutil.copy(python_x, dest)
|
|
761
|
shutil.copy(python_x, dest)
|
|
762
|
|
|
762
|
|
|
763
|
if not pythonlib:
|
|
763
|
if not pythonlib:
|
|
764
|
log.warn(
|
|
764
|
log.warn(
|
|
765
|
'could not determine Python DLL filename; assuming pythonXY'
|
|
765
|
'could not determine Python DLL filename; assuming pythonXY'
|
|
766
|
)
|
|
766
|
)
|
|
767
|
|
|
767
|
|
|
768
|
hv = sys.hexversion
|
|
768
|
hv = sys.hexversion
|
|
769
|
pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
|
|
769
|
pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
|
|
770
|
|
|
770
|
|
|
771
|
log.info('using %s as Python library name' % pythonlib)
|
|
771
|
log.info('using %s as Python library name' % pythonlib)
|
|
772
|
with open('mercurial/hgpythonlib.h', 'wb') as f:
|
|
772
|
with open('mercurial/hgpythonlib.h', 'wb') as f:
|
|
773
|
f.write(b'/* this file is autogenerated by setup.py */\n')
|
|
773
|
f.write(b'/* this file is autogenerated by setup.py */\n')
|
|
774
|
f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
|
|
774
|
f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
|
|
775
|
|
|
775
|
|
|
776
|
objects = self.compiler.compile(
|
|
776
|
objects = self.compiler.compile(
|
|
777
|
['mercurial/exewrapper.c'],
|
|
777
|
['mercurial/exewrapper.c'],
|
|
778
|
output_dir=self.build_temp,
|
|
778
|
output_dir=self.build_temp,
|
|
779
|
macros=[('_UNICODE', None), ('UNICODE', None)],
|
|
779
|
macros=[('_UNICODE', None), ('UNICODE', None)],
|
|
780
|
)
|
|
780
|
)
|
|
781
|
self.compiler.link_executable(
|
|
781
|
self.compiler.link_executable(
|
|
782
|
objects, self.hgtarget, libraries=[], output_dir=self.build_temp
|
|
782
|
objects, self.hgtarget, libraries=[], output_dir=self.build_temp
|
|
783
|
)
|
|
783
|
)
|
|
784
|
if self.long_paths_support:
|
|
784
|
if self.long_paths_support:
|
|
785
|
self.addlongpathsmanifest()
|
|
785
|
self.addlongpathsmanifest()
|
|
786
|
|
|
786
|
|
|
787
|
def addlongpathsmanifest(self):
|
|
787
|
def addlongpathsmanifest(self):
|
|
788
|
r"""Add manifest pieces so that hg.exe understands long paths
|
|
788
|
r"""Add manifest pieces so that hg.exe understands long paths
|
|
789
|
|
|
789
|
|
|
790
|
This is an EXPERIMENTAL feature, use with care.
|
|
790
|
This is an EXPERIMENTAL feature, use with care.
|
|
791
|
To enable long paths support, one needs to do two things:
|
|
791
|
To enable long paths support, one needs to do two things:
|
|
792
|
- build Mercurial with --long-paths-support option
|
|
792
|
- build Mercurial with --long-paths-support option
|
|
793
|
- change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
|
|
793
|
- change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
|
|
794
|
LongPathsEnabled to have value 1.
|
|
794
|
LongPathsEnabled to have value 1.
|
|
795
|
|
|
795
|
|
|
796
|
Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
|
|
796
|
Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
|
|
797
|
it happens because Mercurial uses mt.exe circa 2008, which is not
|
|
797
|
it happens because Mercurial uses mt.exe circa 2008, which is not
|
|
798
|
yet aware of long paths support in the manifest (I think so at least).
|
|
798
|
yet aware of long paths support in the manifest (I think so at least).
|
|
799
|
This does not stop mt.exe from embedding/merging the XML properly.
|
|
799
|
This does not stop mt.exe from embedding/merging the XML properly.
|
|
800
|
|
|
800
|
|
|
801
|
Why resource #1 should be used for .exe manifests? I don't know and
|
|
801
|
Why resource #1 should be used for .exe manifests? I don't know and
|
|
802
|
wasn't able to find an explanation for mortals. But it seems to work.
|
|
802
|
wasn't able to find an explanation for mortals. But it seems to work.
|
|
803
|
"""
|
|
803
|
"""
|
|
804
|
exefname = self.compiler.executable_filename(self.hgtarget)
|
|
804
|
exefname = self.compiler.executable_filename(self.hgtarget)
|
|
805
|
fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
|
|
805
|
fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
|
|
806
|
os.close(fdauto)
|
|
806
|
os.close(fdauto)
|
|
807
|
with open(manfname, 'w') as f:
|
|
807
|
with open(manfname, 'w') as f:
|
|
808
|
f.write(self.LONG_PATHS_MANIFEST)
|
|
808
|
f.write(self.LONG_PATHS_MANIFEST)
|
|
809
|
log.info("long paths manifest is written to '%s'" % manfname)
|
|
809
|
log.info("long paths manifest is written to '%s'" % manfname)
|
|
810
|
inputresource = '-inputresource:%s;#1' % exefname
|
|
810
|
inputresource = '-inputresource:%s;#1' % exefname
|
|
811
|
outputresource = '-outputresource:%s;#1' % exefname
|
|
811
|
outputresource = '-outputresource:%s;#1' % exefname
|
|
812
|
log.info("running mt.exe to update hg.exe's manifest in-place")
|
|
812
|
log.info("running mt.exe to update hg.exe's manifest in-place")
|
|
813
|
# supplying both -manifest and -inputresource to mt.exe makes
|
|
813
|
# supplying both -manifest and -inputresource to mt.exe makes
|
|
814
|
# it merge the embedded and supplied manifests in the -outputresource
|
|
814
|
# it merge the embedded and supplied manifests in the -outputresource
|
|
815
|
self.spawn(
|
|
815
|
self.spawn(
|
|
816
|
[
|
|
816
|
[
|
|
817
|
'mt.exe',
|
|
817
|
'mt.exe',
|
|
818
|
'-nologo',
|
|
818
|
'-nologo',
|
|
819
|
'-manifest',
|
|
819
|
'-manifest',
|
|
820
|
manfname,
|
|
820
|
manfname,
|
|
821
|
inputresource,
|
|
821
|
inputresource,
|
|
822
|
outputresource,
|
|
822
|
outputresource,
|
|
823
|
]
|
|
823
|
]
|
|
824
|
)
|
|
824
|
)
|
|
825
|
log.info("done updating hg.exe's manifest")
|
|
825
|
log.info("done updating hg.exe's manifest")
|
|
826
|
os.remove(manfname)
|
|
826
|
os.remove(manfname)
|
|
827
|
|
|
827
|
|
|
828
|
@property
|
|
828
|
@property
|
|
829
|
def hgexepath(self):
|
|
829
|
def hgexepath(self):
|
|
830
|
dir = os.path.dirname(self.get_ext_fullpath('dummy'))
|
|
830
|
dir = os.path.dirname(self.get_ext_fullpath('dummy'))
|
|
831
|
return os.path.join(self.build_temp, dir, 'hg.exe')
|
|
831
|
return os.path.join(self.build_temp, dir, 'hg.exe')
|
|
832
|
|
|
832
|
|
|
833
|
|
|
833
|
|
|
834
|
class hgbuilddoc(Command):
|
|
834
|
class hgbuilddoc(Command):
|
|
835
|
description = 'build documentation'
|
|
835
|
description = 'build documentation'
|
|
836
|
user_options = [
|
|
836
|
user_options = [
|
|
837
|
('man', None, 'generate man pages'),
|
|
837
|
('man', None, 'generate man pages'),
|
|
838
|
('html', None, 'generate html pages'),
|
|
838
|
('html', None, 'generate html pages'),
|
|
839
|
]
|
|
839
|
]
|
|
840
|
|
|
840
|
|
|
841
|
def initialize_options(self):
|
|
841
|
def initialize_options(self):
|
|
842
|
self.man = None
|
|
842
|
self.man = None
|
|
843
|
self.html = None
|
|
843
|
self.html = None
|
|
844
|
|
|
844
|
|
|
845
|
def finalize_options(self):
|
|
845
|
def finalize_options(self):
|
|
846
|
# If --man or --html are set, only generate what we're told to.
|
|
846
|
# If --man or --html are set, only generate what we're told to.
|
|
847
|
# Otherwise generate everything.
|
|
847
|
# Otherwise generate everything.
|
|
848
|
have_subset = self.man is not None or self.html is not None
|
|
848
|
have_subset = self.man is not None or self.html is not None
|
|
849
|
|
|
849
|
|
|
850
|
if have_subset:
|
|
850
|
if have_subset:
|
|
851
|
self.man = True if self.man else False
|
|
851
|
self.man = True if self.man else False
|
|
852
|
self.html = True if self.html else False
|
|
852
|
self.html = True if self.html else False
|
|
853
|
else:
|
|
853
|
else:
|
|
854
|
self.man = True
|
|
854
|
self.man = True
|
|
855
|
self.html = True
|
|
855
|
self.html = True
|
|
856
|
|
|
856
|
|
|
857
|
def run(self):
|
|
857
|
def run(self):
|
|
858
|
def normalizecrlf(p):
|
|
858
|
def normalizecrlf(p):
|
|
859
|
with open(p, 'rb') as fh:
|
|
859
|
with open(p, 'rb') as fh:
|
|
860
|
orig = fh.read()
|
|
860
|
orig = fh.read()
|
|
861
|
|
|
861
|
|
|
862
|
if b'\r\n' not in orig:
|
|
862
|
if b'\r\n' not in orig:
|
|
863
|
return
|
|
863
|
return
|
|
864
|
|
|
864
|
|
|
865
|
log.info('normalizing %s to LF line endings' % p)
|
|
865
|
log.info('normalizing %s to LF line endings' % p)
|
|
866
|
with open(p, 'wb') as fh:
|
|
866
|
with open(p, 'wb') as fh:
|
|
867
|
fh.write(orig.replace(b'\r\n', b'\n'))
|
|
867
|
fh.write(orig.replace(b'\r\n', b'\n'))
|
|
868
|
|
|
868
|
|
|
869
|
def gentxt(root):
|
|
869
|
def gentxt(root):
|
|
870
|
txt = 'doc/%s.txt' % root
|
|
870
|
txt = 'doc/%s.txt' % root
|
|
871
|
log.info('generating %s' % txt)
|
|
871
|
log.info('generating %s' % txt)
|
|
872
|
res, out, err = runcmd(
|
|
872
|
res, out, err = runcmd(
|
|
873
|
[sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
|
|
873
|
[sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
|
|
874
|
)
|
|
874
|
)
|
|
875
|
if res:
|
|
875
|
if res:
|
|
876
|
raise SystemExit(
|
|
876
|
raise SystemExit(
|
|
877
|
'error running gendoc.py: %s'
|
|
877
|
'error running gendoc.py: %s'
|
|
878
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
878
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
879
|
)
|
|
879
|
)
|
|
880
|
|
|
880
|
|
|
881
|
with open(txt, 'wb') as fh:
|
|
881
|
with open(txt, 'wb') as fh:
|
|
882
|
fh.write(out)
|
|
882
|
fh.write(out)
|
|
883
|
|
|
883
|
|
|
884
|
def gengendoc(root):
|
|
884
|
def gengendoc(root):
|
|
885
|
gendoc = 'doc/%s.gendoc.txt' % root
|
|
885
|
gendoc = 'doc/%s.gendoc.txt' % root
|
|
886
|
|
|
886
|
|
|
887
|
log.info('generating %s' % gendoc)
|
|
887
|
log.info('generating %s' % gendoc)
|
|
888
|
res, out, err = runcmd(
|
|
888
|
res, out, err = runcmd(
|
|
889
|
[sys.executable, 'gendoc.py', '%s.gendoc' % root],
|
|
889
|
[sys.executable, 'gendoc.py', '%s.gendoc' % root],
|
|
890
|
os.environ,
|
|
890
|
os.environ,
|
|
891
|
cwd='doc',
|
|
891
|
cwd='doc',
|
|
892
|
)
|
|
892
|
)
|
|
893
|
if res:
|
|
893
|
if res:
|
|
894
|
raise SystemExit(
|
|
894
|
raise SystemExit(
|
|
895
|
'error running gendoc: %s'
|
|
895
|
'error running gendoc: %s'
|
|
896
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
896
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
897
|
)
|
|
897
|
)
|
|
898
|
|
|
898
|
|
|
899
|
with open(gendoc, 'wb') as fh:
|
|
899
|
with open(gendoc, 'wb') as fh:
|
|
900
|
fh.write(out)
|
|
900
|
fh.write(out)
|
|
901
|
|
|
901
|
|
|
902
|
def genman(root):
|
|
902
|
def genman(root):
|
|
903
|
log.info('generating doc/%s' % root)
|
|
903
|
log.info('generating doc/%s' % root)
|
|
904
|
res, out, err = runcmd(
|
|
904
|
res, out, err = runcmd(
|
|
905
|
[
|
|
905
|
[
|
|
906
|
sys.executable,
|
|
906
|
sys.executable,
|
|
907
|
'runrst',
|
|
907
|
'runrst',
|
|
908
|
'hgmanpage',
|
|
908
|
'hgmanpage',
|
|
909
|
'--halt',
|
|
909
|
'--halt',
|
|
910
|
'warning',
|
|
910
|
'warning',
|
|
911
|
'--strip-elements-with-class',
|
|
911
|
'--strip-elements-with-class',
|
|
912
|
'htmlonly',
|
|
912
|
'htmlonly',
|
|
913
|
'%s.txt' % root,
|
|
913
|
'%s.txt' % root,
|
|
914
|
root,
|
|
914
|
root,
|
|
915
|
],
|
|
915
|
],
|
|
916
|
os.environ,
|
|
916
|
os.environ,
|
|
917
|
cwd='doc',
|
|
917
|
cwd='doc',
|
|
918
|
)
|
|
918
|
)
|
|
919
|
if res:
|
|
919
|
if res:
|
|
920
|
raise SystemExit(
|
|
920
|
raise SystemExit(
|
|
921
|
'error running runrst: %s'
|
|
921
|
'error running runrst: %s'
|
|
922
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
922
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
923
|
)
|
|
923
|
)
|
|
924
|
|
|
924
|
|
|
925
|
normalizecrlf('doc/%s' % root)
|
|
925
|
normalizecrlf('doc/%s' % root)
|
|
926
|
|
|
926
|
|
|
927
|
def genhtml(root):
|
|
927
|
def genhtml(root):
|
|
928
|
log.info('generating doc/%s.html' % root)
|
|
928
|
log.info('generating doc/%s.html' % root)
|
|
929
|
res, out, err = runcmd(
|
|
929
|
res, out, err = runcmd(
|
|
930
|
[
|
|
930
|
[
|
|
931
|
sys.executable,
|
|
931
|
sys.executable,
|
|
932
|
'runrst',
|
|
932
|
'runrst',
|
|
933
|
'html',
|
|
933
|
'html',
|
|
934
|
'--halt',
|
|
934
|
'--halt',
|
|
935
|
'warning',
|
|
935
|
'warning',
|
|
936
|
'--link-stylesheet',
|
|
936
|
'--link-stylesheet',
|
|
937
|
'--stylesheet-path',
|
|
937
|
'--stylesheet-path',
|
|
938
|
'style.css',
|
|
938
|
'style.css',
|
|
939
|
'%s.txt' % root,
|
|
939
|
'%s.txt' % root,
|
|
940
|
'%s.html' % root,
|
|
940
|
'%s.html' % root,
|
|
941
|
],
|
|
941
|
],
|
|
942
|
os.environ,
|
|
942
|
os.environ,
|
|
943
|
cwd='doc',
|
|
943
|
cwd='doc',
|
|
944
|
)
|
|
944
|
)
|
|
945
|
if res:
|
|
945
|
if res:
|
|
946
|
raise SystemExit(
|
|
946
|
raise SystemExit(
|
|
947
|
'error running runrst: %s'
|
|
947
|
'error running runrst: %s'
|
|
948
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
948
|
% '\n'.join([sysstr(out), sysstr(err)])
|
|
949
|
)
|
|
949
|
)
|
|
950
|
|
|
950
|
|
|
951
|
normalizecrlf('doc/%s.html' % root)
|
|
951
|
normalizecrlf('doc/%s.html' % root)
|
|
952
|
|
|
952
|
|
|
953
|
# This logic is duplicated in doc/Makefile.
|
|
953
|
# This logic is duplicated in doc/Makefile.
|
|
954
|
sources = {
|
|
954
|
sources = {
|
|
955
|
f
|
|
955
|
f
|
|
956
|
for f in os.listdir('mercurial/helptext')
|
|
956
|
for f in os.listdir('mercurial/helptext')
|
|
957
|
if re.search(r'[0-9]\.txt$', f)
|
|
957
|
if re.search(r'[0-9]\.txt$', f)
|
|
958
|
}
|
|
958
|
}
|
|
959
|
|
|
959
|
|
|
960
|
# common.txt is a one-off.
|
|
960
|
# common.txt is a one-off.
|
|
961
|
gentxt('common')
|
|
961
|
gentxt('common')
|
|
962
|
|
|
962
|
|
|
963
|
for source in sorted(sources):
|
|
963
|
for source in sorted(sources):
|
|
964
|
assert source[-4:] == '.txt'
|
|
964
|
assert source[-4:] == '.txt'
|
|
965
|
root = source[:-4]
|
|
965
|
root = source[:-4]
|
|
966
|
|
|
966
|
|
|
967
|
gentxt(root)
|
|
967
|
gentxt(root)
|
|
968
|
gengendoc(root)
|
|
968
|
gengendoc(root)
|
|
969
|
|
|
969
|
|
|
970
|
if self.man:
|
|
970
|
if self.man:
|
|
971
|
genman(root)
|
|
971
|
genman(root)
|
|
972
|
if self.html:
|
|
972
|
if self.html:
|
|
973
|
genhtml(root)
|
|
973
|
genhtml(root)
|
|
974
|
|
|
974
|
|
|
975
|
|
|
975
|
|
|
976
|
class hginstall(install):
|
|
976
|
class hginstall(install):
|
|
977
|
|
|
977
|
|
|
978
|
user_options = install.user_options + [
|
|
978
|
user_options = install.user_options + [
|
|
979
|
(
|
|
979
|
(
|
|
980
|
'old-and-unmanageable',
|
|
980
|
'old-and-unmanageable',
|
|
981
|
None,
|
|
981
|
None,
|
|
982
|
'noop, present for eggless setuptools compat',
|
|
982
|
'noop, present for eggless setuptools compat',
|
|
983
|
),
|
|
983
|
),
|
|
984
|
(
|
|
984
|
(
|
|
985
|
'single-version-externally-managed',
|
|
985
|
'single-version-externally-managed',
|
|
986
|
None,
|
|
986
|
None,
|
|
987
|
'noop, present for eggless setuptools compat',
|
|
987
|
'noop, present for eggless setuptools compat',
|
|
988
|
),
|
|
988
|
),
|
|
989
|
]
|
|
989
|
]
|
|
990
|
|
|
990
|
|
|
991
|
# Also helps setuptools not be sad while we refuse to create eggs.
|
|
991
|
# Also helps setuptools not be sad while we refuse to create eggs.
|
|
992
|
single_version_externally_managed = True
|
|
992
|
single_version_externally_managed = True
|
|
993
|
|
|
993
|
|
|
994
|
def get_sub_commands(self):
|
|
994
|
def get_sub_commands(self):
|
|
995
|
# Screen out egg related commands to prevent egg generation. But allow
|
|
995
|
# Screen out egg related commands to prevent egg generation. But allow
|
|
996
|
# mercurial.egg-info generation, since that is part of modern
|
|
996
|
# mercurial.egg-info generation, since that is part of modern
|
|
997
|
# packaging.
|
|
997
|
# packaging.
|
|
998
|
excl = {'bdist_egg'}
|
|
998
|
excl = {'bdist_egg'}
|
|
999
|
return filter(lambda x: x not in excl, install.get_sub_commands(self))
|
|
999
|
return filter(lambda x: x not in excl, install.get_sub_commands(self))
|
|
1000
|
|
|
1000
|
|
|
1001
|
|
|
1001
|
|
|
1002
|
class hginstalllib(install_lib):
|
|
1002
|
class hginstalllib(install_lib):
|
|
1003
|
"""
|
|
1003
|
"""
|
|
1004
|
This is a specialization of install_lib that replaces the copy_file used
|
|
1004
|
This is a specialization of install_lib that replaces the copy_file used
|
|
1005
|
there so that it supports setting the mode of files after copying them,
|
|
1005
|
there so that it supports setting the mode of files after copying them,
|
|
1006
|
instead of just preserving the mode that the files originally had. If your
|
|
1006
|
instead of just preserving the mode that the files originally had. If your
|
|
1007
|
system has a umask of something like 027, preserving the permissions when
|
|
1007
|
system has a umask of something like 027, preserving the permissions when
|
|
1008
|
copying will lead to a broken install.
|
|
1008
|
copying will lead to a broken install.
|
|
1009
|
|
|
1009
|
|
|
1010
|
Note that just passing keep_permissions=False to copy_file would be
|
|
1010
|
Note that just passing keep_permissions=False to copy_file would be
|
|
1011
|
insufficient, as it might still be applying a umask.
|
|
1011
|
insufficient, as it might still be applying a umask.
|
|
1012
|
"""
|
|
1012
|
"""
|
|
1013
|
|
|
1013
|
|
|
1014
|
def run(self):
|
|
1014
|
def run(self):
|
|
1015
|
realcopyfile = file_util.copy_file
|
|
1015
|
realcopyfile = file_util.copy_file
|
|
1016
|
|
|
1016
|
|
|
1017
|
def copyfileandsetmode(*args, **kwargs):
|
|
1017
|
def copyfileandsetmode(*args, **kwargs):
|
|
1018
|
src, dst = args[0], args[1]
|
|
1018
|
src, dst = args[0], args[1]
|
|
1019
|
dst, copied = realcopyfile(*args, **kwargs)
|
|
1019
|
dst, copied = realcopyfile(*args, **kwargs)
|
|
1020
|
if copied:
|
|
1020
|
if copied:
|
|
1021
|
st = os.stat(src)
|
|
1021
|
st = os.stat(src)
|
|
1022
|
# Persist executable bit (apply it to group and other if user
|
|
1022
|
# Persist executable bit (apply it to group and other if user
|
|
1023
|
# has it)
|
|
1023
|
# has it)
|
|
1024
|
if st[stat.ST_MODE] & stat.S_IXUSR:
|
|
1024
|
if st[stat.ST_MODE] & stat.S_IXUSR:
|
|
1025
|
setmode = int('0755', 8)
|
|
1025
|
setmode = int('0755', 8)
|
|
1026
|
else:
|
|
1026
|
else:
|
|
1027
|
setmode = int('0644', 8)
|
|
1027
|
setmode = int('0644', 8)
|
|
1028
|
m = stat.S_IMODE(st[stat.ST_MODE])
|
|
1028
|
m = stat.S_IMODE(st[stat.ST_MODE])
|
|
1029
|
m = (m & ~int('0777', 8)) | setmode
|
|
1029
|
m = (m & ~int('0777', 8)) | setmode
|
|
1030
|
os.chmod(dst, m)
|
|
1030
|
os.chmod(dst, m)
|
|
1031
|
|
|
1031
|
|
|
1032
|
file_util.copy_file = copyfileandsetmode
|
|
1032
|
file_util.copy_file = copyfileandsetmode
|
|
1033
|
try:
|
|
1033
|
try:
|
|
1034
|
install_lib.run(self)
|
|
1034
|
install_lib.run(self)
|
|
1035
|
finally:
|
|
1035
|
finally:
|
|
1036
|
file_util.copy_file = realcopyfile
|
|
1036
|
file_util.copy_file = realcopyfile
|
|
1037
|
|
|
1037
|
|
|
1038
|
|
|
1038
|
|
|
1039
|
class hginstallscripts(install_scripts):
|
|
1039
|
class hginstallscripts(install_scripts):
|
|
1040
|
"""
|
|
1040
|
"""
|
|
1041
|
This is a specialization of install_scripts that replaces the @LIBDIR@ with
|
|
1041
|
This is a specialization of install_scripts that replaces the @LIBDIR@ with
|
|
1042
|
the configured directory for modules. If possible, the path is made relative
|
|
1042
|
the configured directory for modules. If possible, the path is made relative
|
|
1043
|
to the directory for scripts.
|
|
1043
|
to the directory for scripts.
|
|
1044
|
"""
|
|
1044
|
"""
|
|
1045
|
|
|
1045
|
|
|
1046
|
def initialize_options(self):
|
|
1046
|
def initialize_options(self):
|
|
1047
|
install_scripts.initialize_options(self)
|
|
1047
|
install_scripts.initialize_options(self)
|
|
1048
|
|
|
1048
|
|
|
1049
|
self.install_lib = None
|
|
1049
|
self.install_lib = None
|
|
1050
|
|
|
1050
|
|
|
1051
|
def finalize_options(self):
|
|
1051
|
def finalize_options(self):
|
|
1052
|
install_scripts.finalize_options(self)
|
|
1052
|
install_scripts.finalize_options(self)
|
|
1053
|
self.set_undefined_options('install', ('install_lib', 'install_lib'))
|
|
1053
|
self.set_undefined_options('install', ('install_lib', 'install_lib'))
|
|
1054
|
|
|
1054
|
|
|
1055
|
def run(self):
|
|
1055
|
def run(self):
|
|
1056
|
install_scripts.run(self)
|
|
1056
|
install_scripts.run(self)
|
|
1057
|
|
|
1057
|
|
|
1058
|
# It only makes sense to replace @LIBDIR@ with the install path if
|
|
1058
|
# It only makes sense to replace @LIBDIR@ with the install path if
|
|
1059
|
# the install path is known. For wheels, the logic below calculates
|
|
1059
|
# the install path is known. For wheels, the logic below calculates
|
|
1060
|
# the libdir to be "../..". This is because the internal layout of a
|
|
1060
|
# the libdir to be "../..". This is because the internal layout of a
|
|
1061
|
# wheel archive looks like:
|
|
1061
|
# wheel archive looks like:
|
|
1062
|
#
|
|
1062
|
#
|
|
1063
|
# mercurial-3.6.1.data/scripts/hg
|
|
1063
|
# mercurial-3.6.1.data/scripts/hg
|
|
1064
|
# mercurial/__init__.py
|
|
1064
|
# mercurial/__init__.py
|
|
1065
|
#
|
|
1065
|
#
|
|
1066
|
# When installing wheels, the subdirectories of the "<pkg>.data"
|
|
1066
|
# When installing wheels, the subdirectories of the "<pkg>.data"
|
|
1067
|
# directory are translated to system local paths and files therein
|
|
1067
|
# directory are translated to system local paths and files therein
|
|
1068
|
# are copied in place. The mercurial/* files are installed into the
|
|
1068
|
# are copied in place. The mercurial/* files are installed into the
|
|
1069
|
# site-packages directory. However, the site-packages directory
|
|
1069
|
# site-packages directory. However, the site-packages directory
|
|
1070
|
# isn't known until wheel install time. This means we have no clue
|
|
1070
|
# isn't known until wheel install time. This means we have no clue
|
|
1071
|
# at wheel generation time what the installed site-packages directory
|
|
1071
|
# at wheel generation time what the installed site-packages directory
|
|
1072
|
# will be. And, wheels don't appear to provide the ability to register
|
|
1072
|
# will be. And, wheels don't appear to provide the ability to register
|
|
1073
|
# custom code to run during wheel installation. This all means that
|
|
1073
|
# custom code to run during wheel installation. This all means that
|
|
1074
|
# we can't reliably set the libdir in wheels: the default behavior
|
|
1074
|
# we can't reliably set the libdir in wheels: the default behavior
|
|
1075
|
# of looking in sys.path must do.
|
|
1075
|
# of looking in sys.path must do.
|
|
1076
|
|
|
1076
|
|
|
1077
|
if (
|
|
1077
|
if (
|
|
1078
|
os.path.splitdrive(self.install_dir)[0]
|
|
1078
|
os.path.splitdrive(self.install_dir)[0]
|
|
1079
|
!= os.path.splitdrive(self.install_lib)[0]
|
|
1079
|
!= os.path.splitdrive(self.install_lib)[0]
|
|
1080
|
):
|
|
1080
|
):
|
|
1081
|
# can't make relative paths from one drive to another, so use an
|
|
1081
|
# can't make relative paths from one drive to another, so use an
|
|
1082
|
# absolute path instead
|
|
1082
|
# absolute path instead
|
|
1083
|
libdir = self.install_lib
|
|
1083
|
libdir = self.install_lib
|
|
1084
|
else:
|
|
1084
|
else:
|
|
1085
|
libdir = os.path.relpath(self.install_lib, self.install_dir)
|
|
1085
|
libdir = os.path.relpath(self.install_lib, self.install_dir)
|
|
1086
|
|
|
1086
|
|
|
1087
|
for outfile in self.outfiles:
|
|
1087
|
for outfile in self.outfiles:
|
|
1088
|
with open(outfile, 'rb') as fp:
|
|
1088
|
with open(outfile, 'rb') as fp:
|
|
1089
|
data = fp.read()
|
|
1089
|
data = fp.read()
|
|
1090
|
|
|
1090
|
|
|
1091
|
# skip binary files
|
|
1091
|
# skip binary files
|
|
1092
|
if b'\0' in data:
|
|
1092
|
if b'\0' in data:
|
|
1093
|
continue
|
|
1093
|
continue
|
|
1094
|
|
|
1094
|
|
|
1095
|
# During local installs, the shebang will be rewritten to the final
|
|
1095
|
# During local installs, the shebang will be rewritten to the final
|
|
1096
|
# install path. During wheel packaging, the shebang has a special
|
|
1096
|
# install path. During wheel packaging, the shebang has a special
|
|
1097
|
# value.
|
|
1097
|
# value.
|
|
1098
|
if data.startswith(b'#!python'):
|
|
1098
|
if data.startswith(b'#!python'):
|
|
1099
|
log.info(
|
|
1099
|
log.info(
|
|
1100
|
'not rewriting @LIBDIR@ in %s because install path '
|
|
1100
|
'not rewriting @LIBDIR@ in %s because install path '
|
|
1101
|
'not known' % outfile
|
|
1101
|
'not known' % outfile
|
|
1102
|
)
|
|
1102
|
)
|
|
1103
|
continue
|
|
1103
|
continue
|
|
1104
|
|
|
1104
|
|
|
1105
|
data = data.replace(b'@LIBDIR@', libdir.encode('unicode_escape'))
|
|
1105
|
data = data.replace(b'@LIBDIR@', libdir.encode('unicode_escape'))
|
|
1106
|
with open(outfile, 'wb') as fp:
|
|
1106
|
with open(outfile, 'wb') as fp:
|
|
1107
|
fp.write(data)
|
|
1107
|
fp.write(data)
|
|
1108
|
|
|
1108
|
|
|
1109
|
|
|
1109
|
|
|
1110
|
# virtualenv installs custom distutils/__init__.py and
|
|
1110
|
# virtualenv installs custom distutils/__init__.py and
|
|
1111
|
# distutils/distutils.cfg files which essentially proxy back to the
|
|
1111
|
# distutils/distutils.cfg files which essentially proxy back to the
|
|
1112
|
# "real" distutils in the main Python install. The presence of this
|
|
1112
|
# "real" distutils in the main Python install. The presence of this
|
|
1113
|
# directory causes py2exe to pick up the "hacked" distutils package
|
|
1113
|
# directory causes py2exe to pick up the "hacked" distutils package
|
|
1114
|
# from the virtualenv and "import distutils" will fail from the py2exe
|
|
1114
|
# from the virtualenv and "import distutils" will fail from the py2exe
|
|
1115
|
# build because the "real" distutils files can't be located.
|
|
1115
|
# build because the "real" distutils files can't be located.
|
|
1116
|
#
|
|
1116
|
#
|
|
1117
|
# We work around this by monkeypatching the py2exe code finding Python
|
|
1117
|
# We work around this by monkeypatching the py2exe code finding Python
|
|
1118
|
# modules to replace the found virtualenv distutils modules with the
|
|
1118
|
# modules to replace the found virtualenv distutils modules with the
|
|
1119
|
# original versions via filesystem scanning. This is a bit hacky. But
|
|
1119
|
# original versions via filesystem scanning. This is a bit hacky. But
|
|
1120
|
# it allows us to use virtualenvs for py2exe packaging, which is more
|
|
1120
|
# it allows us to use virtualenvs for py2exe packaging, which is more
|
|
1121
|
# deterministic and reproducible.
|
|
1121
|
# deterministic and reproducible.
|
|
1122
|
#
|
|
1122
|
#
|
|
1123
|
# It's worth noting that the common StackOverflow suggestions for this
|
|
1123
|
# It's worth noting that the common StackOverflow suggestions for this
|
|
1124
|
# problem involve copying the original distutils files into the
|
|
1124
|
# problem involve copying the original distutils files into the
|
|
1125
|
# virtualenv or into the staging directory after setup() is invoked.
|
|
1125
|
# virtualenv or into the staging directory after setup() is invoked.
|
|
1126
|
# The former is very brittle and can easily break setup(). Our hacking
|
|
1126
|
# The former is very brittle and can easily break setup(). Our hacking
|
|
1127
|
# of the found modules routine has a similar result as copying the files
|
|
1127
|
# of the found modules routine has a similar result as copying the files
|
|
1128
|
# manually. But it makes fewer assumptions about how py2exe works and
|
|
1128
|
# manually. But it makes fewer assumptions about how py2exe works and
|
|
1129
|
# is less brittle.
|
|
1129
|
# is less brittle.
|
|
1130
|
|
|
1130
|
|
|
1131
|
# This only catches virtualenvs made with virtualenv (as opposed to
|
|
1131
|
# This only catches virtualenvs made with virtualenv (as opposed to
|
|
1132
|
# venv, which is likely what Python 3 uses).
|
|
1132
|
# venv, which is likely what Python 3 uses).
|
|
1133
|
py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
|
|
1133
|
py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
|
|
1134
|
|
|
1134
|
|
|
1135
|
if py2exehacked:
|
|
1135
|
if py2exehacked:
|
|
1136
|
from distutils.command.py2exe import py2exe as buildpy2exe
|
|
1136
|
from distutils.command.py2exe import py2exe as buildpy2exe
|
|
1137
|
from py2exe.mf import Module as py2exemodule
|
|
1137
|
from py2exe.mf import Module as py2exemodule
|
|
1138
|
|
|
1138
|
|
|
1139
|
class hgbuildpy2exe(buildpy2exe):
|
|
1139
|
class hgbuildpy2exe(buildpy2exe):
|
|
1140
|
def find_needed_modules(self, mf, files, modules):
|
|
1140
|
def find_needed_modules(self, mf, files, modules):
|
|
1141
|
res = buildpy2exe.find_needed_modules(self, mf, files, modules)
|
|
1141
|
res = buildpy2exe.find_needed_modules(self, mf, files, modules)
|
|
1142
|
|
|
1142
|
|
|
1143
|
# Replace virtualenv's distutils modules with the real ones.
|
|
1143
|
# Replace virtualenv's distutils modules with the real ones.
|
|
1144
|
modules = {}
|
|
1144
|
modules = {}
|
|
1145
|
for k, v in res.modules.items():
|
|
1145
|
for k, v in res.modules.items():
|
|
1146
|
if k != 'distutils' and not k.startswith('distutils.'):
|
|
1146
|
if k != 'distutils' and not k.startswith('distutils.'):
|
|
1147
|
modules[k] = v
|
|
1147
|
modules[k] = v
|
|
1148
|
|
|
1148
|
|
|
1149
|
res.modules = modules
|
|
1149
|
res.modules = modules
|
|
1150
|
|
|
1150
|
|
|
1151
|
import opcode
|
|
1151
|
import opcode
|
|
1152
|
|
|
1152
|
|
|
1153
|
distutilsreal = os.path.join(
|
|
1153
|
distutilsreal = os.path.join(
|
|
1154
|
os.path.dirname(opcode.__file__), 'distutils'
|
|
1154
|
os.path.dirname(opcode.__file__), 'distutils'
|
|
1155
|
)
|
|
1155
|
)
|
|
1156
|
|
|
1156
|
|
|
1157
|
for root, dirs, files in os.walk(distutilsreal):
|
|
1157
|
for root, dirs, files in os.walk(distutilsreal):
|
|
1158
|
for f in sorted(files):
|
|
1158
|
for f in sorted(files):
|
|
1159
|
if not f.endswith('.py'):
|
|
1159
|
if not f.endswith('.py'):
|
|
1160
|
continue
|
|
1160
|
continue
|
|
1161
|
|
|
1161
|
|
|
1162
|
full = os.path.join(root, f)
|
|
1162
|
full = os.path.join(root, f)
|
|
1163
|
|
|
1163
|
|
|
1164
|
parents = ['distutils']
|
|
1164
|
parents = ['distutils']
|
|
1165
|
|
|
1165
|
|
|
1166
|
if root != distutilsreal:
|
|
1166
|
if root != distutilsreal:
|
|
1167
|
rel = os.path.relpath(root, distutilsreal)
|
|
1167
|
rel = os.path.relpath(root, distutilsreal)
|
|
1168
|
parents.extend(p for p in rel.split(os.sep))
|
|
1168
|
parents.extend(p for p in rel.split(os.sep))
|
|
1169
|
|
|
1169
|
|
|
1170
|
modname = '%s.%s' % ('.'.join(parents), f[:-3])
|
|
1170
|
modname = '%s.%s' % ('.'.join(parents), f[:-3])
|
|
1171
|
|
|
1171
|
|
|
1172
|
if modname.startswith('distutils.tests.'):
|
|
1172
|
if modname.startswith('distutils.tests.'):
|
|
1173
|
continue
|
|
1173
|
continue
|
|
1174
|
|
|
1174
|
|
|
1175
|
if modname.endswith('.__init__'):
|
|
1175
|
if modname.endswith('.__init__'):
|
|
1176
|
modname = modname[: -len('.__init__')]
|
|
1176
|
modname = modname[: -len('.__init__')]
|
|
1177
|
path = os.path.dirname(full)
|
|
1177
|
path = os.path.dirname(full)
|
|
1178
|
else:
|
|
1178
|
else:
|
|
1179
|
path = None
|
|
1179
|
path = None
|
|
1180
|
|
|
1180
|
|
|
1181
|
res.modules[modname] = py2exemodule(
|
|
1181
|
res.modules[modname] = py2exemodule(
|
|
1182
|
modname, full, path=path
|
|
1182
|
modname, full, path=path
|
|
1183
|
)
|
|
1183
|
)
|
|
1184
|
|
|
1184
|
|
|
1185
|
if 'distutils' not in res.modules:
|
|
1185
|
if 'distutils' not in res.modules:
|
|
1186
|
raise SystemExit('could not find distutils modules')
|
|
1186
|
raise SystemExit('could not find distutils modules')
|
|
1187
|
|
|
1187
|
|
|
1188
|
return res
|
|
1188
|
return res
|
|
1189
|
|
|
1189
|
|
|
1190
|
|
|
1190
|
|
|
1191
|
cmdclass = {
|
|
1191
|
cmdclass = {
|
|
1192
|
'build': hgbuild,
|
|
1192
|
'build': hgbuild,
|
|
1193
|
'build_doc': hgbuilddoc,
|
|
1193
|
'build_doc': hgbuilddoc,
|
|
1194
|
'build_mo': hgbuildmo,
|
|
1194
|
'build_mo': hgbuildmo,
|
|
1195
|
'build_ext': hgbuildext,
|
|
1195
|
'build_ext': hgbuildext,
|
|
1196
|
'build_py': hgbuildpy,
|
|
1196
|
'build_py': hgbuildpy,
|
|
1197
|
'build_scripts': hgbuildscripts,
|
|
1197
|
'build_scripts': hgbuildscripts,
|
|
1198
|
'build_hgextindex': buildhgextindex,
|
|
1198
|
'build_hgextindex': buildhgextindex,
|
|
1199
|
'install': hginstall,
|
|
1199
|
'install': hginstall,
|
|
1200
|
'install_lib': hginstalllib,
|
|
1200
|
'install_lib': hginstalllib,
|
|
1201
|
'install_scripts': hginstallscripts,
|
|
1201
|
'install_scripts': hginstallscripts,
|
|
1202
|
'build_hgexe': buildhgexe,
|
|
1202
|
'build_hgexe': buildhgexe,
|
|
1203
|
}
|
|
1203
|
}
|
|
1204
|
|
|
1204
|
|
|
1205
|
if py2exehacked:
|
|
1205
|
if py2exehacked:
|
|
1206
|
cmdclass['py2exe'] = hgbuildpy2exe
|
|
1206
|
cmdclass['py2exe'] = hgbuildpy2exe
|
|
1207
|
|
|
1207
|
|
|
1208
|
packages = [
|
|
1208
|
packages = [
|
|
1209
|
'mercurial',
|
|
1209
|
'mercurial',
|
|
1210
|
'mercurial.cext',
|
|
1210
|
'mercurial.cext',
|
|
1211
|
'mercurial.cffi',
|
|
1211
|
'mercurial.cffi',
|
|
1212
|
'mercurial.defaultrc',
|
|
1212
|
'mercurial.defaultrc',
|
|
1213
|
'mercurial.dirstateutils',
|
|
1213
|
'mercurial.dirstateutils',
|
|
1214
|
'mercurial.helptext',
|
|
1214
|
'mercurial.helptext',
|
|
1215
|
'mercurial.helptext.internals',
|
|
1215
|
'mercurial.helptext.internals',
|
|
1216
|
'mercurial.hgweb',
|
|
1216
|
'mercurial.hgweb',
|
|
1217
|
'mercurial.interfaces',
|
|
1217
|
'mercurial.interfaces',
|
|
1218
|
'mercurial.pure',
|
|
1218
|
'mercurial.pure',
|
|
1219
|
'mercurial.templates',
|
|
1219
|
'mercurial.templates',
|
|
1220
|
'mercurial.thirdparty',
|
|
1220
|
'mercurial.thirdparty',
|
|
1221
|
'mercurial.thirdparty.attr',
|
|
1221
|
'mercurial.thirdparty.attr',
|
|
1222
|
'mercurial.thirdparty.zope',
|
|
1222
|
'mercurial.thirdparty.zope',
|
|
1223
|
'mercurial.thirdparty.zope.interface',
|
|
1223
|
'mercurial.thirdparty.zope.interface',
|
|
1224
|
'mercurial.upgrade_utils',
|
|
1224
|
'mercurial.upgrade_utils',
|
|
1225
|
'mercurial.utils',
|
|
1225
|
'mercurial.utils',
|
|
1226
|
'mercurial.revlogutils',
|
|
1226
|
'mercurial.revlogutils',
|
|
1227
|
'mercurial.testing',
|
|
1227
|
'mercurial.testing',
|
|
1228
|
'hgext',
|
|
1228
|
'hgext',
|
|
1229
|
'hgext.convert',
|
|
1229
|
'hgext.convert',
|
|
1230
|
'hgext.fsmonitor',
|
|
1230
|
'hgext.fsmonitor',
|
|
1231
|
'hgext.fastannotate',
|
|
1231
|
'hgext.fastannotate',
|
|
1232
|
'hgext.fsmonitor.pywatchman',
|
|
1232
|
'hgext.fsmonitor.pywatchman',
|
|
1233
|
'hgext.git',
|
|
1233
|
'hgext.git',
|
|
1234
|
'hgext.highlight',
|
|
1234
|
'hgext.highlight',
|
|
1235
|
'hgext.hooklib',
|
|
1235
|
'hgext.hooklib',
|
|
1236
|
'hgext.infinitepush',
|
|
1236
|
'hgext.infinitepush',
|
|
1237
|
'hgext.largefiles',
|
|
1237
|
'hgext.largefiles',
|
|
1238
|
'hgext.lfs',
|
|
1238
|
'hgext.lfs',
|
|
1239
|
'hgext.narrow',
|
|
1239
|
'hgext.narrow',
|
|
1240
|
'hgext.remotefilelog',
|
|
1240
|
'hgext.remotefilelog',
|
|
1241
|
'hgext.zeroconf',
|
|
1241
|
'hgext.zeroconf',
|
|
1242
|
'hgext3rd',
|
|
1242
|
'hgext3rd',
|
|
1243
|
'hgdemandimport',
|
|
1243
|
'hgdemandimport',
|
|
1244
|
]
|
|
1244
|
]
|
|
1245
|
|
|
1245
|
|
|
1246
|
for name in os.listdir(os.path.join('mercurial', 'templates')):
|
|
1246
|
for name in os.listdir(os.path.join('mercurial', 'templates')):
|
|
1247
|
if name != '__pycache__' and os.path.isdir(
|
|
1247
|
if name != '__pycache__' and os.path.isdir(
|
|
1248
|
os.path.join('mercurial', 'templates', name)
|
|
1248
|
os.path.join('mercurial', 'templates', name)
|
|
1249
|
):
|
|
1249
|
):
|
|
1250
|
packages.append('mercurial.templates.%s' % name)
|
|
1250
|
packages.append('mercurial.templates.%s' % name)
|
|
1251
|
|
|
1251
|
|
|
1252
|
if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
|
|
1252
|
if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
|
|
1253
|
# py2exe can't cope with namespace packages very well, so we have to
|
|
1253
|
# py2exe can't cope with namespace packages very well, so we have to
|
|
1254
|
# install any hgext3rd.* extensions that we want in the final py2exe
|
|
1254
|
# install any hgext3rd.* extensions that we want in the final py2exe
|
|
1255
|
# image here. This is gross, but you gotta do what you gotta do.
|
|
1255
|
# image here. This is gross, but you gotta do what you gotta do.
|
|
1256
|
packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
|
|
1256
|
packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
|
|
1257
|
|
|
1257
|
|
|
1258
|
common_depends = [
|
|
1258
|
common_depends = [
|
|
1259
|
'mercurial/bitmanipulation.h',
|
|
1259
|
'mercurial/bitmanipulation.h',
|
|
1260
|
'mercurial/compat.h',
|
|
1260
|
'mercurial/compat.h',
|
|
1261
|
'mercurial/cext/util.h',
|
|
1261
|
'mercurial/cext/util.h',
|
|
1262
|
]
|
|
1262
|
]
|
|
1263
|
common_include_dirs = ['mercurial']
|
|
1263
|
common_include_dirs = ['mercurial']
|
|
1264
|
|
|
1264
|
|
|
1265
|
common_cflags = []
|
|
1265
|
common_cflags = []
|
|
1266
|
|
|
1266
|
|
|
1267
|
# MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
|
|
1267
|
# MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
|
|
1268
|
# makes declarations not at the top of a scope in the headers.
|
|
1268
|
# makes declarations not at the top of a scope in the headers.
|
|
1269
|
if os.name != 'nt' and sys.version_info[1] < 9:
|
|
1269
|
if os.name != 'nt' and sys.version_info[1] < 9:
|
|
1270
|
common_cflags = ['-Werror=declaration-after-statement']
|
|
1270
|
common_cflags = ['-Werror=declaration-after-statement']
|
|
1271
|
|
|
1271
|
|
|
1272
|
osutil_cflags = []
|
|
1272
|
osutil_cflags = []
|
|
1273
|
osutil_ldflags = []
|
|
1273
|
osutil_ldflags = []
|
|
1274
|
|
|
1274
|
|
|
1275
|
# platform specific macros
|
|
1275
|
# platform specific macros
|
|
1276
|
for plat, func in [('bsd', 'setproctitle')]:
|
|
1276
|
for plat, func in [('bsd', 'setproctitle')]:
|
|
1277
|
if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
|
|
1277
|
if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
|
|
1278
|
osutil_cflags.append('-DHAVE_%s' % func.upper())
|
|
1278
|
osutil_cflags.append('-DHAVE_%s' % func.upper())
|
|
1279
|
|
|
1279
|
|
|
1280
|
for plat, macro, code in [
|
|
1280
|
for plat, macro, code in [
|
|
1281
|
(
|
|
1281
|
(
|
|
1282
|
'bsd|darwin',
|
|
1282
|
'bsd|darwin',
|
|
1283
|
'BSD_STATFS',
|
|
1283
|
'BSD_STATFS',
|
|
1284
|
'''
|
|
1284
|
'''
|
|
1285
|
#include <sys/param.h>
|
|
1285
|
#include <sys/param.h>
|
|
1286
|
#include <sys/mount.h>
|
|
1286
|
#include <sys/mount.h>
|
|
1287
|
int main() { struct statfs s; return sizeof(s.f_fstypename); }
|
|
1287
|
int main() { struct statfs s; return sizeof(s.f_fstypename); }
|
|
1288
|
''',
|
|
1288
|
''',
|
|
1289
|
),
|
|
1289
|
),
|
|
1290
|
(
|
|
1290
|
(
|
|
1291
|
'linux',
|
|
1291
|
'linux',
|
|
1292
|
'LINUX_STATFS',
|
|
1292
|
'LINUX_STATFS',
|
|
1293
|
'''
|
|
1293
|
'''
|
|
1294
|
#include <linux/magic.h>
|
|
1294
|
#include <linux/magic.h>
|
|
1295
|
#include <sys/vfs.h>
|
|
1295
|
#include <sys/vfs.h>
|
|
1296
|
int main() { struct statfs s; return sizeof(s.f_type); }
|
|
1296
|
int main() { struct statfs s; return sizeof(s.f_type); }
|
|
1297
|
''',
|
|
1297
|
''',
|
|
1298
|
),
|
|
1298
|
),
|
|
1299
|
]:
|
|
1299
|
]:
|
|
1300
|
if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
|
|
1300
|
if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
|
|
1301
|
osutil_cflags.append('-DHAVE_%s' % macro)
|
|
1301
|
osutil_cflags.append('-DHAVE_%s' % macro)
|
|
1302
|
|
|
1302
|
|
|
1303
|
if sys.platform == 'darwin':
|
|
1303
|
if sys.platform == 'darwin':
|
|
1304
|
osutil_ldflags += ['-framework', 'ApplicationServices']
|
|
1304
|
osutil_ldflags += ['-framework', 'ApplicationServices']
|
|
1305
|
|
|
1305
|
|
|
1306
|
if sys.platform == 'sunos5':
|
|
1306
|
if sys.platform == 'sunos5':
|
|
1307
|
osutil_ldflags += ['-lsocket']
|
|
1307
|
osutil_ldflags += ['-lsocket']
|
|
1308
|
|
|
1308
|
|
|
1309
|
xdiff_srcs = [
|
|
1309
|
xdiff_srcs = [
|
|
1310
|
'mercurial/thirdparty/xdiff/xdiffi.c',
|
|
1310
|
'mercurial/thirdparty/xdiff/xdiffi.c',
|
|
1311
|
'mercurial/thirdparty/xdiff/xprepare.c',
|
|
1311
|
'mercurial/thirdparty/xdiff/xprepare.c',
|
|
1312
|
'mercurial/thirdparty/xdiff/xutils.c',
|
|
1312
|
'mercurial/thirdparty/xdiff/xutils.c',
|
|
1313
|
]
|
|
1313
|
]
|
|
1314
|
|
|
1314
|
|
|
1315
|
xdiff_headers = [
|
|
1315
|
xdiff_headers = [
|
|
1316
|
'mercurial/thirdparty/xdiff/xdiff.h',
|
|
1316
|
'mercurial/thirdparty/xdiff/xdiff.h',
|
|
1317
|
'mercurial/thirdparty/xdiff/xdiffi.h',
|
|
1317
|
'mercurial/thirdparty/xdiff/xdiffi.h',
|
|
1318
|
'mercurial/thirdparty/xdiff/xinclude.h',
|
|
1318
|
'mercurial/thirdparty/xdiff/xinclude.h',
|
|
1319
|
'mercurial/thirdparty/xdiff/xmacros.h',
|
|
1319
|
'mercurial/thirdparty/xdiff/xmacros.h',
|
|
1320
|
'mercurial/thirdparty/xdiff/xprepare.h',
|
|
1320
|
'mercurial/thirdparty/xdiff/xprepare.h',
|
|
1321
|
'mercurial/thirdparty/xdiff/xtypes.h',
|
|
1321
|
'mercurial/thirdparty/xdiff/xtypes.h',
|
|
1322
|
'mercurial/thirdparty/xdiff/xutils.h',
|
|
1322
|
'mercurial/thirdparty/xdiff/xutils.h',
|
|
1323
|
]
|
|
1323
|
]
|
|
1324
|
|
|
1324
|
|
|
1325
|
|
|
1325
|
|
|
1326
|
class RustCompilationError(CCompilerError):
|
|
1326
|
class RustCompilationError(CCompilerError):
|
|
1327
|
"""Exception class for Rust compilation errors."""
|
|
1327
|
"""Exception class for Rust compilation errors."""
|
|
1328
|
|
|
1328
|
|
|
1329
|
|
|
1329
|
|
|
1330
|
class RustExtension(Extension):
|
|
1330
|
class RustExtension(Extension):
|
|
1331
|
"""Base classes for concrete Rust Extension classes."""
|
|
1331
|
"""Base classes for concrete Rust Extension classes."""
|
|
1332
|
|
|
1332
|
|
|
1333
|
rusttargetdir = os.path.join('rust', 'target', 'release')
|
|
1333
|
rusttargetdir = os.path.join('rust', 'target', 'release')
|
|
1334
|
|
|
1334
|
|
|
1335
|
def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
|
|
1335
|
def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
|
|
1336
|
Extension.__init__(self, mpath, sources, **kw)
|
|
1336
|
Extension.__init__(self, mpath, sources, **kw)
|
|
1337
|
srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
|
|
1337
|
srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
|
|
1338
|
|
|
1338
|
|
|
1339
|
# adding Rust source and control files to depends so that the extension
|
|
1339
|
# adding Rust source and control files to depends so that the extension
|
|
1340
|
# gets rebuilt if they've changed
|
|
1340
|
# gets rebuilt if they've changed
|
|
1341
|
self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
|
|
1341
|
self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
|
|
1342
|
cargo_lock = os.path.join(srcdir, 'Cargo.lock')
|
|
1342
|
cargo_lock = os.path.join(srcdir, 'Cargo.lock')
|
|
1343
|
if os.path.exists(cargo_lock):
|
|
1343
|
if os.path.exists(cargo_lock):
|
|
1344
|
self.depends.append(cargo_lock)
|
|
1344
|
self.depends.append(cargo_lock)
|
|
1345
|
for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
|
|
1345
|
for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
|
|
1346
|
self.depends.extend(
|
|
1346
|
self.depends.extend(
|
|
1347
|
os.path.join(dirpath, fname)
|
|
1347
|
os.path.join(dirpath, fname)
|
|
1348
|
for fname in fnames
|
|
1348
|
for fname in fnames
|
|
1349
|
if os.path.splitext(fname)[1] == '.rs'
|
|
1349
|
if os.path.splitext(fname)[1] == '.rs'
|
|
1350
|
)
|
|
1350
|
)
|
|
1351
|
|
|
1351
|
|
|
1352
|
@staticmethod
|
|
1352
|
@staticmethod
|
|
1353
|
def rustdylibsuffix():
|
|
1353
|
def rustdylibsuffix():
|
|
1354
|
"""Return the suffix for shared libraries produced by rustc.
|
|
1354
|
"""Return the suffix for shared libraries produced by rustc.
|
|
1355
|
|
|
1355
|
|
|
1356
|
See also: https://doc.rust-lang.org/reference/linkage.html
|
|
1356
|
See also: https://doc.rust-lang.org/reference/linkage.html
|
|
1357
|
"""
|
|
1357
|
"""
|
|
1358
|
if sys.platform == 'darwin':
|
|
1358
|
if sys.platform == 'darwin':
|
|
1359
|
return '.dylib'
|
|
1359
|
return '.dylib'
|
|
1360
|
elif os.name == 'nt':
|
|
1360
|
elif os.name == 'nt':
|
|
1361
|
return '.dll'
|
|
1361
|
return '.dll'
|
|
1362
|
else:
|
|
1362
|
else:
|
|
1363
|
return '.so'
|
|
1363
|
return '.so'
|
|
1364
|
|
|
1364
|
|
|
1365
|
def rustbuild(self):
|
|
1365
|
def rustbuild(self):
|
|
1366
|
env = os.environ.copy()
|
|
1366
|
env = os.environ.copy()
|
|
1367
|
if 'HGTEST_RESTOREENV' in env:
|
|
1367
|
if 'HGTEST_RESTOREENV' in env:
|
|
1368
|
# Mercurial tests change HOME to a temporary directory,
|
|
1368
|
# Mercurial tests change HOME to a temporary directory,
|
|
1369
|
# but, if installed with rustup, the Rust toolchain needs
|
|
1369
|
# but, if installed with rustup, the Rust toolchain needs
|
|
1370
|
# HOME to be correct (otherwise the 'no default toolchain'
|
|
1370
|
# HOME to be correct (otherwise the 'no default toolchain'
|
|
1371
|
# error message is issued and the build fails).
|
|
1371
|
# error message is issued and the build fails).
|
|
1372
|
# This happens currently with test-hghave.t, which does
|
|
1372
|
# This happens currently with test-hghave.t, which does
|
|
1373
|
# invoke this build.
|
|
1373
|
# invoke this build.
|
|
1374
|
|
|
1374
|
|
|
1375
|
# Unix only fix (os.path.expanduser not really reliable if
|
|
1375
|
# Unix only fix (os.path.expanduser not really reliable if
|
|
1376
|
# HOME is shadowed like this)
|
|
1376
|
# HOME is shadowed like this)
|
|
1377
|
import pwd
|
|
1377
|
import pwd
|
|
1378
|
|
|
1378
|
|
|
1379
|
env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
|
|
1379
|
env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
|
|
1380
|
|
|
1380
|
|
|
1381
|
cargocmd = ['cargo', 'rustc', '--release']
|
|
1381
|
cargocmd = ['cargo', 'rustc', '--release']
|
|
1382
|
|
|
1382
|
|
|
1383
|
feature_flags = ['python3']
|
|
|
|
|
1384
|
|
|
|
|
|
1385
|
cargocmd.append('--no-default-features')
|
|
|
|
|
1386
|
|
|
|
|
|
1387
|
rust_features = env.get("HG_RUST_FEATURES")
|
|
1383
|
rust_features = env.get("HG_RUST_FEATURES")
|
|
1388
|
if rust_features:
|
|
1384
|
if rust_features:
|
|
1389
|
feature_flags.append(rust_features)
|
|
1385
|
cargocmd.extend(('--features', rust_features))
|
|
1390
|
|
|
|
|
|
1391
|
cargocmd.extend(('--features', " ".join(feature_flags)))
|
|
|
|
|
1392
|
|
|
1386
|
|
|
1393
|
cargocmd.append('--')
|
|
1387
|
cargocmd.append('--')
|
|
1394
|
if sys.platform == 'darwin':
|
|
1388
|
if sys.platform == 'darwin':
|
|
1395
|
cargocmd.extend(
|
|
1389
|
cargocmd.extend(
|
|
1396
|
("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
|
|
1390
|
("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
|
|
1397
|
)
|
|
1391
|
)
|
|
1398
|
try:
|
|
1392
|
try:
|
|
1399
|
subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
|
|
1393
|
subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
|
|
1400
|
except OSError as exc:
|
|
1394
|
except OSError as exc:
|
|
1401
|
if exc.errno == errno.ENOENT:
|
|
1395
|
if exc.errno == errno.ENOENT:
|
|
1402
|
raise RustCompilationError("Cargo not found")
|
|
1396
|
raise RustCompilationError("Cargo not found")
|
|
1403
|
elif exc.errno == errno.EACCES:
|
|
1397
|
elif exc.errno == errno.EACCES:
|
|
1404
|
raise RustCompilationError(
|
|
1398
|
raise RustCompilationError(
|
|
1405
|
"Cargo found, but permission to execute it is denied"
|
|
1399
|
"Cargo found, but permission to execute it is denied"
|
|
1406
|
)
|
|
1400
|
)
|
|
1407
|
else:
|
|
1401
|
else:
|
|
1408
|
raise
|
|
1402
|
raise
|
|
1409
|
except subprocess.CalledProcessError:
|
|
1403
|
except subprocess.CalledProcessError:
|
|
1410
|
raise RustCompilationError(
|
|
1404
|
raise RustCompilationError(
|
|
1411
|
"Cargo failed. Working directory: %r, "
|
|
1405
|
"Cargo failed. Working directory: %r, "
|
|
1412
|
"command: %r, environment: %r"
|
|
1406
|
"command: %r, environment: %r"
|
|
1413
|
% (self.rustsrcdir, cargocmd, env)
|
|
1407
|
% (self.rustsrcdir, cargocmd, env)
|
|
1414
|
)
|
|
1408
|
)
|
|
1415
|
|
|
1409
|
|
|
1416
|
|
|
1410
|
|
|
1417
|
class RustStandaloneExtension(RustExtension):
|
|
1411
|
class RustStandaloneExtension(RustExtension):
|
|
1418
|
def __init__(self, pydottedname, rustcrate, dylibname, **kw):
|
|
1412
|
def __init__(self, pydottedname, rustcrate, dylibname, **kw):
|
|
1419
|
RustExtension.__init__(
|
|
1413
|
RustExtension.__init__(
|
|
1420
|
self, pydottedname, [], dylibname, rustcrate, **kw
|
|
1414
|
self, pydottedname, [], dylibname, rustcrate, **kw
|
|
1421
|
)
|
|
1415
|
)
|
|
1422
|
self.dylibname = dylibname
|
|
1416
|
self.dylibname = dylibname
|
|
1423
|
|
|
1417
|
|
|
1424
|
def build(self, target_dir):
|
|
1418
|
def build(self, target_dir):
|
|
1425
|
self.rustbuild()
|
|
1419
|
self.rustbuild()
|
|
1426
|
target = [target_dir]
|
|
1420
|
target = [target_dir]
|
|
1427
|
target.extend(self.name.split('.'))
|
|
1421
|
target.extend(self.name.split('.'))
|
|
1428
|
target[-1] += DYLIB_SUFFIX
|
|
1422
|
target[-1] += DYLIB_SUFFIX
|
|
1429
|
shutil.copy2(
|
|
1423
|
shutil.copy2(
|
|
1430
|
os.path.join(
|
|
1424
|
os.path.join(
|
|
1431
|
self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
|
|
1425
|
self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
|
|
1432
|
),
|
|
1426
|
),
|
|
1433
|
os.path.join(*target),
|
|
1427
|
os.path.join(*target),
|
|
1434
|
)
|
|
1428
|
)
|
|
1435
|
|
|
1429
|
|
|
1436
|
|
|
1430
|
|
|
1437
|
extmodules = [
|
|
1431
|
extmodules = [
|
|
1438
|
Extension(
|
|
1432
|
Extension(
|
|
1439
|
'mercurial.cext.base85',
|
|
1433
|
'mercurial.cext.base85',
|
|
1440
|
['mercurial/cext/base85.c'],
|
|
1434
|
['mercurial/cext/base85.c'],
|
|
1441
|
include_dirs=common_include_dirs,
|
|
1435
|
include_dirs=common_include_dirs,
|
|
1442
|
extra_compile_args=common_cflags,
|
|
1436
|
extra_compile_args=common_cflags,
|
|
1443
|
depends=common_depends,
|
|
1437
|
depends=common_depends,
|
|
1444
|
),
|
|
1438
|
),
|
|
1445
|
Extension(
|
|
1439
|
Extension(
|
|
1446
|
'mercurial.cext.bdiff',
|
|
1440
|
'mercurial.cext.bdiff',
|
|
1447
|
['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
|
|
1441
|
['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
|
|
1448
|
include_dirs=common_include_dirs,
|
|
1442
|
include_dirs=common_include_dirs,
|
|
1449
|
extra_compile_args=common_cflags,
|
|
1443
|
extra_compile_args=common_cflags,
|
|
1450
|
depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
|
|
1444
|
depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
|
|
1451
|
),
|
|
1445
|
),
|
|
1452
|
Extension(
|
|
1446
|
Extension(
|
|
1453
|
'mercurial.cext.mpatch',
|
|
1447
|
'mercurial.cext.mpatch',
|
|
1454
|
['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
|
|
1448
|
['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
|
|
1455
|
include_dirs=common_include_dirs,
|
|
1449
|
include_dirs=common_include_dirs,
|
|
1456
|
extra_compile_args=common_cflags,
|
|
1450
|
extra_compile_args=common_cflags,
|
|
1457
|
depends=common_depends,
|
|
1451
|
depends=common_depends,
|
|
1458
|
),
|
|
1452
|
),
|
|
1459
|
Extension(
|
|
1453
|
Extension(
|
|
1460
|
'mercurial.cext.parsers',
|
|
1454
|
'mercurial.cext.parsers',
|
|
1461
|
[
|
|
1455
|
[
|
|
1462
|
'mercurial/cext/charencode.c',
|
|
1456
|
'mercurial/cext/charencode.c',
|
|
1463
|
'mercurial/cext/dirs.c',
|
|
1457
|
'mercurial/cext/dirs.c',
|
|
1464
|
'mercurial/cext/manifest.c',
|
|
1458
|
'mercurial/cext/manifest.c',
|
|
1465
|
'mercurial/cext/parsers.c',
|
|
1459
|
'mercurial/cext/parsers.c',
|
|
1466
|
'mercurial/cext/pathencode.c',
|
|
1460
|
'mercurial/cext/pathencode.c',
|
|
1467
|
'mercurial/cext/revlog.c',
|
|
1461
|
'mercurial/cext/revlog.c',
|
|
1468
|
],
|
|
1462
|
],
|
|
1469
|
include_dirs=common_include_dirs,
|
|
1463
|
include_dirs=common_include_dirs,
|
|
1470
|
extra_compile_args=common_cflags,
|
|
1464
|
extra_compile_args=common_cflags,
|
|
1471
|
depends=common_depends
|
|
1465
|
depends=common_depends
|
|
1472
|
+ [
|
|
1466
|
+ [
|
|
1473
|
'mercurial/cext/charencode.h',
|
|
1467
|
'mercurial/cext/charencode.h',
|
|
1474
|
'mercurial/cext/revlog.h',
|
|
1468
|
'mercurial/cext/revlog.h',
|
|
1475
|
],
|
|
1469
|
],
|
|
1476
|
),
|
|
1470
|
),
|
|
1477
|
Extension(
|
|
1471
|
Extension(
|
|
1478
|
'mercurial.cext.osutil',
|
|
1472
|
'mercurial.cext.osutil',
|
|
1479
|
['mercurial/cext/osutil.c'],
|
|
1473
|
['mercurial/cext/osutil.c'],
|
|
1480
|
include_dirs=common_include_dirs,
|
|
1474
|
include_dirs=common_include_dirs,
|
|
1481
|
extra_compile_args=common_cflags + osutil_cflags,
|
|
1475
|
extra_compile_args=common_cflags + osutil_cflags,
|
|
1482
|
extra_link_args=osutil_ldflags,
|
|
1476
|
extra_link_args=osutil_ldflags,
|
|
1483
|
depends=common_depends,
|
|
1477
|
depends=common_depends,
|
|
1484
|
),
|
|
1478
|
),
|
|
1485
|
Extension(
|
|
1479
|
Extension(
|
|
1486
|
'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
|
|
1480
|
'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
|
|
1487
|
[
|
|
1481
|
[
|
|
1488
|
'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
|
|
1482
|
'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
|
|
1489
|
],
|
|
1483
|
],
|
|
1490
|
extra_compile_args=common_cflags,
|
|
1484
|
extra_compile_args=common_cflags,
|
|
1491
|
),
|
|
1485
|
),
|
|
1492
|
Extension(
|
|
1486
|
Extension(
|
|
1493
|
'mercurial.thirdparty.sha1dc',
|
|
1487
|
'mercurial.thirdparty.sha1dc',
|
|
1494
|
[
|
|
1488
|
[
|
|
1495
|
'mercurial/thirdparty/sha1dc/cext.c',
|
|
1489
|
'mercurial/thirdparty/sha1dc/cext.c',
|
|
1496
|
'mercurial/thirdparty/sha1dc/lib/sha1.c',
|
|
1490
|
'mercurial/thirdparty/sha1dc/lib/sha1.c',
|
|
1497
|
'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
|
|
1491
|
'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
|
|
1498
|
],
|
|
1492
|
],
|
|
1499
|
extra_compile_args=common_cflags,
|
|
1493
|
extra_compile_args=common_cflags,
|
|
1500
|
),
|
|
1494
|
),
|
|
1501
|
Extension(
|
|
1495
|
Extension(
|
|
1502
|
'hgext.fsmonitor.pywatchman.bser',
|
|
1496
|
'hgext.fsmonitor.pywatchman.bser',
|
|
1503
|
['hgext/fsmonitor/pywatchman/bser.c'],
|
|
1497
|
['hgext/fsmonitor/pywatchman/bser.c'],
|
|
1504
|
extra_compile_args=common_cflags,
|
|
1498
|
extra_compile_args=common_cflags,
|
|
1505
|
),
|
|
1499
|
),
|
|
1506
|
RustStandaloneExtension(
|
|
1500
|
RustStandaloneExtension(
|
|
1507
|
'mercurial.rustext',
|
|
1501
|
'mercurial.rustext',
|
|
1508
|
'hg-cpython',
|
|
1502
|
'hg-cpython',
|
|
1509
|
'librusthg',
|
|
1503
|
'librusthg',
|
|
1510
|
),
|
|
1504
|
),
|
|
1511
|
]
|
|
1505
|
]
|
|
1512
|
|
|
1506
|
|
|
1513
|
|
|
1507
|
|
|
1514
|
sys.path.insert(0, 'contrib/python-zstandard')
|
|
1508
|
sys.path.insert(0, 'contrib/python-zstandard')
|
|
1515
|
import setup_zstd
|
|
1509
|
import setup_zstd
|
|
1516
|
|
|
1510
|
|
|
1517
|
zstd = setup_zstd.get_c_extension(
|
|
1511
|
zstd = setup_zstd.get_c_extension(
|
|
1518
|
name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
|
|
1512
|
name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
|
|
1519
|
)
|
|
1513
|
)
|
|
1520
|
zstd.extra_compile_args += common_cflags
|
|
1514
|
zstd.extra_compile_args += common_cflags
|
|
1521
|
extmodules.append(zstd)
|
|
1515
|
extmodules.append(zstd)
|
|
1522
|
|
|
1516
|
|
|
1523
|
try:
|
|
1517
|
try:
|
|
1524
|
from distutils import cygwinccompiler
|
|
1518
|
from distutils import cygwinccompiler
|
|
1525
|
|
|
1519
|
|
|
1526
|
# the -mno-cygwin option has been deprecated for years
|
|
1520
|
# the -mno-cygwin option has been deprecated for years
|
|
1527
|
mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
|
|
1521
|
mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
|
|
1528
|
|
|
1522
|
|
|
1529
|
class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
|
|
1523
|
class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
|
|
1530
|
def __init__(self, *args, **kwargs):
|
|
1524
|
def __init__(self, *args, **kwargs):
|
|
1531
|
mingw32compilerclass.__init__(self, *args, **kwargs)
|
|
1525
|
mingw32compilerclass.__init__(self, *args, **kwargs)
|
|
1532
|
for i in 'compiler compiler_so linker_exe linker_so'.split():
|
|
1526
|
for i in 'compiler compiler_so linker_exe linker_so'.split():
|
|
1533
|
try:
|
|
1527
|
try:
|
|
1534
|
getattr(self, i).remove('-mno-cygwin')
|
|
1528
|
getattr(self, i).remove('-mno-cygwin')
|
|
1535
|
except ValueError:
|
|
1529
|
except ValueError:
|
|
1536
|
pass
|
|
1530
|
pass
|
|
1537
|
|
|
1531
|
|
|
1538
|
cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
|
|
1532
|
cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
|
|
1539
|
except ImportError:
|
|
1533
|
except ImportError:
|
|
1540
|
# the cygwinccompiler package is not available on some Python
|
|
1534
|
# the cygwinccompiler package is not available on some Python
|
|
1541
|
# distributions like the ones from the optware project for Synology
|
|
1535
|
# distributions like the ones from the optware project for Synology
|
|
1542
|
# DiskStation boxes
|
|
1536
|
# DiskStation boxes
|
|
1543
|
class HackedMingw32CCompiler(object):
|
|
1537
|
class HackedMingw32CCompiler(object):
|
|
1544
|
pass
|
|
1538
|
pass
|
|
1545
|
|
|
1539
|
|
|
1546
|
|
|
1540
|
|
|
1547
|
if os.name == 'nt':
|
|
1541
|
if os.name == 'nt':
|
|
1548
|
# Allow compiler/linker flags to be added to Visual Studio builds. Passing
|
|
1542
|
# Allow compiler/linker flags to be added to Visual Studio builds. Passing
|
|
1549
|
# extra_link_args to distutils.extensions.Extension() doesn't have any
|
|
1543
|
# extra_link_args to distutils.extensions.Extension() doesn't have any
|
|
1550
|
# effect.
|
|
1544
|
# effect.
|
|
1551
|
from distutils import msvccompiler
|
|
1545
|
from distutils import msvccompiler
|
|
1552
|
|
|
1546
|
|
|
1553
|
msvccompilerclass = msvccompiler.MSVCCompiler
|
|
1547
|
msvccompilerclass = msvccompiler.MSVCCompiler
|
|
1554
|
|
|
1548
|
|
|
1555
|
class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
|
|
1549
|
class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
|
|
1556
|
def initialize(self):
|
|
1550
|
def initialize(self):
|
|
1557
|
msvccompilerclass.initialize(self)
|
|
1551
|
msvccompilerclass.initialize(self)
|
|
1558
|
# "warning LNK4197: export 'func' specified multiple times"
|
|
1552
|
# "warning LNK4197: export 'func' specified multiple times"
|
|
1559
|
self.ldflags_shared.append('/ignore:4197')
|
|
1553
|
self.ldflags_shared.append('/ignore:4197')
|
|
1560
|
self.ldflags_shared_debug.append('/ignore:4197')
|
|
1554
|
self.ldflags_shared_debug.append('/ignore:4197')
|
|
1561
|
|
|
1555
|
|
|
1562
|
msvccompiler.MSVCCompiler = HackedMSVCCompiler
|
|
1556
|
msvccompiler.MSVCCompiler = HackedMSVCCompiler
|
|
1563
|
|
|
1557
|
|
|
1564
|
packagedata = {
|
|
1558
|
packagedata = {
|
|
1565
|
'mercurial': [
|
|
1559
|
'mercurial': [
|
|
1566
|
'locale/*/LC_MESSAGES/hg.mo',
|
|
1560
|
'locale/*/LC_MESSAGES/hg.mo',
|
|
1567
|
'dummycert.pem',
|
|
1561
|
'dummycert.pem',
|
|
1568
|
],
|
|
1562
|
],
|
|
1569
|
'mercurial.defaultrc': [
|
|
1563
|
'mercurial.defaultrc': [
|
|
1570
|
'*.rc',
|
|
1564
|
'*.rc',
|
|
1571
|
],
|
|
1565
|
],
|
|
1572
|
'mercurial.helptext': [
|
|
1566
|
'mercurial.helptext': [
|
|
1573
|
'*.txt',
|
|
1567
|
'*.txt',
|
|
1574
|
],
|
|
1568
|
],
|
|
1575
|
'mercurial.helptext.internals': [
|
|
1569
|
'mercurial.helptext.internals': [
|
|
1576
|
'*.txt',
|
|
1570
|
'*.txt',
|
|
1577
|
],
|
|
1571
|
],
|
|
1578
|
}
|
|
1572
|
}
|
|
1579
|
|
|
1573
|
|
|
1580
|
|
|
1574
|
|
|
1581
|
def ordinarypath(p):
|
|
1575
|
def ordinarypath(p):
|
|
1582
|
return p and p[0] != '.' and p[-1] != '~'
|
|
1576
|
return p and p[0] != '.' and p[-1] != '~'
|
|
1583
|
|
|
1577
|
|
|
1584
|
|
|
1578
|
|
|
1585
|
for root in ('templates',):
|
|
1579
|
for root in ('templates',):
|
|
1586
|
for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
|
|
1580
|
for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
|
|
1587
|
packagename = curdir.replace(os.sep, '.')
|
|
1581
|
packagename = curdir.replace(os.sep, '.')
|
|
1588
|
packagedata[packagename] = list(filter(ordinarypath, files))
|
|
1582
|
packagedata[packagename] = list(filter(ordinarypath, files))
|
|
1589
|
|
|
1583
|
|
|
1590
|
datafiles = []
|
|
1584
|
datafiles = []
|
|
1591
|
|
|
1585
|
|
|
1592
|
# distutils expects version to be str/unicode. Converting it to
|
|
1586
|
# distutils expects version to be str/unicode. Converting it to
|
|
1593
|
# unicode on Python 2 still works because it won't contain any
|
|
1587
|
# unicode on Python 2 still works because it won't contain any
|
|
1594
|
# non-ascii bytes and will be implicitly converted back to bytes
|
|
1588
|
# non-ascii bytes and will be implicitly converted back to bytes
|
|
1595
|
# when operated on.
|
|
1589
|
# when operated on.
|
|
1596
|
assert isinstance(version, str)
|
|
1590
|
assert isinstance(version, str)
|
|
1597
|
setupversion = version
|
|
1591
|
setupversion = version
|
|
1598
|
|
|
1592
|
|
|
1599
|
extra = {}
|
|
1593
|
extra = {}
|
|
1600
|
|
|
1594
|
|
|
1601
|
py2exepackages = [
|
|
1595
|
py2exepackages = [
|
|
1602
|
'hgdemandimport',
|
|
1596
|
'hgdemandimport',
|
|
1603
|
'hgext3rd',
|
|
1597
|
'hgext3rd',
|
|
1604
|
'hgext',
|
|
1598
|
'hgext',
|
|
1605
|
'email',
|
|
1599
|
'email',
|
|
1606
|
# implicitly imported per module policy
|
|
1600
|
# implicitly imported per module policy
|
|
1607
|
# (cffi wouldn't be used as a frozen exe)
|
|
1601
|
# (cffi wouldn't be used as a frozen exe)
|
|
1608
|
'mercurial.cext',
|
|
1602
|
'mercurial.cext',
|
|
1609
|
#'mercurial.cffi',
|
|
1603
|
#'mercurial.cffi',
|
|
1610
|
'mercurial.pure',
|
|
1604
|
'mercurial.pure',
|
|
1611
|
]
|
|
1605
|
]
|
|
1612
|
|
|
1606
|
|
|
1613
|
py2exe_includes = []
|
|
1607
|
py2exe_includes = []
|
|
1614
|
|
|
1608
|
|
|
1615
|
py2exeexcludes = []
|
|
1609
|
py2exeexcludes = []
|
|
1616
|
py2exedllexcludes = ['crypt32.dll']
|
|
1610
|
py2exedllexcludes = ['crypt32.dll']
|
|
1617
|
|
|
1611
|
|
|
1618
|
if issetuptools:
|
|
1612
|
if issetuptools:
|
|
1619
|
extra['python_requires'] = supportedpy
|
|
1613
|
extra['python_requires'] = supportedpy
|
|
1620
|
|
|
1614
|
|
|
1621
|
if py2exeloaded:
|
|
1615
|
if py2exeloaded:
|
|
1622
|
extra['console'] = [
|
|
1616
|
extra['console'] = [
|
|
1623
|
{
|
|
1617
|
{
|
|
1624
|
'script': 'hg',
|
|
1618
|
'script': 'hg',
|
|
1625
|
'copyright': 'Copyright (C) 2005-2022 Olivia Mackall and others',
|
|
1619
|
'copyright': 'Copyright (C) 2005-2022 Olivia Mackall and others',
|
|
1626
|
'product_version': version,
|
|
1620
|
'product_version': version,
|
|
1627
|
}
|
|
1621
|
}
|
|
1628
|
]
|
|
1622
|
]
|
|
1629
|
# Sub command of 'build' because 'py2exe' does not handle sub_commands.
|
|
1623
|
# Sub command of 'build' because 'py2exe' does not handle sub_commands.
|
|
1630
|
# Need to override hgbuild because it has a private copy of
|
|
1624
|
# Need to override hgbuild because it has a private copy of
|
|
1631
|
# build.sub_commands.
|
|
1625
|
# build.sub_commands.
|
|
1632
|
hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
|
|
1626
|
hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
|
|
1633
|
# put dlls in sub directory so that they won't pollute PATH
|
|
1627
|
# put dlls in sub directory so that they won't pollute PATH
|
|
1634
|
extra['zipfile'] = 'lib/library.zip'
|
|
1628
|
extra['zipfile'] = 'lib/library.zip'
|
|
1635
|
|
|
1629
|
|
|
1636
|
# We allow some configuration to be supplemented via environment
|
|
1630
|
# We allow some configuration to be supplemented via environment
|
|
1637
|
# variables. This is better than setup.cfg files because it allows
|
|
1631
|
# variables. This is better than setup.cfg files because it allows
|
|
1638
|
# supplementing configs instead of replacing them.
|
|
1632
|
# supplementing configs instead of replacing them.
|
|
1639
|
extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
|
|
1633
|
extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
|
|
1640
|
if extrapackages:
|
|
1634
|
if extrapackages:
|
|
1641
|
py2exepackages.extend(extrapackages.split(' '))
|
|
1635
|
py2exepackages.extend(extrapackages.split(' '))
|
|
1642
|
|
|
1636
|
|
|
1643
|
extra_includes = os.environ.get('HG_PY2EXE_EXTRA_INCLUDES')
|
|
1637
|
extra_includes = os.environ.get('HG_PY2EXE_EXTRA_INCLUDES')
|
|
1644
|
if extra_includes:
|
|
1638
|
if extra_includes:
|
|
1645
|
py2exe_includes.extend(extra_includes.split(' '))
|
|
1639
|
py2exe_includes.extend(extra_includes.split(' '))
|
|
1646
|
|
|
1640
|
|
|
1647
|
excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
|
|
1641
|
excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
|
|
1648
|
if excludes:
|
|
1642
|
if excludes:
|
|
1649
|
py2exeexcludes.extend(excludes.split(' '))
|
|
1643
|
py2exeexcludes.extend(excludes.split(' '))
|
|
1650
|
|
|
1644
|
|
|
1651
|
dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
|
|
1645
|
dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
|
|
1652
|
if dllexcludes:
|
|
1646
|
if dllexcludes:
|
|
1653
|
py2exedllexcludes.extend(dllexcludes.split(' '))
|
|
1647
|
py2exedllexcludes.extend(dllexcludes.split(' '))
|
|
1654
|
|
|
1648
|
|
|
1655
|
if os.environ.get('PYOXIDIZER'):
|
|
1649
|
if os.environ.get('PYOXIDIZER'):
|
|
1656
|
hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
|
|
1650
|
hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
|
|
1657
|
|
|
1651
|
|
|
1658
|
if os.name == 'nt':
|
|
1652
|
if os.name == 'nt':
|
|
1659
|
# Windows binary file versions for exe/dll files must have the
|
|
1653
|
# Windows binary file versions for exe/dll files must have the
|
|
1660
|
# form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
|
|
1654
|
# form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
|
|
1661
|
setupversion = setupversion.split(r'+', 1)[0]
|
|
1655
|
setupversion = setupversion.split(r'+', 1)[0]
|
|
1662
|
|
|
1656
|
|
|
1663
|
if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
|
|
1657
|
if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
|
|
1664
|
version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
|
|
1658
|
version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
|
|
1665
|
if version:
|
|
1659
|
if version:
|
|
1666
|
version = version[0].decode('utf-8')
|
|
1660
|
version = version[0].decode('utf-8')
|
|
1667
|
xcode4 = version.startswith('Xcode') and StrictVersion(
|
|
1661
|
xcode4 = version.startswith('Xcode') and StrictVersion(
|
|
1668
|
version.split()[1]
|
|
1662
|
version.split()[1]
|
|
1669
|
) >= StrictVersion('4.0')
|
|
1663
|
) >= StrictVersion('4.0')
|
|
1670
|
xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
|
|
1664
|
xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
|
|
1671
|
else:
|
|
1665
|
else:
|
|
1672
|
# xcodebuild returns empty on OS X Lion with XCode 4.3 not
|
|
1666
|
# xcodebuild returns empty on OS X Lion with XCode 4.3 not
|
|
1673
|
# installed, but instead with only command-line tools. Assume
|
|
1667
|
# installed, but instead with only command-line tools. Assume
|
|
1674
|
# that only happens on >= Lion, thus no PPC support.
|
|
1668
|
# that only happens on >= Lion, thus no PPC support.
|
|
1675
|
xcode4 = True
|
|
1669
|
xcode4 = True
|
|
1676
|
xcode51 = False
|
|
1670
|
xcode51 = False
|
|
1677
|
|
|
1671
|
|
|
1678
|
# XCode 4.0 dropped support for ppc architecture, which is hardcoded in
|
|
1672
|
# XCode 4.0 dropped support for ppc architecture, which is hardcoded in
|
|
1679
|
# distutils.sysconfig
|
|
1673
|
# distutils.sysconfig
|
|
1680
|
if xcode4:
|
|
1674
|
if xcode4:
|
|
1681
|
os.environ['ARCHFLAGS'] = ''
|
|
1675
|
os.environ['ARCHFLAGS'] = ''
|
|
1682
|
|
|
1676
|
|
|
1683
|
# XCode 5.1 changes clang such that it now fails to compile if the
|
|
1677
|
# XCode 5.1 changes clang such that it now fails to compile if the
|
|
1684
|
# -mno-fused-madd flag is passed, but the version of Python shipped with
|
|
1678
|
# -mno-fused-madd flag is passed, but the version of Python shipped with
|
|
1685
|
# OS X 10.9 Mavericks includes this flag. This causes problems in all
|
|
1679
|
# OS X 10.9 Mavericks includes this flag. This causes problems in all
|
|
1686
|
# C extension modules, and a bug has been filed upstream at
|
|
1680
|
# C extension modules, and a bug has been filed upstream at
|
|
1687
|
# http://bugs.python.org/issue21244. We also need to patch this here
|
|
1681
|
# http://bugs.python.org/issue21244. We also need to patch this here
|
|
1688
|
# so Mercurial can continue to compile in the meantime.
|
|
1682
|
# so Mercurial can continue to compile in the meantime.
|
|
1689
|
if xcode51:
|
|
1683
|
if xcode51:
|
|
1690
|
cflags = get_config_var('CFLAGS')
|
|
1684
|
cflags = get_config_var('CFLAGS')
|
|
1691
|
if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
|
|
1685
|
if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
|
|
1692
|
os.environ['CFLAGS'] = (
|
|
1686
|
os.environ['CFLAGS'] = (
|
|
1693
|
os.environ.get('CFLAGS', '') + ' -Qunused-arguments'
|
|
1687
|
os.environ.get('CFLAGS', '') + ' -Qunused-arguments'
|
|
1694
|
)
|
|
1688
|
)
|
|
1695
|
|
|
1689
|
|
|
1696
|
setup(
|
|
1690
|
setup(
|
|
1697
|
name='mercurial',
|
|
1691
|
name='mercurial',
|
|
1698
|
version=setupversion,
|
|
1692
|
version=setupversion,
|
|
1699
|
author='Olivia Mackall and many others',
|
|
1693
|
author='Olivia Mackall and many others',
|
|
1700
|
author_email='mercurial@mercurial-scm.org',
|
|
1694
|
author_email='mercurial@mercurial-scm.org',
|
|
1701
|
url='https://mercurial-scm.org/',
|
|
1695
|
url='https://mercurial-scm.org/',
|
|
1702
|
download_url='https://mercurial-scm.org/release/',
|
|
1696
|
download_url='https://mercurial-scm.org/release/',
|
|
1703
|
description=(
|
|
1697
|
description=(
|
|
1704
|
'Fast scalable distributed SCM (revision control, version '
|
|
1698
|
'Fast scalable distributed SCM (revision control, version '
|
|
1705
|
'control) system'
|
|
1699
|
'control) system'
|
|
1706
|
),
|
|
1700
|
),
|
|
1707
|
long_description=(
|
|
1701
|
long_description=(
|
|
1708
|
'Mercurial is a distributed SCM tool written in Python.'
|
|
1702
|
'Mercurial is a distributed SCM tool written in Python.'
|
|
1709
|
' It is used by a number of large projects that require'
|
|
1703
|
' It is used by a number of large projects that require'
|
|
1710
|
' fast, reliable distributed revision control, such as '
|
|
1704
|
' fast, reliable distributed revision control, such as '
|
|
1711
|
'Mozilla.'
|
|
1705
|
'Mozilla.'
|
|
1712
|
),
|
|
1706
|
),
|
|
1713
|
license='GNU GPLv2 or any later version',
|
|
1707
|
license='GNU GPLv2 or any later version',
|
|
1714
|
classifiers=[
|
|
1708
|
classifiers=[
|
|
1715
|
'Development Status :: 6 - Mature',
|
|
1709
|
'Development Status :: 6 - Mature',
|
|
1716
|
'Environment :: Console',
|
|
1710
|
'Environment :: Console',
|
|
1717
|
'Intended Audience :: Developers',
|
|
1711
|
'Intended Audience :: Developers',
|
|
1718
|
'Intended Audience :: System Administrators',
|
|
1712
|
'Intended Audience :: System Administrators',
|
|
1719
|
'License :: OSI Approved :: GNU General Public License (GPL)',
|
|
1713
|
'License :: OSI Approved :: GNU General Public License (GPL)',
|
|
1720
|
'Natural Language :: Danish',
|
|
1714
|
'Natural Language :: Danish',
|
|
1721
|
'Natural Language :: English',
|
|
1715
|
'Natural Language :: English',
|
|
1722
|
'Natural Language :: German',
|
|
1716
|
'Natural Language :: German',
|
|
1723
|
'Natural Language :: Italian',
|
|
1717
|
'Natural Language :: Italian',
|
|
1724
|
'Natural Language :: Japanese',
|
|
1718
|
'Natural Language :: Japanese',
|
|
1725
|
'Natural Language :: Portuguese (Brazilian)',
|
|
1719
|
'Natural Language :: Portuguese (Brazilian)',
|
|
1726
|
'Operating System :: Microsoft :: Windows',
|
|
1720
|
'Operating System :: Microsoft :: Windows',
|
|
1727
|
'Operating System :: OS Independent',
|
|
1721
|
'Operating System :: OS Independent',
|
|
1728
|
'Operating System :: POSIX',
|
|
1722
|
'Operating System :: POSIX',
|
|
1729
|
'Programming Language :: C',
|
|
1723
|
'Programming Language :: C',
|
|
1730
|
'Programming Language :: Python',
|
|
1724
|
'Programming Language :: Python',
|
|
1731
|
'Topic :: Software Development :: Version Control',
|
|
1725
|
'Topic :: Software Development :: Version Control',
|
|
1732
|
],
|
|
1726
|
],
|
|
1733
|
scripts=scripts,
|
|
1727
|
scripts=scripts,
|
|
1734
|
packages=packages,
|
|
1728
|
packages=packages,
|
|
1735
|
ext_modules=extmodules,
|
|
1729
|
ext_modules=extmodules,
|
|
1736
|
data_files=datafiles,
|
|
1730
|
data_files=datafiles,
|
|
1737
|
package_data=packagedata,
|
|
1731
|
package_data=packagedata,
|
|
1738
|
cmdclass=cmdclass,
|
|
1732
|
cmdclass=cmdclass,
|
|
1739
|
distclass=hgdist,
|
|
1733
|
distclass=hgdist,
|
|
1740
|
options={
|
|
1734
|
options={
|
|
1741
|
'py2exe': {
|
|
1735
|
'py2exe': {
|
|
1742
|
'bundle_files': 3,
|
|
1736
|
'bundle_files': 3,
|
|
1743
|
'dll_excludes': py2exedllexcludes,
|
|
1737
|
'dll_excludes': py2exedllexcludes,
|
|
1744
|
'includes': py2exe_includes,
|
|
1738
|
'includes': py2exe_includes,
|
|
1745
|
'excludes': py2exeexcludes,
|
|
1739
|
'excludes': py2exeexcludes,
|
|
1746
|
'packages': py2exepackages,
|
|
1740
|
'packages': py2exepackages,
|
|
1747
|
},
|
|
1741
|
},
|
|
1748
|
'bdist_mpkg': {
|
|
1742
|
'bdist_mpkg': {
|
|
1749
|
'zipdist': False,
|
|
1743
|
'zipdist': False,
|
|
1750
|
'license': 'COPYING',
|
|
1744
|
'license': 'COPYING',
|
|
1751
|
'readme': 'contrib/packaging/macosx/Readme.html',
|
|
1745
|
'readme': 'contrib/packaging/macosx/Readme.html',
|
|
1752
|
'welcome': 'contrib/packaging/macosx/Welcome.html',
|
|
1746
|
'welcome': 'contrib/packaging/macosx/Welcome.html',
|
|
1753
|
},
|
|
1747
|
},
|
|
1754
|
},
|
|
1748
|
},
|
|
1755
|
**extra
|
|
1749
|
**extra
|
|
1756
|
)
|
|
1750
|
)
|