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