##// END OF EJS Templates
tests: add tests about diff quality...
Jun Wu -
r36696:7834927f default
parent child Browse files
Show More
@@ -0,0 +1,91 b''
1 #testcases bdiff xdiff
2
3 #if xdiff
4 #require xdiff
5 $ cat >> $HGRCPATH <<EOF
6 > [experimental]
7 > xdiff = true
8 > EOF
9 #endif
10
11 Test case that makes use of the weakness of patience diff algorithm
12
13 $ hg init
14 >>> open('a', 'wb').write(b'\n'.join(list(b'a' + b'x' * 10 + b'u' + b'x' * 30 + b'a\n')))
15 $ hg commit -m 1 -A a
16 >>> open('a', 'wb').write(b'\n'.join(list(b'b' + b'x' * 30 + b'u' + b'x' * 10 + b'b\n')))
17 #if xdiff
18 $ hg diff
19 diff -r f0aeecb49805 a
20 --- a/a Thu Jan 01 00:00:00 1970 +0000
21 +++ b/a Thu Jan 01 00:00:00 1970 +0000
22 @@ -1,4 +1,4 @@
23 -a
24 +b
25 x
26 x
27 x
28 @@ -9,7 +9,6 @@
29 x
30 x
31 x
32 -u
33 x
34 x
35 x
36 @@ -30,6 +29,7 @@
37 x
38 x
39 x
40 +u
41 x
42 x
43 x
44 @@ -40,5 +40,5 @@
45 x
46 x
47 x
48 -a
49 +b
50
51 #else
52 $ hg diff
53 diff -r f0aeecb49805 a
54 --- a/a Thu Jan 01 00:00:00 1970 +0000
55 +++ b/a Thu Jan 01 00:00:00 1970 +0000
56 @@ -1,15 +1,4 @@
57 -a
58 -x
59 -x
60 -x
61 -x
62 -x
63 -x
64 -x
65 -x
66 -x
67 -x
68 -u
69 +b
70 x
71 x
72 x
73 @@ -40,5 +29,16 @@
74 x
75 x
76 x
77 -a
78 +u
79 +x
80 +x
81 +x
82 +x
83 +x
84 +x
85 +x
86 +x
87 +x
88 +x
89 +b
90
91 #endif
@@ -0,0 +1,339 b''
1 #testcases bdiff xdiff
2
3 #if xdiff
4 #require xdiff
5 $ cat >> $HGRCPATH <<EOF
6 > [experimental]
7 > xdiff = true
8 > EOF
9 #endif
10
11 $ hg init
12
13 $ cat > a.c <<'EOF'
14 > /*
15 > * This function returns 1.
16 > */
17 > int f() {
18 > return 1;
19 > }
20 > /*
21 > * This function returns 2.
22 > */
23 > int g() {
24 > return 2;
25 > }
26 > /*
27 > * This function returns 3.
28 > */
29 > int h() {
30 > return 3;
31 > }
32 > EOF
33
34 $ cat > b.c <<'EOF'
35 > if (x) {
36 > do_something();
37 > }
38 >
39 > if (y) {
40 > do_something_else();
41 > }
42 > EOF
43
44 $ cat > c.rb <<'EOF'
45 > #!ruby
46 > ["foo", "bar", "baz"].map do |i|
47 > i.upcase
48 > end
49 > EOF
50
51 $ cat > d.py <<'EOF'
52 > try:
53 > import foo
54 > except ImportError:
55 > pass
56 > try:
57 > import bar
58 > except ImportError:
59 > pass
60 > EOF
61
62 The below two files are taken from git: t/t4061-diff-indent.sh
63
64 $ cat > spaces.txt <<'EOF'
65 > 1
66 > 2
67 > a
68 >
69 > b
70 > 3
71 > 4
72 > EOF
73
74 $ cat > functions.c <<'EOF'
75 > 1
76 > 2
77 > /* function */
78 > foo() {
79 > foo
80 > }
81 >
82 > 3
83 > 4
84 > EOF
85
86 $ hg commit -m 1 -A . -q
87
88 $ cat > a.c <<'EOF'
89 > /*
90 > * This function returns 1.
91 > */
92 > int f() {
93 > return 1;
94 > }
95 > /*
96 > * This function returns 3.
97 > */
98 > int h() {
99 > return 3;
100 > }
101 > EOF
102
103 $ cat > b.c <<'EOF'
104 > if (x) {
105 > do_something();
106 > }
107 >
108 > if (y) {
109 > do_another_thing();
110 > }
111 >
112 > if (y) {
113 > do_something_else();
114 > }
115 > EOF
116
117 $ cat > c.rb <<'EOF'
118 > #!ruby
119 > ["foo", "bar", "baz"].map do |i|
120 > i
121 > end
122 > ["foo", "bar", "baz"].map do |i|
123 > i.upcase
124 > end
125 > EOF
126
127 $ cat > d.py <<'EOF'
128 > try:
129 > import foo
130 > except ImportError:
131 > pass
132 > try:
133 > import baz
134 > except ImportError:
135 > pass
136 > try:
137 > import bar
138 > except ImportError:
139 > pass
140 > EOF
141
142 $ cat > spaces.txt <<'EOF'
143 > 1
144 > 2
145 > a
146 >
147 > b
148 > a
149 >
150 > b
151 > 3
152 > 4
153 > EOF
154
155 $ cat > functions.c <<'EOF'
156 > 1
157 > 2
158 > /* function */
159 > bar() {
160 > foo
161 > }
162 >
163 > /* function */
164 > foo() {
165 > foo
166 > }
167 >
168 > 3
169 > 4
170 > EOF
171
172 #if xdiff
173 $ hg diff --git
174 diff --git a/a.c b/a.c
175 --- a/a.c
176 +++ b/a.c
177 @@ -4,12 +4,6 @@
178 int f() {
179 return 1;
180 }
181 -/*
182 - * This function returns 2.
183 - */
184 -int g() {
185 - return 2;
186 -}
187 /*
188 * This function returns 3.
189 */
190 diff --git a/b.c b/b.c
191 --- a/b.c
192 +++ b/b.c
193 @@ -2,6 +2,10 @@
194 do_something();
195 }
196
197 +if (y) {
198 + do_another_thing();
199 +}
200 +
201 if (y) {
202 do_something_else();
203 }
204 diff --git a/c.rb b/c.rb
205 --- a/c.rb
206 +++ b/c.rb
207 @@ -1,4 +1,7 @@
208 #!ruby
209 +["foo", "bar", "baz"].map do |i|
210 + i
211 +end
212 ["foo", "bar", "baz"].map do |i|
213 i.upcase
214 end
215 diff --git a/d.py b/d.py
216 --- a/d.py
217 +++ b/d.py
218 @@ -2,6 +2,10 @@
219 import foo
220 except ImportError:
221 pass
222 +try:
223 + import baz
224 +except ImportError:
225 + pass
226 try:
227 import bar
228 except ImportError:
229 diff --git a/functions.c b/functions.c
230 --- a/functions.c
231 +++ b/functions.c
232 @@ -1,5 +1,10 @@
233 1
234 2
235 +/* function */
236 +bar() {
237 + foo
238 +}
239 +
240 /* function */
241 foo() {
242 foo
243 diff --git a/spaces.txt b/spaces.txt
244 --- a/spaces.txt
245 +++ b/spaces.txt
246 @@ -2,6 +2,9 @@
247 2
248 a
249
250 +b
251 +a
252 +
253 b
254 3
255 4
256 #else
257 $ hg diff --git
258 diff --git a/a.c b/a.c
259 --- a/a.c
260 +++ b/a.c
261 @@ -5,12 +5,6 @@
262 return 1;
263 }
264 /*
265 - * This function returns 2.
266 - */
267 -int g() {
268 - return 2;
269 -}
270 -/*
271 * This function returns 3.
272 */
273 int h() {
274 diff --git a/b.c b/b.c
275 --- a/b.c
276 +++ b/b.c
277 @@ -3,5 +3,9 @@
278 }
279
280 if (y) {
281 + do_another_thing();
282 +}
283 +
284 +if (y) {
285 do_something_else();
286 }
287 diff --git a/c.rb b/c.rb
288 --- a/c.rb
289 +++ b/c.rb
290 @@ -1,4 +1,7 @@
291 #!ruby
292 ["foo", "bar", "baz"].map do |i|
293 + i
294 +end
295 +["foo", "bar", "baz"].map do |i|
296 i.upcase
297 end
298 diff --git a/d.py b/d.py
299 --- a/d.py
300 +++ b/d.py
301 @@ -3,6 +3,10 @@
302 except ImportError:
303 pass
304 try:
305 + import baz
306 +except ImportError:
307 + pass
308 +try:
309 import bar
310 except ImportError:
311 pass
312 diff --git a/functions.c b/functions.c
313 --- a/functions.c
314 +++ b/functions.c
315 @@ -1,6 +1,11 @@
316 1
317 2
318 /* function */
319 +bar() {
320 + foo
321 +}
322 +
323 +/* function */
324 foo() {
325 foo
326 }
327 diff --git a/spaces.txt b/spaces.txt
328 --- a/spaces.txt
329 +++ b/spaces.txt
330 @@ -3,5 +3,8 @@
331 a
332
333 b
334 +a
335 +
336 +b
337 3
338 4
339 #endif
@@ -1,710 +1,719 b''
1 1 from __future__ import absolute_import
2 2
3 3 import errno
4 4 import os
5 5 import re
6 6 import socket
7 7 import stat
8 8 import subprocess
9 9 import sys
10 10 import tempfile
11 11
12 12 tempprefix = 'hg-hghave-'
13 13
14 14 checks = {
15 15 "true": (lambda: True, "yak shaving"),
16 16 "false": (lambda: False, "nail clipper"),
17 17 }
18 18
19 19 def check(name, desc):
20 20 """Registers a check function for a feature."""
21 21 def decorator(func):
22 22 checks[name] = (func, desc)
23 23 return func
24 24 return decorator
25 25
26 26 def checkvers(name, desc, vers):
27 27 """Registers a check function for each of a series of versions.
28 28
29 29 vers can be a list or an iterator"""
30 30 def decorator(func):
31 31 def funcv(v):
32 32 def f():
33 33 return func(v)
34 34 return f
35 35 for v in vers:
36 36 v = str(v)
37 37 f = funcv(v)
38 38 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
39 39 return func
40 40 return decorator
41 41
42 42 def checkfeatures(features):
43 43 result = {
44 44 'error': [],
45 45 'missing': [],
46 46 'skipped': [],
47 47 }
48 48
49 49 for feature in features:
50 50 negate = feature.startswith('no-')
51 51 if negate:
52 52 feature = feature[3:]
53 53
54 54 if feature not in checks:
55 55 result['missing'].append(feature)
56 56 continue
57 57
58 58 check, desc = checks[feature]
59 59 try:
60 60 available = check()
61 61 except Exception:
62 62 result['error'].append('hghave check failed: %s' % feature)
63 63 continue
64 64
65 65 if not negate and not available:
66 66 result['skipped'].append('missing feature: %s' % desc)
67 67 elif negate and available:
68 68 result['skipped'].append('system supports %s' % desc)
69 69
70 70 return result
71 71
72 72 def require(features):
73 73 """Require that features are available, exiting if not."""
74 74 result = checkfeatures(features)
75 75
76 76 for missing in result['missing']:
77 77 sys.stderr.write('skipped: unknown feature: %s\n' % missing)
78 78 for msg in result['skipped']:
79 79 sys.stderr.write('skipped: %s\n' % msg)
80 80 for msg in result['error']:
81 81 sys.stderr.write('%s\n' % msg)
82 82
83 83 if result['missing']:
84 84 sys.exit(2)
85 85
86 86 if result['skipped'] or result['error']:
87 87 sys.exit(1)
88 88
89 89 def matchoutput(cmd, regexp, ignorestatus=False):
90 90 """Return the match object if cmd executes successfully and its output
91 91 is matched by the supplied regular expression.
92 92 """
93 93 r = re.compile(regexp)
94 94 try:
95 95 p = subprocess.Popen(
96 96 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
97 97 except OSError as e:
98 98 if e.errno != errno.ENOENT:
99 99 raise
100 100 ret = -1
101 101 ret = p.wait()
102 102 s = p.stdout.read()
103 103 return (ignorestatus or not ret) and r.search(s)
104 104
105 105 @check("baz", "GNU Arch baz client")
106 106 def has_baz():
107 107 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
108 108
109 109 @check("bzr", "Canonical's Bazaar client")
110 110 def has_bzr():
111 111 try:
112 112 import bzrlib
113 113 import bzrlib.bzrdir
114 114 import bzrlib.errors
115 115 import bzrlib.revision
116 116 import bzrlib.revisionspec
117 117 bzrlib.revisionspec.RevisionSpec
118 118 return bzrlib.__doc__ is not None
119 119 except (AttributeError, ImportError):
120 120 return False
121 121
122 122 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
123 123 def has_bzr_range(v):
124 124 major, minor = v.split('.')[0:2]
125 125 try:
126 126 import bzrlib
127 127 return (bzrlib.__doc__ is not None
128 128 and bzrlib.version_info[:2] >= (int(major), int(minor)))
129 129 except ImportError:
130 130 return False
131 131
132 132 @check("chg", "running with chg")
133 133 def has_chg():
134 134 return 'CHGHG' in os.environ
135 135
136 136 @check("cvs", "cvs client/server")
137 137 def has_cvs():
138 138 re = br'Concurrent Versions System.*?server'
139 139 return matchoutput('cvs --version 2>&1', re) and not has_msys()
140 140
141 141 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
142 142 def has_cvs112():
143 143 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
144 144 return matchoutput('cvs --version 2>&1', re) and not has_msys()
145 145
146 146 @check("cvsnt", "cvsnt client/server")
147 147 def has_cvsnt():
148 148 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
149 149 return matchoutput('cvsnt --version 2>&1', re)
150 150
151 151 @check("darcs", "darcs client")
152 152 def has_darcs():
153 153 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
154 154
155 155 @check("mtn", "monotone client (>= 1.0)")
156 156 def has_mtn():
157 157 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
158 158 'mtn --version', br'monotone 0\.', True)
159 159
160 160 @check("eol-in-paths", "end-of-lines in paths")
161 161 def has_eol_in_paths():
162 162 try:
163 163 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
164 164 os.close(fd)
165 165 os.remove(path)
166 166 return True
167 167 except (IOError, OSError):
168 168 return False
169 169
170 170 @check("execbit", "executable bit")
171 171 def has_executablebit():
172 172 try:
173 173 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
174 174 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
175 175 try:
176 176 os.close(fh)
177 177 m = os.stat(fn).st_mode & 0o777
178 178 new_file_has_exec = m & EXECFLAGS
179 179 os.chmod(fn, m ^ EXECFLAGS)
180 180 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
181 181 finally:
182 182 os.unlink(fn)
183 183 except (IOError, OSError):
184 184 # we don't care, the user probably won't be able to commit anyway
185 185 return False
186 186 return not (new_file_has_exec or exec_flags_cannot_flip)
187 187
188 188 @check("icasefs", "case insensitive file system")
189 189 def has_icasefs():
190 190 # Stolen from mercurial.util
191 191 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
192 192 os.close(fd)
193 193 try:
194 194 s1 = os.stat(path)
195 195 d, b = os.path.split(path)
196 196 p2 = os.path.join(d, b.upper())
197 197 if path == p2:
198 198 p2 = os.path.join(d, b.lower())
199 199 try:
200 200 s2 = os.stat(p2)
201 201 return s2 == s1
202 202 except OSError:
203 203 return False
204 204 finally:
205 205 os.remove(path)
206 206
207 207 @check("fifo", "named pipes")
208 208 def has_fifo():
209 209 if getattr(os, "mkfifo", None) is None:
210 210 return False
211 211 name = tempfile.mktemp(dir='.', prefix=tempprefix)
212 212 try:
213 213 os.mkfifo(name)
214 214 os.unlink(name)
215 215 return True
216 216 except OSError:
217 217 return False
218 218
219 219 @check("killdaemons", 'killdaemons.py support')
220 220 def has_killdaemons():
221 221 return True
222 222
223 223 @check("cacheable", "cacheable filesystem")
224 224 def has_cacheable_fs():
225 225 from mercurial import util
226 226
227 227 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
228 228 os.close(fd)
229 229 try:
230 230 return util.cachestat(path).cacheable()
231 231 finally:
232 232 os.remove(path)
233 233
234 234 @check("lsprof", "python lsprof module")
235 235 def has_lsprof():
236 236 try:
237 237 import _lsprof
238 238 _lsprof.Profiler # silence unused import warning
239 239 return True
240 240 except ImportError:
241 241 return False
242 242
243 243 def gethgversion():
244 244 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
245 245 if not m:
246 246 return (0, 0)
247 247 return (int(m.group(1)), int(m.group(2)))
248 248
249 249 @checkvers("hg", "Mercurial >= %s",
250 250 list([(1.0 * x) / 10 for x in range(9, 99)]))
251 251 def has_hg_range(v):
252 252 major, minor = v.split('.')[0:2]
253 253 return gethgversion() >= (int(major), int(minor))
254 254
255 255 @check("hg08", "Mercurial >= 0.8")
256 256 def has_hg08():
257 257 if checks["hg09"][0]():
258 258 return True
259 259 return matchoutput('hg help annotate 2>&1', '--date')
260 260
261 261 @check("hg07", "Mercurial >= 0.7")
262 262 def has_hg07():
263 263 if checks["hg08"][0]():
264 264 return True
265 265 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
266 266
267 267 @check("hg06", "Mercurial >= 0.6")
268 268 def has_hg06():
269 269 if checks["hg07"][0]():
270 270 return True
271 271 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
272 272
273 273 @check("gettext", "GNU Gettext (msgfmt)")
274 274 def has_gettext():
275 275 return matchoutput('msgfmt --version', br'GNU gettext-tools')
276 276
277 277 @check("git", "git command line client")
278 278 def has_git():
279 279 return matchoutput('git --version 2>&1', br'^git version')
280 280
281 281 def getgitversion():
282 282 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
283 283 if not m:
284 284 return (0, 0)
285 285 return (int(m.group(1)), int(m.group(2)))
286 286
287 287 # https://github.com/git-lfs/lfs-test-server
288 288 @check("lfs-test-server", "git-lfs test server")
289 289 def has_lfsserver():
290 290 exe = 'lfs-test-server'
291 291 if has_windows():
292 292 exe = 'lfs-test-server.exe'
293 293 return any(
294 294 os.access(os.path.join(path, exe), os.X_OK)
295 295 for path in os.environ["PATH"].split(os.pathsep)
296 296 )
297 297
298 298 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
299 299 def has_git_range(v):
300 300 major, minor = v.split('.')[0:2]
301 301 return getgitversion() >= (int(major), int(minor))
302 302
303 303 @check("docutils", "Docutils text processing library")
304 304 def has_docutils():
305 305 try:
306 306 import docutils.core
307 307 docutils.core.publish_cmdline # silence unused import
308 308 return True
309 309 except ImportError:
310 310 return False
311 311
312 312 def getsvnversion():
313 313 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
314 314 if not m:
315 315 return (0, 0)
316 316 return (int(m.group(1)), int(m.group(2)))
317 317
318 318 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
319 319 def has_svn_range(v):
320 320 major, minor = v.split('.')[0:2]
321 321 return getsvnversion() >= (int(major), int(minor))
322 322
323 323 @check("svn", "subversion client and admin tools")
324 324 def has_svn():
325 325 return matchoutput('svn --version 2>&1', br'^svn, version') and \
326 326 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')
327 327
328 328 @check("svn-bindings", "subversion python bindings")
329 329 def has_svn_bindings():
330 330 try:
331 331 import svn.core
332 332 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
333 333 if version < (1, 4):
334 334 return False
335 335 return True
336 336 except ImportError:
337 337 return False
338 338
339 339 @check("p4", "Perforce server and client")
340 340 def has_p4():
341 341 return (matchoutput('p4 -V', br'Rev\. P4/') and
342 342 matchoutput('p4d -V', br'Rev\. P4D/'))
343 343
344 344 @check("symlink", "symbolic links")
345 345 def has_symlink():
346 346 if getattr(os, "symlink", None) is None:
347 347 return False
348 348 name = tempfile.mktemp(dir='.', prefix=tempprefix)
349 349 try:
350 350 os.symlink(".", name)
351 351 os.unlink(name)
352 352 return True
353 353 except (OSError, AttributeError):
354 354 return False
355 355
356 356 @check("hardlink", "hardlinks")
357 357 def has_hardlink():
358 358 from mercurial import util
359 359 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
360 360 os.close(fh)
361 361 name = tempfile.mktemp(dir='.', prefix=tempprefix)
362 362 try:
363 363 util.oslink(fn, name)
364 364 os.unlink(name)
365 365 return True
366 366 except OSError:
367 367 return False
368 368 finally:
369 369 os.unlink(fn)
370 370
371 371 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
372 372 def has_hardlink_whitelisted():
373 373 from mercurial import util
374 374 try:
375 375 fstype = util.getfstype('.')
376 376 except OSError:
377 377 return False
378 378 return fstype in util._hardlinkfswhitelist
379 379
380 380 @check("rmcwd", "can remove current working directory")
381 381 def has_rmcwd():
382 382 ocwd = os.getcwd()
383 383 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
384 384 try:
385 385 os.chdir(temp)
386 386 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
387 387 # On Solaris and Windows, the cwd can't be removed by any names.
388 388 os.rmdir(os.getcwd())
389 389 return True
390 390 except OSError:
391 391 return False
392 392 finally:
393 393 os.chdir(ocwd)
394 394 # clean up temp dir on platforms where cwd can't be removed
395 395 try:
396 396 os.rmdir(temp)
397 397 except OSError:
398 398 pass
399 399
400 400 @check("tla", "GNU Arch tla client")
401 401 def has_tla():
402 402 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
403 403
404 404 @check("gpg", "gpg client")
405 405 def has_gpg():
406 406 return matchoutput('gpg --version 2>&1', br'GnuPG')
407 407
408 408 @check("gpg2", "gpg client v2")
409 409 def has_gpg2():
410 410 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
411 411
412 412 @check("gpg21", "gpg client v2.1+")
413 413 def has_gpg21():
414 414 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
415 415
416 416 @check("unix-permissions", "unix-style permissions")
417 417 def has_unix_permissions():
418 418 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
419 419 try:
420 420 fname = os.path.join(d, 'foo')
421 421 for umask in (0o77, 0o07, 0o22):
422 422 os.umask(umask)
423 423 f = open(fname, 'w')
424 424 f.close()
425 425 mode = os.stat(fname).st_mode
426 426 os.unlink(fname)
427 427 if mode & 0o777 != ~umask & 0o666:
428 428 return False
429 429 return True
430 430 finally:
431 431 os.rmdir(d)
432 432
433 433 @check("unix-socket", "AF_UNIX socket family")
434 434 def has_unix_socket():
435 435 return getattr(socket, 'AF_UNIX', None) is not None
436 436
437 437 @check("root", "root permissions")
438 438 def has_root():
439 439 return getattr(os, 'geteuid', None) and os.geteuid() == 0
440 440
441 441 @check("pyflakes", "Pyflakes python linter")
442 442 def has_pyflakes():
443 443 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
444 444 br"<stdin>:1: 're' imported but unused",
445 445 True)
446 446
447 447 @check("pylint", "Pylint python linter")
448 448 def has_pylint():
449 449 return matchoutput("pylint --help",
450 450 br"Usage: pylint",
451 451 True)
452 452
453 453 @check("clang-format", "clang-format C code formatter")
454 454 def has_clang_format():
455 455 return matchoutput("clang-format --help",
456 456 br"^OVERVIEW: A tool to format C/C\+\+[^ ]+ code.")
457 457
458 458 @check("jshint", "JSHint static code analysis tool")
459 459 def has_jshint():
460 460 return matchoutput("jshint --version 2>&1", br"jshint v")
461 461
462 462 @check("pygments", "Pygments source highlighting library")
463 463 def has_pygments():
464 464 try:
465 465 import pygments
466 466 pygments.highlight # silence unused import warning
467 467 return True
468 468 except ImportError:
469 469 return False
470 470
471 471 @check("outer-repo", "outer repo")
472 472 def has_outer_repo():
473 473 # failing for other reasons than 'no repo' imply that there is a repo
474 474 return not matchoutput('hg root 2>&1',
475 475 br'abort: no repository found', True)
476 476
477 477 @check("ssl", "ssl module available")
478 478 def has_ssl():
479 479 try:
480 480 import ssl
481 481 ssl.CERT_NONE
482 482 return True
483 483 except ImportError:
484 484 return False
485 485
486 486 @check("sslcontext", "python >= 2.7.9 ssl")
487 487 def has_sslcontext():
488 488 try:
489 489 import ssl
490 490 ssl.SSLContext
491 491 return True
492 492 except (ImportError, AttributeError):
493 493 return False
494 494
495 495 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
496 496 def has_defaultcacerts():
497 497 from mercurial import sslutil, ui as uimod
498 498 ui = uimod.ui.load()
499 499 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
500 500
501 501 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
502 502 def has_defaultcacertsloaded():
503 503 import ssl
504 504 from mercurial import sslutil, ui as uimod
505 505
506 506 if not has_defaultcacerts():
507 507 return False
508 508 if not has_sslcontext():
509 509 return False
510 510
511 511 ui = uimod.ui.load()
512 512 cafile = sslutil._defaultcacerts(ui)
513 513 ctx = ssl.create_default_context()
514 514 if cafile:
515 515 ctx.load_verify_locations(cafile=cafile)
516 516 else:
517 517 ctx.load_default_certs()
518 518
519 519 return len(ctx.get_ca_certs()) > 0
520 520
521 521 @check("tls1.2", "TLS 1.2 protocol support")
522 522 def has_tls1_2():
523 523 from mercurial import sslutil
524 524 return 'tls1.2' in sslutil.supportedprotocols
525 525
526 526 @check("windows", "Windows")
527 527 def has_windows():
528 528 return os.name == 'nt'
529 529
530 530 @check("system-sh", "system() uses sh")
531 531 def has_system_sh():
532 532 return os.name != 'nt'
533 533
534 534 @check("serve", "platform and python can manage 'hg serve -d'")
535 535 def has_serve():
536 536 return True
537 537
538 538 @check("test-repo", "running tests from repository")
539 539 def has_test_repo():
540 540 t = os.environ["TESTDIR"]
541 541 return os.path.isdir(os.path.join(t, "..", ".hg"))
542 542
543 543 @check("tic", "terminfo compiler and curses module")
544 544 def has_tic():
545 545 try:
546 546 import curses
547 547 curses.COLOR_BLUE
548 548 return matchoutput('test -x "`which tic`"', br'')
549 549 except ImportError:
550 550 return False
551 551
552 552 @check("msys", "Windows with MSYS")
553 553 def has_msys():
554 554 return os.getenv('MSYSTEM')
555 555
556 556 @check("aix", "AIX")
557 557 def has_aix():
558 558 return sys.platform.startswith("aix")
559 559
560 560 @check("osx", "OS X")
561 561 def has_osx():
562 562 return sys.platform == 'darwin'
563 563
564 564 @check("osxpackaging", "OS X packaging tools")
565 565 def has_osxpackaging():
566 566 try:
567 567 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
568 568 and matchoutput(
569 569 'productbuild', br'Usage: productbuild ',
570 570 ignorestatus=1)
571 571 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
572 572 and matchoutput(
573 573 'xar --help', br'Usage: xar', ignorestatus=1))
574 574 except ImportError:
575 575 return False
576 576
577 577 @check('linuxormacos', 'Linux or MacOS')
578 578 def has_linuxormacos():
579 579 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
580 580 return sys.platform.startswith(('linux', 'darwin'))
581 581
582 582 @check("docker", "docker support")
583 583 def has_docker():
584 584 pat = br'A self-sufficient runtime for'
585 585 if matchoutput('docker --help', pat):
586 586 if 'linux' not in sys.platform:
587 587 # TODO: in theory we should be able to test docker-based
588 588 # package creation on non-linux using boot2docker, but in
589 589 # practice that requires extra coordination to make sure
590 590 # $TESTTEMP is going to be visible at the same path to the
591 591 # boot2docker VM. If we figure out how to verify that, we
592 592 # can use the following instead of just saying False:
593 593 # return 'DOCKER_HOST' in os.environ
594 594 return False
595 595
596 596 return True
597 597 return False
598 598
599 599 @check("debhelper", "debian packaging tools")
600 600 def has_debhelper():
601 601 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
602 602 # quote), so just accept anything in that spot.
603 603 dpkg = matchoutput('dpkg --version',
604 604 br"Debian .dpkg' package management program")
605 605 dh = matchoutput('dh --help',
606 606 br'dh is a part of debhelper.', ignorestatus=True)
607 607 dh_py2 = matchoutput('dh_python2 --help',
608 608 br'other supported Python versions')
609 609 # debuild comes from the 'devscripts' package, though you might want
610 610 # the 'build-debs' package instead, which has a dependency on devscripts.
611 611 debuild = matchoutput('debuild --help',
612 612 br'to run debian/rules with given parameter')
613 613 return dpkg and dh and dh_py2 and debuild
614 614
615 615 @check("debdeps",
616 616 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)")
617 617 def has_debdeps():
618 618 # just check exit status (ignoring output)
619 619 path = '%s/../contrib/debian/control' % os.environ['TESTDIR']
620 620 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
621 621
622 622 @check("demandimport", "demandimport enabled")
623 623 def has_demandimport():
624 624 # chg disables demandimport intentionally for performance wins.
625 625 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable')
626 626
627 627 @check("py3k", "running with Python 3.x")
628 628 def has_py3k():
629 629 return 3 == sys.version_info[0]
630 630
631 631 @check("py3exe", "a Python 3.x interpreter is available")
632 632 def has_python3exe():
633 633 return 'PYTHON3' in os.environ
634 634
635 635 @check("py3pygments", "Pygments available on Python 3.x")
636 636 def has_py3pygments():
637 637 if has_py3k():
638 638 return has_pygments()
639 639 elif has_python3exe():
640 640 # just check exit status (ignoring output)
641 641 py3 = os.environ['PYTHON3']
642 642 return matchoutput('%s -c "import pygments"' % py3, br'')
643 643 return False
644 644
645 645 @check("pure", "running with pure Python code")
646 646 def has_pure():
647 647 return any([
648 648 os.environ.get("HGMODULEPOLICY") == "py",
649 649 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
650 650 ])
651 651
652 652 @check("slow", "allow slow tests (use --allow-slow-tests)")
653 653 def has_slow():
654 654 return os.environ.get('HGTEST_SLOW') == 'slow'
655 655
656 656 @check("hypothesis", "Hypothesis automated test generation")
657 657 def has_hypothesis():
658 658 try:
659 659 import hypothesis
660 660 hypothesis.given
661 661 return True
662 662 except ImportError:
663 663 return False
664 664
665 665 @check("unziplinks", "unzip(1) understands and extracts symlinks")
666 666 def unzip_understands_symlinks():
667 667 return matchoutput('unzip --help', br'Info-ZIP')
668 668
669 669 @check("zstd", "zstd Python module available")
670 670 def has_zstd():
671 671 try:
672 672 import mercurial.zstd
673 673 mercurial.zstd.__version__
674 674 return True
675 675 except ImportError:
676 676 return False
677 677
678 678 @check("devfull", "/dev/full special file")
679 679 def has_dev_full():
680 680 return os.path.exists('/dev/full')
681 681
682 682 @check("virtualenv", "Python virtualenv support")
683 683 def has_virtualenv():
684 684 try:
685 685 import virtualenv
686 686 virtualenv.ACTIVATE_SH
687 687 return True
688 688 except ImportError:
689 689 return False
690 690
691 691 @check("fsmonitor", "running tests with fsmonitor")
692 692 def has_fsmonitor():
693 693 return 'HGFSMONITOR_TESTS' in os.environ
694 694
695 695 @check("fuzzywuzzy", "Fuzzy string matching library")
696 696 def has_fuzzywuzzy():
697 697 try:
698 698 import fuzzywuzzy
699 699 fuzzywuzzy.__version__
700 700 return True
701 701 except ImportError:
702 702 return False
703 703
704 704 @check("clang-libfuzzer", "clang new enough to include libfuzzer")
705 705 def has_clang_libfuzzer():
706 706 mat = matchoutput('clang --version', b'clang version (\d)')
707 707 if mat:
708 708 # libfuzzer is new in clang 6
709 709 return int(mat.group(1)) > 5
710 710 return False
711
712 @check("xdiff", "xdiff algorithm")
713 def has_xdiff():
714 try:
715 from mercurial import policy
716 bdiff = policy.importmod('bdiff')
717 return bdiff.xdiffblocks('', '') == [(0, 0, 0, 0)]
718 except (ImportError, AttributeError) as ex:
719 return False
General Comments 0
You need to be logged in to leave comments. Login now