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