##// END OF EJS Templates
hghave: use a less brittle have-json check
Augie Fackler -
r23262:86a8658c default
parent child Browse files
Show More
@@ -1,364 +1,367
1 1 import os, stat
2 2 import re
3 3 import socket
4 4 import sys
5 5 import tempfile
6 6
7 7 tempprefix = 'hg-hghave-'
8 8
9 9 checks = {
10 10 "true": (lambda: True, "yak shaving"),
11 11 "false": (lambda: False, "nail clipper"),
12 12 }
13 13
14 14 def check(name, desc):
15 15 def decorator(func):
16 16 checks[name] = (func, desc)
17 17 return func
18 18 return decorator
19 19
20 20 def matchoutput(cmd, regexp, ignorestatus=False):
21 21 """Return True if cmd executes successfully and its output
22 22 is matched by the supplied regular expression.
23 23 """
24 24 r = re.compile(regexp)
25 25 fh = os.popen(cmd)
26 26 s = fh.read()
27 27 try:
28 28 ret = fh.close()
29 29 except IOError:
30 30 # Happen in Windows test environment
31 31 ret = 1
32 32 return (ignorestatus or ret is None) and r.search(s)
33 33
34 34 @check("baz", "GNU Arch baz client")
35 35 def has_baz():
36 36 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
37 37
38 38 @check("bzr", "Canonical's Bazaar client")
39 39 def has_bzr():
40 40 try:
41 41 import bzrlib
42 42 return bzrlib.__doc__ is not None
43 43 except ImportError:
44 44 return False
45 45
46 46 @check("bzr114", "Canonical's Bazaar client >= 1.14")
47 47 def has_bzr114():
48 48 try:
49 49 import bzrlib
50 50 return (bzrlib.__doc__ is not None
51 51 and bzrlib.version_info[:2] >= (1, 14))
52 52 except ImportError:
53 53 return False
54 54
55 55 @check("cvs", "cvs client/server")
56 56 def has_cvs():
57 57 re = r'Concurrent Versions System.*?server'
58 58 return matchoutput('cvs --version 2>&1', re) and not has_msys()
59 59
60 60 @check("cvs112", "cvs client/server >= 1.12")
61 61 def has_cvs112():
62 62 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
63 63 return matchoutput('cvs --version 2>&1', re) and not has_msys()
64 64
65 65 @check("darcs", "darcs client")
66 66 def has_darcs():
67 67 return matchoutput('darcs --version', r'2\.[2-9]', True)
68 68
69 69 @check("mtn", "monotone client (>= 1.0)")
70 70 def has_mtn():
71 71 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
72 72 'mtn --version', r'monotone 0\.', True)
73 73
74 74 @check("eol-in-paths", "end-of-lines in paths")
75 75 def has_eol_in_paths():
76 76 try:
77 77 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
78 78 os.close(fd)
79 79 os.remove(path)
80 80 return True
81 81 except (IOError, OSError):
82 82 return False
83 83
84 84 @check("execbit", "executable bit")
85 85 def has_executablebit():
86 86 try:
87 87 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
88 88 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
89 89 try:
90 90 os.close(fh)
91 91 m = os.stat(fn).st_mode & 0777
92 92 new_file_has_exec = m & EXECFLAGS
93 93 os.chmod(fn, m ^ EXECFLAGS)
94 94 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
95 95 finally:
96 96 os.unlink(fn)
97 97 except (IOError, OSError):
98 98 # we don't care, the user probably won't be able to commit anyway
99 99 return False
100 100 return not (new_file_has_exec or exec_flags_cannot_flip)
101 101
102 102 @check("icasefs", "case insensitive file system")
103 103 def has_icasefs():
104 104 # Stolen from mercurial.util
105 105 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
106 106 os.close(fd)
107 107 try:
108 108 s1 = os.stat(path)
109 109 d, b = os.path.split(path)
110 110 p2 = os.path.join(d, b.upper())
111 111 if path == p2:
112 112 p2 = os.path.join(d, b.lower())
113 113 try:
114 114 s2 = os.stat(p2)
115 115 return s2 == s1
116 116 except OSError:
117 117 return False
118 118 finally:
119 119 os.remove(path)
120 120
121 121 @check("fifo", "named pipes")
122 122 def has_fifo():
123 123 if getattr(os, "mkfifo", None) is None:
124 124 return False
125 125 name = tempfile.mktemp(dir='.', prefix=tempprefix)
126 126 try:
127 127 os.mkfifo(name)
128 128 os.unlink(name)
129 129 return True
130 130 except OSError:
131 131 return False
132 132
133 133 @check("killdaemons", 'killdaemons.py support')
134 134 def has_killdaemons():
135 135 return True
136 136
137 137 @check("cacheable", "cacheable filesystem")
138 138 def has_cacheable_fs():
139 139 from mercurial import util
140 140
141 141 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
142 142 os.close(fd)
143 143 try:
144 144 return util.cachestat(path).cacheable()
145 145 finally:
146 146 os.remove(path)
147 147
148 148 @check("lsprof", "python lsprof module")
149 149 def has_lsprof():
150 150 try:
151 151 import _lsprof
152 152 _lsprof.Profiler # silence unused import warning
153 153 return True
154 154 except ImportError:
155 155 return False
156 156
157 157 @check("gettext", "GNU Gettext (msgfmt)")
158 158 def has_gettext():
159 159 return matchoutput('msgfmt --version', 'GNU gettext-tools')
160 160
161 161 @check("git", "git command line client")
162 162 def has_git():
163 163 return matchoutput('git --version 2>&1', r'^git version')
164 164
165 165 @check("docutils", "Docutils text processing library")
166 166 def has_docutils():
167 167 try:
168 168 from docutils.core import publish_cmdline
169 169 publish_cmdline # silence unused import
170 170 return True
171 171 except ImportError:
172 172 return False
173 173
174 174 def getsvnversion():
175 175 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
176 176 if not m:
177 177 return (0, 0)
178 178 return (int(m.group(1)), int(m.group(2)))
179 179
180 180 @check("svn15", "subversion client and admin tools >= 1.5")
181 181 def has_svn15():
182 182 return getsvnversion() >= (1, 5)
183 183
184 184 @check("svn13", "subversion client and admin tools >= 1.3")
185 185 def has_svn13():
186 186 return getsvnversion() >= (1, 3)
187 187
188 188 @check("svn", "subversion client and admin tools")
189 189 def has_svn():
190 190 return matchoutput('svn --version 2>&1', r'^svn, version') and \
191 191 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
192 192
193 193 @check("svn-bindings", "subversion python bindings")
194 194 def has_svn_bindings():
195 195 try:
196 196 import svn.core
197 197 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
198 198 if version < (1, 4):
199 199 return False
200 200 return True
201 201 except ImportError:
202 202 return False
203 203
204 204 @check("p4", "Perforce server and client")
205 205 def has_p4():
206 206 return (matchoutput('p4 -V', r'Rev\. P4/') and
207 207 matchoutput('p4d -V', r'Rev\. P4D/'))
208 208
209 209 @check("symlink", "symbolic links")
210 210 def has_symlink():
211 211 if getattr(os, "symlink", None) is None:
212 212 return False
213 213 name = tempfile.mktemp(dir='.', prefix=tempprefix)
214 214 try:
215 215 os.symlink(".", name)
216 216 os.unlink(name)
217 217 return True
218 218 except (OSError, AttributeError):
219 219 return False
220 220
221 221 @check("hardlink", "hardlinks")
222 222 def has_hardlink():
223 223 from mercurial import util
224 224 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
225 225 os.close(fh)
226 226 name = tempfile.mktemp(dir='.', prefix=tempprefix)
227 227 try:
228 228 try:
229 229 util.oslink(fn, name)
230 230 os.unlink(name)
231 231 return True
232 232 except OSError:
233 233 return False
234 234 finally:
235 235 os.unlink(fn)
236 236
237 237 @check("tla", "GNU Arch tla client")
238 238 def has_tla():
239 239 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
240 240
241 241 @check("gpg", "gpg client")
242 242 def has_gpg():
243 243 return matchoutput('gpg --version 2>&1', r'GnuPG')
244 244
245 245 @check("unix-permissions", "unix-style permissions")
246 246 def has_unix_permissions():
247 247 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
248 248 try:
249 249 fname = os.path.join(d, 'foo')
250 250 for umask in (077, 007, 022):
251 251 os.umask(umask)
252 252 f = open(fname, 'w')
253 253 f.close()
254 254 mode = os.stat(fname).st_mode
255 255 os.unlink(fname)
256 256 if mode & 0777 != ~umask & 0666:
257 257 return False
258 258 return True
259 259 finally:
260 260 os.rmdir(d)
261 261
262 262 @check("unix-socket", "AF_UNIX socket family")
263 263 def has_unix_socket():
264 264 return getattr(socket, 'AF_UNIX', None) is not None
265 265
266 266 @check("root", "root permissions")
267 267 def has_root():
268 268 return getattr(os, 'geteuid', None) and os.geteuid() == 0
269 269
270 270 @check("pyflakes", "Pyflakes python linter")
271 271 def has_pyflakes():
272 272 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
273 273 r"<stdin>:1: 're' imported but unused",
274 274 True)
275 275
276 276 @check("pygments", "Pygments source highlighting library")
277 277 def has_pygments():
278 278 try:
279 279 import pygments
280 280 pygments.highlight # silence unused import warning
281 281 return True
282 282 except ImportError:
283 283 return False
284 284
285 285 @check("python243", "python >= 2.4.3")
286 286 def has_python243():
287 287 return sys.version_info >= (2, 4, 3)
288 288
289 289 @check("json", "some json module available")
290 290 def has_json():
291 291 try:
292 if sys.version_info < (2, 7):
293 import simplejson as json
294 else:
295 import json
292 import json
296 293 json.dumps
297 294 return True
298 295 except ImportError:
299 return False
296 try:
297 import simplejson as json
298 json.dumps
299 return True
300 except ImportError:
301 pass
302 return False
300 303
301 304 @check("outer-repo", "outer repo")
302 305 def has_outer_repo():
303 306 # failing for other reasons than 'no repo' imply that there is a repo
304 307 return not matchoutput('hg root 2>&1',
305 308 r'abort: no repository found', True)
306 309
307 310 @check("ssl", "python >= 2.6 ssl module and python OpenSSL")
308 311 def has_ssl():
309 312 try:
310 313 import ssl
311 314 ssl.wrap_socket # silence unused import warning
312 315 import OpenSSL
313 316 OpenSSL.SSL.Context
314 317 return True
315 318 except ImportError:
316 319 return False
317 320
318 321 @check("windows", "Windows")
319 322 def has_windows():
320 323 return os.name == 'nt'
321 324
322 325 @check("system-sh", "system() uses sh")
323 326 def has_system_sh():
324 327 return os.name != 'nt'
325 328
326 329 @check("serve", "platform and python can manage 'hg serve -d'")
327 330 def has_serve():
328 331 return os.name != 'nt' # gross approximation
329 332
330 333 @check("test-repo", "running tests from repository")
331 334 def has_test_repo():
332 335 t = os.environ["TESTDIR"]
333 336 return os.path.isdir(os.path.join(t, "..", ".hg"))
334 337
335 338 @check("tic", "terminfo compiler and curses module")
336 339 def has_tic():
337 340 try:
338 341 import curses
339 342 curses.COLOR_BLUE
340 343 return matchoutput('test -x "`which tic`"', '')
341 344 except ImportError:
342 345 return False
343 346
344 347 @check("msys", "Windows with MSYS")
345 348 def has_msys():
346 349 return os.getenv('MSYSTEM')
347 350
348 351 @check("aix", "AIX")
349 352 def has_aix():
350 353 return sys.platform.startswith("aix")
351 354
352 355 @check("osx", "OS X")
353 356 def has_osx():
354 357 return sys.platform == 'darwin'
355 358
356 359 @check("absimport", "absolute_import in __future__")
357 360 def has_absimport():
358 361 import __future__
359 362 from mercurial import util
360 363 return util.safehasattr(__future__, "absolute_import")
361 364
362 365 @check("py3k", "running with Python 3.x")
363 366 def has_py3k():
364 367 return 3 == sys.version_info[0]
General Comments 0
You need to be logged in to leave comments. Login now