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