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