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