##// END OF EJS Templates
hghave: replace has_svn13/has_svn15 with checkvers...
timeless -
r28759:2348ca49 default
parent child Browse files
Show More
@@ -1,481 +1,478
1 from __future__ import absolute_import
1 from __future__ import absolute_import
2
2
3 import errno
3 import errno
4 import os
4 import os
5 import re
5 import re
6 import socket
6 import socket
7 import stat
7 import stat
8 import subprocess
8 import subprocess
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11
11
12 tempprefix = 'hg-hghave-'
12 tempprefix = 'hg-hghave-'
13
13
14 checks = {
14 checks = {
15 "true": (lambda: True, "yak shaving"),
15 "true": (lambda: True, "yak shaving"),
16 "false": (lambda: False, "nail clipper"),
16 "false": (lambda: False, "nail clipper"),
17 }
17 }
18
18
19 def check(name, desc):
19 def check(name, desc):
20 """Registers a check function for a feature."""
20 """Registers a check function for a feature."""
21 def decorator(func):
21 def decorator(func):
22 checks[name] = (func, desc)
22 checks[name] = (func, desc)
23 return func
23 return func
24 return decorator
24 return decorator
25
25
26 def checkvers(name, desc, vers):
26 def checkvers(name, desc, vers):
27 """Registers a check function for each of a series of versions.
27 """Registers a check function for each of a series of versions.
28
28
29 vers can be a list or an iterator"""
29 vers can be a list or an iterator"""
30 def decorator(func):
30 def decorator(func):
31 def funcv(v):
31 def funcv(v):
32 def f():
32 def f():
33 return func(v)
33 return func(v)
34 return f
34 return f
35 for v in vers:
35 for v in vers:
36 v = str(v)
36 v = str(v)
37 f = funcv(v)
37 f = funcv(v)
38 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
38 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
39 return func
39 return func
40 return decorator
40 return decorator
41
41
42 def checkfeatures(features):
42 def checkfeatures(features):
43 result = {
43 result = {
44 'error': [],
44 'error': [],
45 'missing': [],
45 'missing': [],
46 'skipped': [],
46 'skipped': [],
47 }
47 }
48
48
49 for feature in features:
49 for feature in features:
50 negate = feature.startswith('no-')
50 negate = feature.startswith('no-')
51 if negate:
51 if negate:
52 feature = feature[3:]
52 feature = feature[3:]
53
53
54 if feature not in checks:
54 if feature not in checks:
55 result['missing'].append(feature)
55 result['missing'].append(feature)
56 continue
56 continue
57
57
58 check, desc = checks[feature]
58 check, desc = checks[feature]
59 try:
59 try:
60 available = check()
60 available = check()
61 except Exception:
61 except Exception:
62 result['error'].append('hghave check failed: %s' % feature)
62 result['error'].append('hghave check failed: %s' % feature)
63 continue
63 continue
64
64
65 if not negate and not available:
65 if not negate and not available:
66 result['skipped'].append('missing feature: %s' % desc)
66 result['skipped'].append('missing feature: %s' % desc)
67 elif negate and available:
67 elif negate and available:
68 result['skipped'].append('system supports %s' % desc)
68 result['skipped'].append('system supports %s' % desc)
69
69
70 return result
70 return result
71
71
72 def require(features):
72 def require(features):
73 """Require that features are available, exiting if not."""
73 """Require that features are available, exiting if not."""
74 result = checkfeatures(features)
74 result = checkfeatures(features)
75
75
76 for missing in result['missing']:
76 for missing in result['missing']:
77 sys.stderr.write('skipped: unknown feature: %s\n' % missing)
77 sys.stderr.write('skipped: unknown feature: %s\n' % missing)
78 for msg in result['skipped']:
78 for msg in result['skipped']:
79 sys.stderr.write('skipped: %s\n' % msg)
79 sys.stderr.write('skipped: %s\n' % msg)
80 for msg in result['error']:
80 for msg in result['error']:
81 sys.stderr.write('%s\n' % msg)
81 sys.stderr.write('%s\n' % msg)
82
82
83 if result['missing']:
83 if result['missing']:
84 sys.exit(2)
84 sys.exit(2)
85
85
86 if result['skipped'] or result['error']:
86 if result['skipped'] or result['error']:
87 sys.exit(1)
87 sys.exit(1)
88
88
89 def matchoutput(cmd, regexp, ignorestatus=False):
89 def matchoutput(cmd, regexp, ignorestatus=False):
90 """Return the match object if cmd executes successfully and its output
90 """Return the match object if cmd executes successfully and its output
91 is matched by the supplied regular expression.
91 is matched by the supplied regular expression.
92 """
92 """
93 r = re.compile(regexp)
93 r = re.compile(regexp)
94 try:
94 try:
95 p = subprocess.Popen(
95 p = subprocess.Popen(
96 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
96 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
97 except OSError as e:
97 except OSError as e:
98 if e.errno != errno.ENOENT:
98 if e.errno != errno.ENOENT:
99 raise
99 raise
100 ret = -1
100 ret = -1
101 ret = p.wait()
101 ret = p.wait()
102 s = p.stdout.read()
102 s = p.stdout.read()
103 return (ignorestatus or not ret) and r.search(s)
103 return (ignorestatus or not ret) and r.search(s)
104
104
105 @check("baz", "GNU Arch baz client")
105 @check("baz", "GNU Arch baz client")
106 def has_baz():
106 def has_baz():
107 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
107 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
108
108
109 @check("bzr", "Canonical's Bazaar client")
109 @check("bzr", "Canonical's Bazaar client")
110 def has_bzr():
110 def has_bzr():
111 try:
111 try:
112 import bzrlib
112 import bzrlib
113 return bzrlib.__doc__ is not None
113 return bzrlib.__doc__ is not None
114 except ImportError:
114 except ImportError:
115 return False
115 return False
116
116
117 @check("bzr114", "Canonical's Bazaar client >= 1.14")
117 @check("bzr114", "Canonical's Bazaar client >= 1.14")
118 def has_bzr114():
118 def has_bzr114():
119 try:
119 try:
120 import bzrlib
120 import bzrlib
121 return (bzrlib.__doc__ is not None
121 return (bzrlib.__doc__ is not None
122 and bzrlib.version_info[:2] >= (1, 14))
122 and bzrlib.version_info[:2] >= (1, 14))
123 except ImportError:
123 except ImportError:
124 return False
124 return False
125
125
126 @check("cvs", "cvs client/server")
126 @check("cvs", "cvs client/server")
127 def has_cvs():
127 def has_cvs():
128 re = r'Concurrent Versions System.*?server'
128 re = r'Concurrent Versions System.*?server'
129 return matchoutput('cvs --version 2>&1', re) and not has_msys()
129 return matchoutput('cvs --version 2>&1', re) and not has_msys()
130
130
131 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
131 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
132 def has_cvs112():
132 def has_cvs112():
133 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
133 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
134 return matchoutput('cvs --version 2>&1', re) and not has_msys()
134 return matchoutput('cvs --version 2>&1', re) and not has_msys()
135
135
136 @check("darcs", "darcs client")
136 @check("darcs", "darcs client")
137 def has_darcs():
137 def has_darcs():
138 return matchoutput('darcs --version', r'2\.[2-9]', True)
138 return matchoutput('darcs --version', r'2\.[2-9]', True)
139
139
140 @check("mtn", "monotone client (>= 1.0)")
140 @check("mtn", "monotone client (>= 1.0)")
141 def has_mtn():
141 def has_mtn():
142 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
142 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
143 'mtn --version', r'monotone 0\.', True)
143 'mtn --version', r'monotone 0\.', True)
144
144
145 @check("eol-in-paths", "end-of-lines in paths")
145 @check("eol-in-paths", "end-of-lines in paths")
146 def has_eol_in_paths():
146 def has_eol_in_paths():
147 try:
147 try:
148 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
148 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
149 os.close(fd)
149 os.close(fd)
150 os.remove(path)
150 os.remove(path)
151 return True
151 return True
152 except (IOError, OSError):
152 except (IOError, OSError):
153 return False
153 return False
154
154
155 @check("execbit", "executable bit")
155 @check("execbit", "executable bit")
156 def has_executablebit():
156 def has_executablebit():
157 try:
157 try:
158 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
158 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
159 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
159 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
160 try:
160 try:
161 os.close(fh)
161 os.close(fh)
162 m = os.stat(fn).st_mode & 0o777
162 m = os.stat(fn).st_mode & 0o777
163 new_file_has_exec = m & EXECFLAGS
163 new_file_has_exec = m & EXECFLAGS
164 os.chmod(fn, m ^ EXECFLAGS)
164 os.chmod(fn, m ^ EXECFLAGS)
165 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
165 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
166 finally:
166 finally:
167 os.unlink(fn)
167 os.unlink(fn)
168 except (IOError, OSError):
168 except (IOError, OSError):
169 # we don't care, the user probably won't be able to commit anyway
169 # we don't care, the user probably won't be able to commit anyway
170 return False
170 return False
171 return not (new_file_has_exec or exec_flags_cannot_flip)
171 return not (new_file_has_exec or exec_flags_cannot_flip)
172
172
173 @check("icasefs", "case insensitive file system")
173 @check("icasefs", "case insensitive file system")
174 def has_icasefs():
174 def has_icasefs():
175 # Stolen from mercurial.util
175 # Stolen from mercurial.util
176 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
176 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
177 os.close(fd)
177 os.close(fd)
178 try:
178 try:
179 s1 = os.stat(path)
179 s1 = os.stat(path)
180 d, b = os.path.split(path)
180 d, b = os.path.split(path)
181 p2 = os.path.join(d, b.upper())
181 p2 = os.path.join(d, b.upper())
182 if path == p2:
182 if path == p2:
183 p2 = os.path.join(d, b.lower())
183 p2 = os.path.join(d, b.lower())
184 try:
184 try:
185 s2 = os.stat(p2)
185 s2 = os.stat(p2)
186 return s2 == s1
186 return s2 == s1
187 except OSError:
187 except OSError:
188 return False
188 return False
189 finally:
189 finally:
190 os.remove(path)
190 os.remove(path)
191
191
192 @check("fifo", "named pipes")
192 @check("fifo", "named pipes")
193 def has_fifo():
193 def has_fifo():
194 if getattr(os, "mkfifo", None) is None:
194 if getattr(os, "mkfifo", None) is None:
195 return False
195 return False
196 name = tempfile.mktemp(dir='.', prefix=tempprefix)
196 name = tempfile.mktemp(dir='.', prefix=tempprefix)
197 try:
197 try:
198 os.mkfifo(name)
198 os.mkfifo(name)
199 os.unlink(name)
199 os.unlink(name)
200 return True
200 return True
201 except OSError:
201 except OSError:
202 return False
202 return False
203
203
204 @check("killdaemons", 'killdaemons.py support')
204 @check("killdaemons", 'killdaemons.py support')
205 def has_killdaemons():
205 def has_killdaemons():
206 return True
206 return True
207
207
208 @check("cacheable", "cacheable filesystem")
208 @check("cacheable", "cacheable filesystem")
209 def has_cacheable_fs():
209 def has_cacheable_fs():
210 from mercurial import util
210 from mercurial import util
211
211
212 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
212 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
213 os.close(fd)
213 os.close(fd)
214 try:
214 try:
215 return util.cachestat(path).cacheable()
215 return util.cachestat(path).cacheable()
216 finally:
216 finally:
217 os.remove(path)
217 os.remove(path)
218
218
219 @check("lsprof", "python lsprof module")
219 @check("lsprof", "python lsprof module")
220 def has_lsprof():
220 def has_lsprof():
221 try:
221 try:
222 import _lsprof
222 import _lsprof
223 _lsprof.Profiler # silence unused import warning
223 _lsprof.Profiler # silence unused import warning
224 return True
224 return True
225 except ImportError:
225 except ImportError:
226 return False
226 return False
227
227
228 @check("gettext", "GNU Gettext (msgfmt)")
228 @check("gettext", "GNU Gettext (msgfmt)")
229 def has_gettext():
229 def has_gettext():
230 return matchoutput('msgfmt --version', 'GNU gettext-tools')
230 return matchoutput('msgfmt --version', 'GNU gettext-tools')
231
231
232 @check("git", "git command line client")
232 @check("git", "git command line client")
233 def has_git():
233 def has_git():
234 return matchoutput('git --version 2>&1', r'^git version')
234 return matchoutput('git --version 2>&1', r'^git version')
235
235
236 @check("docutils", "Docutils text processing library")
236 @check("docutils", "Docutils text processing library")
237 def has_docutils():
237 def has_docutils():
238 try:
238 try:
239 from docutils.core import publish_cmdline
239 from docutils.core import publish_cmdline
240 publish_cmdline # silence unused import
240 publish_cmdline # silence unused import
241 return True
241 return True
242 except ImportError:
242 except ImportError:
243 return False
243 return False
244
244
245 def getsvnversion():
245 def getsvnversion():
246 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
246 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
247 if not m:
247 if not m:
248 return (0, 0)
248 return (0, 0)
249 return (int(m.group(1)), int(m.group(2)))
249 return (int(m.group(1)), int(m.group(2)))
250
250
251 @check("svn15", "subversion client and admin tools >= 1.5")
251 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
252 def has_svn15():
252 def has_svn_range(v):
253 return getsvnversion() >= (1, 5)
253 major, minor = v.split('.')[0:2]
254
254 return getsvnversion() >= (int(major), int(minor))
255 @check("svn13", "subversion client and admin tools >= 1.3")
256 def has_svn13():
257 return getsvnversion() >= (1, 3)
258
255
259 @check("svn", "subversion client and admin tools")
256 @check("svn", "subversion client and admin tools")
260 def has_svn():
257 def has_svn():
261 return matchoutput('svn --version 2>&1', r'^svn, version') and \
258 return matchoutput('svn --version 2>&1', r'^svn, version') and \
262 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
259 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
263
260
264 @check("svn-bindings", "subversion python bindings")
261 @check("svn-bindings", "subversion python bindings")
265 def has_svn_bindings():
262 def has_svn_bindings():
266 try:
263 try:
267 import svn.core
264 import svn.core
268 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
265 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
269 if version < (1, 4):
266 if version < (1, 4):
270 return False
267 return False
271 return True
268 return True
272 except ImportError:
269 except ImportError:
273 return False
270 return False
274
271
275 @check("p4", "Perforce server and client")
272 @check("p4", "Perforce server and client")
276 def has_p4():
273 def has_p4():
277 return (matchoutput('p4 -V', r'Rev\. P4/') and
274 return (matchoutput('p4 -V', r'Rev\. P4/') and
278 matchoutput('p4d -V', r'Rev\. P4D/'))
275 matchoutput('p4d -V', r'Rev\. P4D/'))
279
276
280 @check("symlink", "symbolic links")
277 @check("symlink", "symbolic links")
281 def has_symlink():
278 def has_symlink():
282 if getattr(os, "symlink", None) is None:
279 if getattr(os, "symlink", None) is None:
283 return False
280 return False
284 name = tempfile.mktemp(dir='.', prefix=tempprefix)
281 name = tempfile.mktemp(dir='.', prefix=tempprefix)
285 try:
282 try:
286 os.symlink(".", name)
283 os.symlink(".", name)
287 os.unlink(name)
284 os.unlink(name)
288 return True
285 return True
289 except (OSError, AttributeError):
286 except (OSError, AttributeError):
290 return False
287 return False
291
288
292 @check("hardlink", "hardlinks")
289 @check("hardlink", "hardlinks")
293 def has_hardlink():
290 def has_hardlink():
294 from mercurial import util
291 from mercurial import util
295 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
292 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
296 os.close(fh)
293 os.close(fh)
297 name = tempfile.mktemp(dir='.', prefix=tempprefix)
294 name = tempfile.mktemp(dir='.', prefix=tempprefix)
298 try:
295 try:
299 util.oslink(fn, name)
296 util.oslink(fn, name)
300 os.unlink(name)
297 os.unlink(name)
301 return True
298 return True
302 except OSError:
299 except OSError:
303 return False
300 return False
304 finally:
301 finally:
305 os.unlink(fn)
302 os.unlink(fn)
306
303
307 @check("tla", "GNU Arch tla client")
304 @check("tla", "GNU Arch tla client")
308 def has_tla():
305 def has_tla():
309 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
306 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
310
307
311 @check("gpg", "gpg client")
308 @check("gpg", "gpg client")
312 def has_gpg():
309 def has_gpg():
313 return matchoutput('gpg --version 2>&1', r'GnuPG')
310 return matchoutput('gpg --version 2>&1', r'GnuPG')
314
311
315 @check("unix-permissions", "unix-style permissions")
312 @check("unix-permissions", "unix-style permissions")
316 def has_unix_permissions():
313 def has_unix_permissions():
317 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
314 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
318 try:
315 try:
319 fname = os.path.join(d, 'foo')
316 fname = os.path.join(d, 'foo')
320 for umask in (0o77, 0o07, 0o22):
317 for umask in (0o77, 0o07, 0o22):
321 os.umask(umask)
318 os.umask(umask)
322 f = open(fname, 'w')
319 f = open(fname, 'w')
323 f.close()
320 f.close()
324 mode = os.stat(fname).st_mode
321 mode = os.stat(fname).st_mode
325 os.unlink(fname)
322 os.unlink(fname)
326 if mode & 0o777 != ~umask & 0o666:
323 if mode & 0o777 != ~umask & 0o666:
327 return False
324 return False
328 return True
325 return True
329 finally:
326 finally:
330 os.rmdir(d)
327 os.rmdir(d)
331
328
332 @check("unix-socket", "AF_UNIX socket family")
329 @check("unix-socket", "AF_UNIX socket family")
333 def has_unix_socket():
330 def has_unix_socket():
334 return getattr(socket, 'AF_UNIX', None) is not None
331 return getattr(socket, 'AF_UNIX', None) is not None
335
332
336 @check("root", "root permissions")
333 @check("root", "root permissions")
337 def has_root():
334 def has_root():
338 return getattr(os, 'geteuid', None) and os.geteuid() == 0
335 return getattr(os, 'geteuid', None) and os.geteuid() == 0
339
336
340 @check("pyflakes", "Pyflakes python linter")
337 @check("pyflakes", "Pyflakes python linter")
341 def has_pyflakes():
338 def has_pyflakes():
342 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
339 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
343 r"<stdin>:1: 're' imported but unused",
340 r"<stdin>:1: 're' imported but unused",
344 True)
341 True)
345
342
346 @check("pygments", "Pygments source highlighting library")
343 @check("pygments", "Pygments source highlighting library")
347 def has_pygments():
344 def has_pygments():
348 try:
345 try:
349 import pygments
346 import pygments
350 pygments.highlight # silence unused import warning
347 pygments.highlight # silence unused import warning
351 return True
348 return True
352 except ImportError:
349 except ImportError:
353 return False
350 return False
354
351
355 @check("outer-repo", "outer repo")
352 @check("outer-repo", "outer repo")
356 def has_outer_repo():
353 def has_outer_repo():
357 # failing for other reasons than 'no repo' imply that there is a repo
354 # failing for other reasons than 'no repo' imply that there is a repo
358 return not matchoutput('hg root 2>&1',
355 return not matchoutput('hg root 2>&1',
359 r'abort: no repository found', True)
356 r'abort: no repository found', True)
360
357
361 @check("ssl", "ssl module available")
358 @check("ssl", "ssl module available")
362 def has_ssl():
359 def has_ssl():
363 try:
360 try:
364 import ssl
361 import ssl
365 ssl.CERT_NONE
362 ssl.CERT_NONE
366 return True
363 return True
367 except ImportError:
364 except ImportError:
368 return False
365 return False
369
366
370 @check("sslcontext", "python >= 2.7.9 ssl")
367 @check("sslcontext", "python >= 2.7.9 ssl")
371 def has_sslcontext():
368 def has_sslcontext():
372 try:
369 try:
373 import ssl
370 import ssl
374 ssl.SSLContext
371 ssl.SSLContext
375 return True
372 return True
376 except (ImportError, AttributeError):
373 except (ImportError, AttributeError):
377 return False
374 return False
378
375
379 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
376 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
380 def has_defaultcacerts():
377 def has_defaultcacerts():
381 from mercurial import sslutil
378 from mercurial import sslutil
382 return sslutil._defaultcacerts() != '!'
379 return sslutil._defaultcacerts() != '!'
383
380
384 @check("windows", "Windows")
381 @check("windows", "Windows")
385 def has_windows():
382 def has_windows():
386 return os.name == 'nt'
383 return os.name == 'nt'
387
384
388 @check("system-sh", "system() uses sh")
385 @check("system-sh", "system() uses sh")
389 def has_system_sh():
386 def has_system_sh():
390 return os.name != 'nt'
387 return os.name != 'nt'
391
388
392 @check("serve", "platform and python can manage 'hg serve -d'")
389 @check("serve", "platform and python can manage 'hg serve -d'")
393 def has_serve():
390 def has_serve():
394 return os.name != 'nt' # gross approximation
391 return os.name != 'nt' # gross approximation
395
392
396 @check("test-repo", "running tests from repository")
393 @check("test-repo", "running tests from repository")
397 def has_test_repo():
394 def has_test_repo():
398 t = os.environ["TESTDIR"]
395 t = os.environ["TESTDIR"]
399 return os.path.isdir(os.path.join(t, "..", ".hg"))
396 return os.path.isdir(os.path.join(t, "..", ".hg"))
400
397
401 @check("tic", "terminfo compiler and curses module")
398 @check("tic", "terminfo compiler and curses module")
402 def has_tic():
399 def has_tic():
403 try:
400 try:
404 import curses
401 import curses
405 curses.COLOR_BLUE
402 curses.COLOR_BLUE
406 return matchoutput('test -x "`which tic`"', '')
403 return matchoutput('test -x "`which tic`"', '')
407 except ImportError:
404 except ImportError:
408 return False
405 return False
409
406
410 @check("msys", "Windows with MSYS")
407 @check("msys", "Windows with MSYS")
411 def has_msys():
408 def has_msys():
412 return os.getenv('MSYSTEM')
409 return os.getenv('MSYSTEM')
413
410
414 @check("aix", "AIX")
411 @check("aix", "AIX")
415 def has_aix():
412 def has_aix():
416 return sys.platform.startswith("aix")
413 return sys.platform.startswith("aix")
417
414
418 @check("osx", "OS X")
415 @check("osx", "OS X")
419 def has_osx():
416 def has_osx():
420 return sys.platform == 'darwin'
417 return sys.platform == 'darwin'
421
418
422 @check("docker", "docker support")
419 @check("docker", "docker support")
423 def has_docker():
420 def has_docker():
424 pat = r'A self-sufficient runtime for linux containers\.'
421 pat = r'A self-sufficient runtime for linux containers\.'
425 if matchoutput('docker --help', pat):
422 if matchoutput('docker --help', pat):
426 if 'linux' not in sys.platform:
423 if 'linux' not in sys.platform:
427 # TODO: in theory we should be able to test docker-based
424 # TODO: in theory we should be able to test docker-based
428 # package creation on non-linux using boot2docker, but in
425 # package creation on non-linux using boot2docker, but in
429 # practice that requires extra coordination to make sure
426 # practice that requires extra coordination to make sure
430 # $TESTTEMP is going to be visible at the same path to the
427 # $TESTTEMP is going to be visible at the same path to the
431 # boot2docker VM. If we figure out how to verify that, we
428 # boot2docker VM. If we figure out how to verify that, we
432 # can use the following instead of just saying False:
429 # can use the following instead of just saying False:
433 # return 'DOCKER_HOST' in os.environ
430 # return 'DOCKER_HOST' in os.environ
434 return False
431 return False
435
432
436 return True
433 return True
437 return False
434 return False
438
435
439 @check("debhelper", "debian packaging tools")
436 @check("debhelper", "debian packaging tools")
440 def has_debhelper():
437 def has_debhelper():
441 dpkg = matchoutput('dpkg --version',
438 dpkg = matchoutput('dpkg --version',
442 "Debian `dpkg' package management program")
439 "Debian `dpkg' package management program")
443 dh = matchoutput('dh --help',
440 dh = matchoutput('dh --help',
444 'dh is a part of debhelper.', ignorestatus=True)
441 'dh is a part of debhelper.', ignorestatus=True)
445 dh_py2 = matchoutput('dh_python2 --help',
442 dh_py2 = matchoutput('dh_python2 --help',
446 'other supported Python versions')
443 'other supported Python versions')
447 return dpkg and dh and dh_py2
444 return dpkg and dh and dh_py2
448
445
449 @check("absimport", "absolute_import in __future__")
446 @check("absimport", "absolute_import in __future__")
450 def has_absimport():
447 def has_absimport():
451 import __future__
448 import __future__
452 from mercurial import util
449 from mercurial import util
453 return util.safehasattr(__future__, "absolute_import")
450 return util.safehasattr(__future__, "absolute_import")
454
451
455 @check("py3k", "running with Python 3.x")
452 @check("py3k", "running with Python 3.x")
456 def has_py3k():
453 def has_py3k():
457 return 3 == sys.version_info[0]
454 return 3 == sys.version_info[0]
458
455
459 @check("py3exe", "a Python 3.x interpreter is available")
456 @check("py3exe", "a Python 3.x interpreter is available")
460 def has_python3exe():
457 def has_python3exe():
461 return 'PYTHON3' in os.environ
458 return 'PYTHON3' in os.environ
462
459
463 @check("pure", "running with pure Python code")
460 @check("pure", "running with pure Python code")
464 def has_pure():
461 def has_pure():
465 return any([
462 return any([
466 os.environ.get("HGMODULEPOLICY") == "py",
463 os.environ.get("HGMODULEPOLICY") == "py",
467 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
464 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
468 ])
465 ])
469
466
470 @check("slow", "allow slow tests")
467 @check("slow", "allow slow tests")
471 def has_slow():
468 def has_slow():
472 return os.environ.get('HGTEST_SLOW') == 'slow'
469 return os.environ.get('HGTEST_SLOW') == 'slow'
473
470
474 @check("hypothesis", "Hypothesis automated test generation")
471 @check("hypothesis", "Hypothesis automated test generation")
475 def has_hypothesis():
472 def has_hypothesis():
476 try:
473 try:
477 import hypothesis
474 import hypothesis
478 hypothesis.given
475 hypothesis.given
479 return True
476 return True
480 except ImportError:
477 except ImportError:
481 return False
478 return False
General Comments 0
You need to be logged in to leave comments. Login now