##// END OF EJS Templates
test-gpg: start gpg-agent by gpg-connect-agent only if GnuPG v2.1+ detected...
Yuya Nishihara -
r29873:80ba176b default
parent child Browse files
Show More
@@ -1,587 +1,591
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', br'baz Bazaar version')
107 return matchoutput('baz --version 2>&1', br'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 import bzrlib.bzrdir
113 import bzrlib.bzrdir
114 import bzrlib.errors
114 import bzrlib.errors
115 import bzrlib.revision
115 import bzrlib.revision
116 import bzrlib.revisionspec.RevisionSpec
116 import bzrlib.revisionspec.RevisionSpec
117 return bzrlib.__doc__ is not None
117 return bzrlib.__doc__ is not None
118 except ImportError:
118 except ImportError:
119 return False
119 return False
120
120
121 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
121 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
122 def has_bzr_range(v):
122 def has_bzr_range(v):
123 major, minor = v.split('.')[0:2]
123 major, minor = v.split('.')[0:2]
124 try:
124 try:
125 import bzrlib
125 import bzrlib
126 return (bzrlib.__doc__ is not None
126 return (bzrlib.__doc__ is not None
127 and bzrlib.version_info[:2] >= (int(major), int(minor)))
127 and bzrlib.version_info[:2] >= (int(major), int(minor)))
128 except ImportError:
128 except ImportError:
129 return False
129 return False
130
130
131 @check("chg", "running with chg")
131 @check("chg", "running with chg")
132 def has_chg():
132 def has_chg():
133 return 'CHGHG' in os.environ
133 return 'CHGHG' in os.environ
134
134
135 @check("cvs", "cvs client/server")
135 @check("cvs", "cvs client/server")
136 def has_cvs():
136 def has_cvs():
137 re = br'Concurrent Versions System.*?server'
137 re = br'Concurrent Versions System.*?server'
138 return matchoutput('cvs --version 2>&1', re) and not has_msys()
138 return matchoutput('cvs --version 2>&1', re) and not has_msys()
139
139
140 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
140 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
141 def has_cvs112():
141 def has_cvs112():
142 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
142 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
143 return matchoutput('cvs --version 2>&1', re) and not has_msys()
143 return matchoutput('cvs --version 2>&1', re) and not has_msys()
144
144
145 @check("cvsnt", "cvsnt client/server")
145 @check("cvsnt", "cvsnt client/server")
146 def has_cvsnt():
146 def has_cvsnt():
147 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
147 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
148 return matchoutput('cvsnt --version 2>&1', re)
148 return matchoutput('cvsnt --version 2>&1', re)
149
149
150 @check("darcs", "darcs client")
150 @check("darcs", "darcs client")
151 def has_darcs():
151 def has_darcs():
152 return matchoutput('darcs --version', br'2\.[2-9]', True)
152 return matchoutput('darcs --version', br'2\.[2-9]', True)
153
153
154 @check("mtn", "monotone client (>= 1.0)")
154 @check("mtn", "monotone client (>= 1.0)")
155 def has_mtn():
155 def has_mtn():
156 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
156 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
157 'mtn --version', br'monotone 0\.', True)
157 'mtn --version', br'monotone 0\.', True)
158
158
159 @check("eol-in-paths", "end-of-lines in paths")
159 @check("eol-in-paths", "end-of-lines in paths")
160 def has_eol_in_paths():
160 def has_eol_in_paths():
161 try:
161 try:
162 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
162 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
163 os.close(fd)
163 os.close(fd)
164 os.remove(path)
164 os.remove(path)
165 return True
165 return True
166 except (IOError, OSError):
166 except (IOError, OSError):
167 return False
167 return False
168
168
169 @check("execbit", "executable bit")
169 @check("execbit", "executable bit")
170 def has_executablebit():
170 def has_executablebit():
171 try:
171 try:
172 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
172 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
173 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
173 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
174 try:
174 try:
175 os.close(fh)
175 os.close(fh)
176 m = os.stat(fn).st_mode & 0o777
176 m = os.stat(fn).st_mode & 0o777
177 new_file_has_exec = m & EXECFLAGS
177 new_file_has_exec = m & EXECFLAGS
178 os.chmod(fn, m ^ EXECFLAGS)
178 os.chmod(fn, m ^ EXECFLAGS)
179 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
179 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
180 finally:
180 finally:
181 os.unlink(fn)
181 os.unlink(fn)
182 except (IOError, OSError):
182 except (IOError, OSError):
183 # we don't care, the user probably won't be able to commit anyway
183 # we don't care, the user probably won't be able to commit anyway
184 return False
184 return False
185 return not (new_file_has_exec or exec_flags_cannot_flip)
185 return not (new_file_has_exec or exec_flags_cannot_flip)
186
186
187 @check("icasefs", "case insensitive file system")
187 @check("icasefs", "case insensitive file system")
188 def has_icasefs():
188 def has_icasefs():
189 # Stolen from mercurial.util
189 # Stolen from mercurial.util
190 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
190 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
191 os.close(fd)
191 os.close(fd)
192 try:
192 try:
193 s1 = os.stat(path)
193 s1 = os.stat(path)
194 d, b = os.path.split(path)
194 d, b = os.path.split(path)
195 p2 = os.path.join(d, b.upper())
195 p2 = os.path.join(d, b.upper())
196 if path == p2:
196 if path == p2:
197 p2 = os.path.join(d, b.lower())
197 p2 = os.path.join(d, b.lower())
198 try:
198 try:
199 s2 = os.stat(p2)
199 s2 = os.stat(p2)
200 return s2 == s1
200 return s2 == s1
201 except OSError:
201 except OSError:
202 return False
202 return False
203 finally:
203 finally:
204 os.remove(path)
204 os.remove(path)
205
205
206 @check("fifo", "named pipes")
206 @check("fifo", "named pipes")
207 def has_fifo():
207 def has_fifo():
208 if getattr(os, "mkfifo", None) is None:
208 if getattr(os, "mkfifo", None) is None:
209 return False
209 return False
210 name = tempfile.mktemp(dir='.', prefix=tempprefix)
210 name = tempfile.mktemp(dir='.', prefix=tempprefix)
211 try:
211 try:
212 os.mkfifo(name)
212 os.mkfifo(name)
213 os.unlink(name)
213 os.unlink(name)
214 return True
214 return True
215 except OSError:
215 except OSError:
216 return False
216 return False
217
217
218 @check("killdaemons", 'killdaemons.py support')
218 @check("killdaemons", 'killdaemons.py support')
219 def has_killdaemons():
219 def has_killdaemons():
220 return True
220 return True
221
221
222 @check("cacheable", "cacheable filesystem")
222 @check("cacheable", "cacheable filesystem")
223 def has_cacheable_fs():
223 def has_cacheable_fs():
224 from mercurial import util
224 from mercurial import util
225
225
226 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
226 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
227 os.close(fd)
227 os.close(fd)
228 try:
228 try:
229 return util.cachestat(path).cacheable()
229 return util.cachestat(path).cacheable()
230 finally:
230 finally:
231 os.remove(path)
231 os.remove(path)
232
232
233 @check("lsprof", "python lsprof module")
233 @check("lsprof", "python lsprof module")
234 def has_lsprof():
234 def has_lsprof():
235 try:
235 try:
236 import _lsprof
236 import _lsprof
237 _lsprof.Profiler # silence unused import warning
237 _lsprof.Profiler # silence unused import warning
238 return True
238 return True
239 except ImportError:
239 except ImportError:
240 return False
240 return False
241
241
242 def gethgversion():
242 def gethgversion():
243 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
243 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
244 if not m:
244 if not m:
245 return (0, 0)
245 return (0, 0)
246 return (int(m.group(1)), int(m.group(2)))
246 return (int(m.group(1)), int(m.group(2)))
247
247
248 @checkvers("hg", "Mercurial >= %s",
248 @checkvers("hg", "Mercurial >= %s",
249 list([(1.0 * x) / 10 for x in range(9, 40)]))
249 list([(1.0 * x) / 10 for x in range(9, 40)]))
250 def has_hg_range(v):
250 def has_hg_range(v):
251 major, minor = v.split('.')[0:2]
251 major, minor = v.split('.')[0:2]
252 return gethgversion() >= (int(major), int(minor))
252 return gethgversion() >= (int(major), int(minor))
253
253
254 @check("hg08", "Mercurial >= 0.8")
254 @check("hg08", "Mercurial >= 0.8")
255 def has_hg08():
255 def has_hg08():
256 if checks["hg09"][0]():
256 if checks["hg09"][0]():
257 return True
257 return True
258 return matchoutput('hg help annotate 2>&1', '--date')
258 return matchoutput('hg help annotate 2>&1', '--date')
259
259
260 @check("hg07", "Mercurial >= 0.7")
260 @check("hg07", "Mercurial >= 0.7")
261 def has_hg07():
261 def has_hg07():
262 if checks["hg08"][0]():
262 if checks["hg08"][0]():
263 return True
263 return True
264 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
264 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
265
265
266 @check("hg06", "Mercurial >= 0.6")
266 @check("hg06", "Mercurial >= 0.6")
267 def has_hg06():
267 def has_hg06():
268 if checks["hg07"][0]():
268 if checks["hg07"][0]():
269 return True
269 return True
270 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
270 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
271
271
272 @check("gettext", "GNU Gettext (msgfmt)")
272 @check("gettext", "GNU Gettext (msgfmt)")
273 def has_gettext():
273 def has_gettext():
274 return matchoutput('msgfmt --version', br'GNU gettext-tools')
274 return matchoutput('msgfmt --version', br'GNU gettext-tools')
275
275
276 @check("git", "git command line client")
276 @check("git", "git command line client")
277 def has_git():
277 def has_git():
278 return matchoutput('git --version 2>&1', br'^git version')
278 return matchoutput('git --version 2>&1', br'^git version')
279
279
280 @check("docutils", "Docutils text processing library")
280 @check("docutils", "Docutils text processing library")
281 def has_docutils():
281 def has_docutils():
282 try:
282 try:
283 import docutils.core
283 import docutils.core
284 docutils.core.publish_cmdline # silence unused import
284 docutils.core.publish_cmdline # silence unused import
285 return True
285 return True
286 except ImportError:
286 except ImportError:
287 return False
287 return False
288
288
289 def getsvnversion():
289 def getsvnversion():
290 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
290 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
291 if not m:
291 if not m:
292 return (0, 0)
292 return (0, 0)
293 return (int(m.group(1)), int(m.group(2)))
293 return (int(m.group(1)), int(m.group(2)))
294
294
295 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
295 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
296 def has_svn_range(v):
296 def has_svn_range(v):
297 major, minor = v.split('.')[0:2]
297 major, minor = v.split('.')[0:2]
298 return getsvnversion() >= (int(major), int(minor))
298 return getsvnversion() >= (int(major), int(minor))
299
299
300 @check("svn", "subversion client and admin tools")
300 @check("svn", "subversion client and admin tools")
301 def has_svn():
301 def has_svn():
302 return matchoutput('svn --version 2>&1', br'^svn, version') and \
302 return matchoutput('svn --version 2>&1', br'^svn, version') and \
303 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')
303 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')
304
304
305 @check("svn-bindings", "subversion python bindings")
305 @check("svn-bindings", "subversion python bindings")
306 def has_svn_bindings():
306 def has_svn_bindings():
307 try:
307 try:
308 import svn.core
308 import svn.core
309 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
309 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
310 if version < (1, 4):
310 if version < (1, 4):
311 return False
311 return False
312 return True
312 return True
313 except ImportError:
313 except ImportError:
314 return False
314 return False
315
315
316 @check("p4", "Perforce server and client")
316 @check("p4", "Perforce server and client")
317 def has_p4():
317 def has_p4():
318 return (matchoutput('p4 -V', br'Rev\. P4/') and
318 return (matchoutput('p4 -V', br'Rev\. P4/') and
319 matchoutput('p4d -V', br'Rev\. P4D/'))
319 matchoutput('p4d -V', br'Rev\. P4D/'))
320
320
321 @check("symlink", "symbolic links")
321 @check("symlink", "symbolic links")
322 def has_symlink():
322 def has_symlink():
323 if getattr(os, "symlink", None) is None:
323 if getattr(os, "symlink", None) is None:
324 return False
324 return False
325 name = tempfile.mktemp(dir='.', prefix=tempprefix)
325 name = tempfile.mktemp(dir='.', prefix=tempprefix)
326 try:
326 try:
327 os.symlink(".", name)
327 os.symlink(".", name)
328 os.unlink(name)
328 os.unlink(name)
329 return True
329 return True
330 except (OSError, AttributeError):
330 except (OSError, AttributeError):
331 return False
331 return False
332
332
333 @check("hardlink", "hardlinks")
333 @check("hardlink", "hardlinks")
334 def has_hardlink():
334 def has_hardlink():
335 from mercurial import util
335 from mercurial import util
336 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
336 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
337 os.close(fh)
337 os.close(fh)
338 name = tempfile.mktemp(dir='.', prefix=tempprefix)
338 name = tempfile.mktemp(dir='.', prefix=tempprefix)
339 try:
339 try:
340 util.oslink(fn, name)
340 util.oslink(fn, name)
341 os.unlink(name)
341 os.unlink(name)
342 return True
342 return True
343 except OSError:
343 except OSError:
344 return False
344 return False
345 finally:
345 finally:
346 os.unlink(fn)
346 os.unlink(fn)
347
347
348 @check("tla", "GNU Arch tla client")
348 @check("tla", "GNU Arch tla client")
349 def has_tla():
349 def has_tla():
350 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
350 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
351
351
352 @check("gpg", "gpg client")
352 @check("gpg", "gpg client")
353 def has_gpg():
353 def has_gpg():
354 return matchoutput('gpg --version 2>&1', br'GnuPG')
354 return matchoutput('gpg --version 2>&1', br'GnuPG')
355
355
356 @check("gpg2", "gpg client v2")
356 @check("gpg2", "gpg client v2")
357 def has_gpg2():
357 def has_gpg2():
358 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
358 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
359
359
360 @check("gpg21", "gpg client v2.1+")
361 def has_gpg21():
362 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
363
360 @check("unix-permissions", "unix-style permissions")
364 @check("unix-permissions", "unix-style permissions")
361 def has_unix_permissions():
365 def has_unix_permissions():
362 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
366 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
363 try:
367 try:
364 fname = os.path.join(d, 'foo')
368 fname = os.path.join(d, 'foo')
365 for umask in (0o77, 0o07, 0o22):
369 for umask in (0o77, 0o07, 0o22):
366 os.umask(umask)
370 os.umask(umask)
367 f = open(fname, 'w')
371 f = open(fname, 'w')
368 f.close()
372 f.close()
369 mode = os.stat(fname).st_mode
373 mode = os.stat(fname).st_mode
370 os.unlink(fname)
374 os.unlink(fname)
371 if mode & 0o777 != ~umask & 0o666:
375 if mode & 0o777 != ~umask & 0o666:
372 return False
376 return False
373 return True
377 return True
374 finally:
378 finally:
375 os.rmdir(d)
379 os.rmdir(d)
376
380
377 @check("unix-socket", "AF_UNIX socket family")
381 @check("unix-socket", "AF_UNIX socket family")
378 def has_unix_socket():
382 def has_unix_socket():
379 return getattr(socket, 'AF_UNIX', None) is not None
383 return getattr(socket, 'AF_UNIX', None) is not None
380
384
381 @check("root", "root permissions")
385 @check("root", "root permissions")
382 def has_root():
386 def has_root():
383 return getattr(os, 'geteuid', None) and os.geteuid() == 0
387 return getattr(os, 'geteuid', None) and os.geteuid() == 0
384
388
385 @check("pyflakes", "Pyflakes python linter")
389 @check("pyflakes", "Pyflakes python linter")
386 def has_pyflakes():
390 def has_pyflakes():
387 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
391 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
388 br"<stdin>:1: 're' imported but unused",
392 br"<stdin>:1: 're' imported but unused",
389 True)
393 True)
390
394
391 @check("pygments", "Pygments source highlighting library")
395 @check("pygments", "Pygments source highlighting library")
392 def has_pygments():
396 def has_pygments():
393 try:
397 try:
394 import pygments
398 import pygments
395 pygments.highlight # silence unused import warning
399 pygments.highlight # silence unused import warning
396 return True
400 return True
397 except ImportError:
401 except ImportError:
398 return False
402 return False
399
403
400 @check("outer-repo", "outer repo")
404 @check("outer-repo", "outer repo")
401 def has_outer_repo():
405 def has_outer_repo():
402 # failing for other reasons than 'no repo' imply that there is a repo
406 # failing for other reasons than 'no repo' imply that there is a repo
403 return not matchoutput('hg root 2>&1',
407 return not matchoutput('hg root 2>&1',
404 br'abort: no repository found', True)
408 br'abort: no repository found', True)
405
409
406 @check("ssl", "ssl module available")
410 @check("ssl", "ssl module available")
407 def has_ssl():
411 def has_ssl():
408 try:
412 try:
409 import ssl
413 import ssl
410 ssl.CERT_NONE
414 ssl.CERT_NONE
411 return True
415 return True
412 except ImportError:
416 except ImportError:
413 return False
417 return False
414
418
415 @check("sslcontext", "python >= 2.7.9 ssl")
419 @check("sslcontext", "python >= 2.7.9 ssl")
416 def has_sslcontext():
420 def has_sslcontext():
417 try:
421 try:
418 import ssl
422 import ssl
419 ssl.SSLContext
423 ssl.SSLContext
420 return True
424 return True
421 except (ImportError, AttributeError):
425 except (ImportError, AttributeError):
422 return False
426 return False
423
427
424 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
428 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
425 def has_defaultcacerts():
429 def has_defaultcacerts():
426 from mercurial import sslutil, ui as uimod
430 from mercurial import sslutil, ui as uimod
427 ui = uimod.ui()
431 ui = uimod.ui()
428 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
432 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
429
433
430 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
434 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
431 def has_defaultcacertsloaded():
435 def has_defaultcacertsloaded():
432 import ssl
436 import ssl
433 from mercurial import sslutil, ui as uimod
437 from mercurial import sslutil, ui as uimod
434
438
435 if not has_defaultcacerts():
439 if not has_defaultcacerts():
436 return False
440 return False
437 if not has_sslcontext():
441 if not has_sslcontext():
438 return False
442 return False
439
443
440 ui = uimod.ui()
444 ui = uimod.ui()
441 cafile = sslutil._defaultcacerts(ui)
445 cafile = sslutil._defaultcacerts(ui)
442 ctx = ssl.create_default_context()
446 ctx = ssl.create_default_context()
443 if cafile:
447 if cafile:
444 ctx.load_verify_locations(cafile=cafile)
448 ctx.load_verify_locations(cafile=cafile)
445 else:
449 else:
446 ctx.load_default_certs()
450 ctx.load_default_certs()
447
451
448 return len(ctx.get_ca_certs()) > 0
452 return len(ctx.get_ca_certs()) > 0
449
453
450 @check("tls1.2", "TLS 1.2 protocol support")
454 @check("tls1.2", "TLS 1.2 protocol support")
451 def has_tls1_2():
455 def has_tls1_2():
452 from mercurial import sslutil
456 from mercurial import sslutil
453 return 'tls1.2' in sslutil.supportedprotocols
457 return 'tls1.2' in sslutil.supportedprotocols
454
458
455 @check("windows", "Windows")
459 @check("windows", "Windows")
456 def has_windows():
460 def has_windows():
457 return os.name == 'nt'
461 return os.name == 'nt'
458
462
459 @check("system-sh", "system() uses sh")
463 @check("system-sh", "system() uses sh")
460 def has_system_sh():
464 def has_system_sh():
461 return os.name != 'nt'
465 return os.name != 'nt'
462
466
463 @check("serve", "platform and python can manage 'hg serve -d'")
467 @check("serve", "platform and python can manage 'hg serve -d'")
464 def has_serve():
468 def has_serve():
465 return os.name != 'nt' # gross approximation
469 return os.name != 'nt' # gross approximation
466
470
467 @check("test-repo", "running tests from repository")
471 @check("test-repo", "running tests from repository")
468 def has_test_repo():
472 def has_test_repo():
469 t = os.environ["TESTDIR"]
473 t = os.environ["TESTDIR"]
470 return os.path.isdir(os.path.join(t, "..", ".hg"))
474 return os.path.isdir(os.path.join(t, "..", ".hg"))
471
475
472 @check("tic", "terminfo compiler and curses module")
476 @check("tic", "terminfo compiler and curses module")
473 def has_tic():
477 def has_tic():
474 try:
478 try:
475 import curses
479 import curses
476 curses.COLOR_BLUE
480 curses.COLOR_BLUE
477 return matchoutput('test -x "`which tic`"', br'')
481 return matchoutput('test -x "`which tic`"', br'')
478 except ImportError:
482 except ImportError:
479 return False
483 return False
480
484
481 @check("msys", "Windows with MSYS")
485 @check("msys", "Windows with MSYS")
482 def has_msys():
486 def has_msys():
483 return os.getenv('MSYSTEM')
487 return os.getenv('MSYSTEM')
484
488
485 @check("aix", "AIX")
489 @check("aix", "AIX")
486 def has_aix():
490 def has_aix():
487 return sys.platform.startswith("aix")
491 return sys.platform.startswith("aix")
488
492
489 @check("osx", "OS X")
493 @check("osx", "OS X")
490 def has_osx():
494 def has_osx():
491 return sys.platform == 'darwin'
495 return sys.platform == 'darwin'
492
496
493 @check("osxpackaging", "OS X packaging tools")
497 @check("osxpackaging", "OS X packaging tools")
494 def has_osxpackaging():
498 def has_osxpackaging():
495 try:
499 try:
496 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
500 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
497 and matchoutput(
501 and matchoutput(
498 'productbuild', br'Usage: productbuild ',
502 'productbuild', br'Usage: productbuild ',
499 ignorestatus=1)
503 ignorestatus=1)
500 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
504 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
501 and matchoutput(
505 and matchoutput(
502 'xar --help', br'Usage: xar', ignorestatus=1))
506 'xar --help', br'Usage: xar', ignorestatus=1))
503 except ImportError:
507 except ImportError:
504 return False
508 return False
505
509
506 @check("docker", "docker support")
510 @check("docker", "docker support")
507 def has_docker():
511 def has_docker():
508 pat = br'A self-sufficient runtime for'
512 pat = br'A self-sufficient runtime for'
509 if matchoutput('docker --help', pat):
513 if matchoutput('docker --help', pat):
510 if 'linux' not in sys.platform:
514 if 'linux' not in sys.platform:
511 # TODO: in theory we should be able to test docker-based
515 # TODO: in theory we should be able to test docker-based
512 # package creation on non-linux using boot2docker, but in
516 # package creation on non-linux using boot2docker, but in
513 # practice that requires extra coordination to make sure
517 # practice that requires extra coordination to make sure
514 # $TESTTEMP is going to be visible at the same path to the
518 # $TESTTEMP is going to be visible at the same path to the
515 # boot2docker VM. If we figure out how to verify that, we
519 # boot2docker VM. If we figure out how to verify that, we
516 # can use the following instead of just saying False:
520 # can use the following instead of just saying False:
517 # return 'DOCKER_HOST' in os.environ
521 # return 'DOCKER_HOST' in os.environ
518 return False
522 return False
519
523
520 return True
524 return True
521 return False
525 return False
522
526
523 @check("debhelper", "debian packaging tools")
527 @check("debhelper", "debian packaging tools")
524 def has_debhelper():
528 def has_debhelper():
525 dpkg = matchoutput('dpkg --version',
529 dpkg = matchoutput('dpkg --version',
526 br"Debian `dpkg' package management program")
530 br"Debian `dpkg' package management program")
527 dh = matchoutput('dh --help',
531 dh = matchoutput('dh --help',
528 br'dh is a part of debhelper.', ignorestatus=True)
532 br'dh is a part of debhelper.', ignorestatus=True)
529 dh_py2 = matchoutput('dh_python2 --help',
533 dh_py2 = matchoutput('dh_python2 --help',
530 br'other supported Python versions')
534 br'other supported Python versions')
531 return dpkg and dh and dh_py2
535 return dpkg and dh and dh_py2
532
536
533 @check("demandimport", "demandimport enabled")
537 @check("demandimport", "demandimport enabled")
534 def has_demandimport():
538 def has_demandimport():
535 return os.environ.get('HGDEMANDIMPORT') != 'disable'
539 return os.environ.get('HGDEMANDIMPORT') != 'disable'
536
540
537 @check("absimport", "absolute_import in __future__")
541 @check("absimport", "absolute_import in __future__")
538 def has_absimport():
542 def has_absimport():
539 import __future__
543 import __future__
540 from mercurial import util
544 from mercurial import util
541 return util.safehasattr(__future__, "absolute_import")
545 return util.safehasattr(__future__, "absolute_import")
542
546
543 @check("py27+", "running with Python 2.7+")
547 @check("py27+", "running with Python 2.7+")
544 def has_python27ornewer():
548 def has_python27ornewer():
545 return sys.version_info[0:2] >= (2, 7)
549 return sys.version_info[0:2] >= (2, 7)
546
550
547 @check("py3k", "running with Python 3.x")
551 @check("py3k", "running with Python 3.x")
548 def has_py3k():
552 def has_py3k():
549 return 3 == sys.version_info[0]
553 return 3 == sys.version_info[0]
550
554
551 @check("py3exe", "a Python 3.x interpreter is available")
555 @check("py3exe", "a Python 3.x interpreter is available")
552 def has_python3exe():
556 def has_python3exe():
553 return 'PYTHON3' in os.environ
557 return 'PYTHON3' in os.environ
554
558
555 @check("py3pygments", "Pygments available on Python 3.x")
559 @check("py3pygments", "Pygments available on Python 3.x")
556 def has_py3pygments():
560 def has_py3pygments():
557 if has_py3k():
561 if has_py3k():
558 return has_pygments()
562 return has_pygments()
559 elif has_python3exe():
563 elif has_python3exe():
560 # just check exit status (ignoring output)
564 # just check exit status (ignoring output)
561 py3 = os.environ['PYTHON3']
565 py3 = os.environ['PYTHON3']
562 return matchoutput('%s -c "import pygments"' % py3, br'')
566 return matchoutput('%s -c "import pygments"' % py3, br'')
563 return False
567 return False
564
568
565 @check("pure", "running with pure Python code")
569 @check("pure", "running with pure Python code")
566 def has_pure():
570 def has_pure():
567 return any([
571 return any([
568 os.environ.get("HGMODULEPOLICY") == "py",
572 os.environ.get("HGMODULEPOLICY") == "py",
569 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
573 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
570 ])
574 ])
571
575
572 @check("slow", "allow slow tests")
576 @check("slow", "allow slow tests")
573 def has_slow():
577 def has_slow():
574 return os.environ.get('HGTEST_SLOW') == 'slow'
578 return os.environ.get('HGTEST_SLOW') == 'slow'
575
579
576 @check("hypothesis", "Hypothesis automated test generation")
580 @check("hypothesis", "Hypothesis automated test generation")
577 def has_hypothesis():
581 def has_hypothesis():
578 try:
582 try:
579 import hypothesis
583 import hypothesis
580 hypothesis.given
584 hypothesis.given
581 return True
585 return True
582 except ImportError:
586 except ImportError:
583 return False
587 return False
584
588
585 @check("unziplinks", "unzip(1) understands and extracts symlinks")
589 @check("unziplinks", "unzip(1) understands and extracts symlinks")
586 def unzip_understands_symlinks():
590 def unzip_understands_symlinks():
587 return matchoutput('unzip --help', br'Info-ZIP')
591 return matchoutput('unzip --help', br'Info-ZIP')
@@ -1,51 +1,56
1 #require gpg
1 #require gpg
2
2
3 Test the GPG extension
3 Test the GPG extension
4
4
5 $ cat <<EOF >> $HGRCPATH
5 $ cat <<EOF >> $HGRCPATH
6 > [extensions]
6 > [extensions]
7 > gpg=
7 > gpg=
8 >
8 >
9 > [gpg]
9 > [gpg]
10 > cmd=gpg --no-permission-warning --no-secmem-warning --no-auto-check-trustdb
10 > cmd=gpg --no-permission-warning --no-secmem-warning --no-auto-check-trustdb
11 > EOF
11 > EOF
12 $ GNUPGHOME="$TESTTMP/gpg"; export GNUPGHOME
12 $ GNUPGHOME="$TESTTMP/gpg"; export GNUPGHOME
13 $ cp -R "$TESTDIR/gpg" "$GNUPGHOME"
13 $ cp -R "$TESTDIR/gpg" "$GNUPGHOME"
14
14
15 Start gpg-agent, which is required by GnuPG v2, and migrate secret keys
15 Start gpg-agent, which is required by GnuPG v2
16
17 #if gpg21
18 $ gpg-connect-agent -q --subst /serverpid '/echo ${get serverpid}' /bye \
19 > >> $DAEMON_PIDS
20 #endif
21
22 and migrate secret keys
16
23
17 #if gpg2
24 #if gpg2
18 $ gpg-connect-agent -q --subst /serverpid '/echo ${get serverpid}' /bye \
19 > >> $DAEMON_PIDS
20 $ gpg --no-permission-warning --no-secmem-warning --list-secret-keys \
25 $ gpg --no-permission-warning --no-secmem-warning --list-secret-keys \
21 > > /dev/null 2>&1
26 > > /dev/null 2>&1
22 #endif
27 #endif
23
28
24 $ hg init r
29 $ hg init r
25 $ cd r
30 $ cd r
26 $ echo foo > foo
31 $ echo foo > foo
27 $ hg ci -Amfoo
32 $ hg ci -Amfoo
28 adding foo
33 adding foo
29
34
30 $ hg sigs
35 $ hg sigs
31
36
32 $ HGEDITOR=cat hg sign -e 0
37 $ HGEDITOR=cat hg sign -e 0
33 signing 0:e63c23eaa88a
38 signing 0:e63c23eaa88a
34 Added signature for changeset e63c23eaa88a
39 Added signature for changeset e63c23eaa88a
35
40
36
41
37 HG: Enter commit message. Lines beginning with 'HG:' are removed.
42 HG: Enter commit message. Lines beginning with 'HG:' are removed.
38 HG: Leave message empty to abort commit.
43 HG: Leave message empty to abort commit.
39 HG: --
44 HG: --
40 HG: user: test
45 HG: user: test
41 HG: branch 'default'
46 HG: branch 'default'
42 HG: added .hgsigs
47 HG: added .hgsigs
43
48
44 $ hg sigs
49 $ hg sigs
45 hgtest 0:e63c23eaa88ae77967edcf4ea194d31167c478b0
50 hgtest 0:e63c23eaa88ae77967edcf4ea194d31167c478b0
46
51
47 $ hg sigcheck 0
52 $ hg sigcheck 0
48 e63c23eaa88a is signed by:
53 e63c23eaa88a is signed by:
49 hgtest
54 hgtest
50
55
51 $ cd ..
56 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now