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