##// END OF EJS Templates
tests: conditionalize test-hightlight.t on pygments version...
Gregory Szorc -
r44578:5b38c2ab default
parent child Browse files
Show More
@@ -1,1025 +1,1041 b''
1 from __future__ import absolute_import, print_function
1 from __future__ import absolute_import, print_function
2
2
3 import distutils.version
3 import distutils.version
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 try:
19 try:
20 import msvcrt
20 import msvcrt
21
21
22 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
22 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
23 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
23 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
24 except ImportError:
24 except ImportError:
25 pass
25 pass
26
26
27 stdout = getattr(sys.stdout, 'buffer', sys.stdout)
27 stdout = getattr(sys.stdout, 'buffer', sys.stdout)
28 stderr = getattr(sys.stderr, 'buffer', sys.stderr)
28 stderr = getattr(sys.stderr, 'buffer', sys.stderr)
29
29
30 if sys.version_info[0] >= 3:
30 if sys.version_info[0] >= 3:
31
31
32 def _bytespath(p):
32 def _bytespath(p):
33 if p is None:
33 if p is None:
34 return p
34 return p
35 return p.encode('utf-8')
35 return p.encode('utf-8')
36
36
37 def _strpath(p):
37 def _strpath(p):
38 if p is None:
38 if p is None:
39 return p
39 return p
40 return p.decode('utf-8')
40 return p.decode('utf-8')
41
41
42
42
43 else:
43 else:
44
44
45 def _bytespath(p):
45 def _bytespath(p):
46 return p
46 return p
47
47
48 _strpath = _bytespath
48 _strpath = _bytespath
49
49
50
50
51 def check(name, desc):
51 def check(name, desc):
52 """Registers a check function for a feature."""
52 """Registers a check function for a feature."""
53
53
54 def decorator(func):
54 def decorator(func):
55 checks[name] = (func, desc)
55 checks[name] = (func, desc)
56 return func
56 return func
57
57
58 return decorator
58 return decorator
59
59
60
60
61 def checkvers(name, desc, vers):
61 def checkvers(name, desc, vers):
62 """Registers a check function for each of a series of versions.
62 """Registers a check function for each of a series of versions.
63
63
64 vers can be a list or an iterator.
64 vers can be a list or an iterator.
65
65
66 Produces a series of feature checks that have the form <name><vers> without
66 Produces a series of feature checks that have the form <name><vers> without
67 any punctuation (even if there's punctuation in 'vers'; i.e. this produces
67 any punctuation (even if there's punctuation in 'vers'; i.e. this produces
68 'py38', not 'py3.8' or 'py-38')."""
68 'py38', not 'py3.8' or 'py-38')."""
69
69
70 def decorator(func):
70 def decorator(func):
71 def funcv(v):
71 def funcv(v):
72 def f():
72 def f():
73 return func(v)
73 return func(v)
74
74
75 return f
75 return f
76
76
77 for v in vers:
77 for v in vers:
78 v = str(v)
78 v = str(v)
79 f = funcv(v)
79 f = funcv(v)
80 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
80 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
81 return func
81 return func
82
82
83 return decorator
83 return decorator
84
84
85
85
86 def checkfeatures(features):
86 def checkfeatures(features):
87 result = {
87 result = {
88 'error': [],
88 'error': [],
89 'missing': [],
89 'missing': [],
90 'skipped': [],
90 'skipped': [],
91 }
91 }
92
92
93 for feature in features:
93 for feature in features:
94 negate = feature.startswith('no-')
94 negate = feature.startswith('no-')
95 if negate:
95 if negate:
96 feature = feature[3:]
96 feature = feature[3:]
97
97
98 if feature not in checks:
98 if feature not in checks:
99 result['missing'].append(feature)
99 result['missing'].append(feature)
100 continue
100 continue
101
101
102 check, desc = checks[feature]
102 check, desc = checks[feature]
103 try:
103 try:
104 available = check()
104 available = check()
105 except Exception:
105 except Exception:
106 result['error'].append('hghave check failed: %s' % feature)
106 result['error'].append('hghave check failed: %s' % feature)
107 continue
107 continue
108
108
109 if not negate and not available:
109 if not negate and not available:
110 result['skipped'].append('missing feature: %s' % desc)
110 result['skipped'].append('missing feature: %s' % desc)
111 elif negate and available:
111 elif negate and available:
112 result['skipped'].append('system supports %s' % desc)
112 result['skipped'].append('system supports %s' % desc)
113
113
114 return result
114 return result
115
115
116
116
117 def require(features):
117 def require(features):
118 """Require that features are available, exiting if not."""
118 """Require that features are available, exiting if not."""
119 result = checkfeatures(features)
119 result = checkfeatures(features)
120
120
121 for missing in result['missing']:
121 for missing in result['missing']:
122 stderr.write(
122 stderr.write(
123 ('skipped: unknown feature: %s\n' % missing).encode('utf-8')
123 ('skipped: unknown feature: %s\n' % missing).encode('utf-8')
124 )
124 )
125 for msg in result['skipped']:
125 for msg in result['skipped']:
126 stderr.write(('skipped: %s\n' % msg).encode('utf-8'))
126 stderr.write(('skipped: %s\n' % msg).encode('utf-8'))
127 for msg in result['error']:
127 for msg in result['error']:
128 stderr.write(('%s\n' % msg).encode('utf-8'))
128 stderr.write(('%s\n' % msg).encode('utf-8'))
129
129
130 if result['missing']:
130 if result['missing']:
131 sys.exit(2)
131 sys.exit(2)
132
132
133 if result['skipped'] or result['error']:
133 if result['skipped'] or result['error']:
134 sys.exit(1)
134 sys.exit(1)
135
135
136
136
137 def matchoutput(cmd, regexp, ignorestatus=False):
137 def matchoutput(cmd, regexp, ignorestatus=False):
138 """Return the match object if cmd executes successfully and its output
138 """Return the match object if cmd executes successfully and its output
139 is matched by the supplied regular expression.
139 is matched by the supplied regular expression.
140 """
140 """
141 r = re.compile(regexp)
141 r = re.compile(regexp)
142 p = subprocess.Popen(
142 p = subprocess.Popen(
143 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
143 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
144 )
144 )
145 s = p.communicate()[0]
145 s = p.communicate()[0]
146 ret = p.returncode
146 ret = p.returncode
147 return (ignorestatus or not ret) and r.search(s)
147 return (ignorestatus or not ret) and r.search(s)
148
148
149
149
150 @check("baz", "GNU Arch baz client")
150 @check("baz", "GNU Arch baz client")
151 def has_baz():
151 def has_baz():
152 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
152 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
153
153
154
154
155 @check("bzr", "Canonical's Bazaar client")
155 @check("bzr", "Canonical's Bazaar client")
156 def has_bzr():
156 def has_bzr():
157 try:
157 try:
158 import bzrlib
158 import bzrlib
159 import bzrlib.bzrdir
159 import bzrlib.bzrdir
160 import bzrlib.errors
160 import bzrlib.errors
161 import bzrlib.revision
161 import bzrlib.revision
162 import bzrlib.revisionspec
162 import bzrlib.revisionspec
163
163
164 bzrlib.revisionspec.RevisionSpec
164 bzrlib.revisionspec.RevisionSpec
165 return bzrlib.__doc__ is not None
165 return bzrlib.__doc__ is not None
166 except (AttributeError, ImportError):
166 except (AttributeError, ImportError):
167 return False
167 return False
168
168
169
169
170 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
170 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
171 def has_bzr_range(v):
171 def has_bzr_range(v):
172 major, minor = v.split('rc')[0].split('.')[0:2]
172 major, minor = v.split('rc')[0].split('.')[0:2]
173 try:
173 try:
174 import bzrlib
174 import bzrlib
175
175
176 return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= (
176 return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= (
177 int(major),
177 int(major),
178 int(minor),
178 int(minor),
179 )
179 )
180 except ImportError:
180 except ImportError:
181 return False
181 return False
182
182
183
183
184 @check("chg", "running with chg")
184 @check("chg", "running with chg")
185 def has_chg():
185 def has_chg():
186 return 'CHGHG' in os.environ
186 return 'CHGHG' in os.environ
187
187
188
188
189 @check("cvs", "cvs client/server")
189 @check("cvs", "cvs client/server")
190 def has_cvs():
190 def has_cvs():
191 re = br'Concurrent Versions System.*?server'
191 re = br'Concurrent Versions System.*?server'
192 return matchoutput('cvs --version 2>&1', re) and not has_msys()
192 return matchoutput('cvs --version 2>&1', re) and not has_msys()
193
193
194
194
195 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
195 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
196 def has_cvs112():
196 def has_cvs112():
197 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
197 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
198 return matchoutput('cvs --version 2>&1', re) and not has_msys()
198 return matchoutput('cvs --version 2>&1', re) and not has_msys()
199
199
200
200
201 @check("cvsnt", "cvsnt client/server")
201 @check("cvsnt", "cvsnt client/server")
202 def has_cvsnt():
202 def has_cvsnt():
203 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
203 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
204 return matchoutput('cvsnt --version 2>&1', re)
204 return matchoutput('cvsnt --version 2>&1', re)
205
205
206
206
207 @check("darcs", "darcs client")
207 @check("darcs", "darcs client")
208 def has_darcs():
208 def has_darcs():
209 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
209 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
210
210
211
211
212 @check("mtn", "monotone client (>= 1.0)")
212 @check("mtn", "monotone client (>= 1.0)")
213 def has_mtn():
213 def has_mtn():
214 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
214 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
215 'mtn --version', br'monotone 0\.', True
215 'mtn --version', br'monotone 0\.', True
216 )
216 )
217
217
218
218
219 @check("eol-in-paths", "end-of-lines in paths")
219 @check("eol-in-paths", "end-of-lines in paths")
220 def has_eol_in_paths():
220 def has_eol_in_paths():
221 try:
221 try:
222 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
222 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
223 os.close(fd)
223 os.close(fd)
224 os.remove(path)
224 os.remove(path)
225 return True
225 return True
226 except (IOError, OSError):
226 except (IOError, OSError):
227 return False
227 return False
228
228
229
229
230 @check("execbit", "executable bit")
230 @check("execbit", "executable bit")
231 def has_executablebit():
231 def has_executablebit():
232 try:
232 try:
233 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
233 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
234 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
234 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
235 try:
235 try:
236 os.close(fh)
236 os.close(fh)
237 m = os.stat(fn).st_mode & 0o777
237 m = os.stat(fn).st_mode & 0o777
238 new_file_has_exec = m & EXECFLAGS
238 new_file_has_exec = m & EXECFLAGS
239 os.chmod(fn, m ^ EXECFLAGS)
239 os.chmod(fn, m ^ EXECFLAGS)
240 exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m
240 exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m
241 finally:
241 finally:
242 os.unlink(fn)
242 os.unlink(fn)
243 except (IOError, OSError):
243 except (IOError, OSError):
244 # we don't care, the user probably won't be able to commit anyway
244 # we don't care, the user probably won't be able to commit anyway
245 return False
245 return False
246 return not (new_file_has_exec or exec_flags_cannot_flip)
246 return not (new_file_has_exec or exec_flags_cannot_flip)
247
247
248
248
249 @check("icasefs", "case insensitive file system")
249 @check("icasefs", "case insensitive file system")
250 def has_icasefs():
250 def has_icasefs():
251 # Stolen from mercurial.util
251 # Stolen from mercurial.util
252 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
252 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
253 os.close(fd)
253 os.close(fd)
254 try:
254 try:
255 s1 = os.stat(path)
255 s1 = os.stat(path)
256 d, b = os.path.split(path)
256 d, b = os.path.split(path)
257 p2 = os.path.join(d, b.upper())
257 p2 = os.path.join(d, b.upper())
258 if path == p2:
258 if path == p2:
259 p2 = os.path.join(d, b.lower())
259 p2 = os.path.join(d, b.lower())
260 try:
260 try:
261 s2 = os.stat(p2)
261 s2 = os.stat(p2)
262 return s2 == s1
262 return s2 == s1
263 except OSError:
263 except OSError:
264 return False
264 return False
265 finally:
265 finally:
266 os.remove(path)
266 os.remove(path)
267
267
268
268
269 @check("fifo", "named pipes")
269 @check("fifo", "named pipes")
270 def has_fifo():
270 def has_fifo():
271 if getattr(os, "mkfifo", None) is None:
271 if getattr(os, "mkfifo", None) is None:
272 return False
272 return False
273 name = tempfile.mktemp(dir='.', prefix=tempprefix)
273 name = tempfile.mktemp(dir='.', prefix=tempprefix)
274 try:
274 try:
275 os.mkfifo(name)
275 os.mkfifo(name)
276 os.unlink(name)
276 os.unlink(name)
277 return True
277 return True
278 except OSError:
278 except OSError:
279 return False
279 return False
280
280
281
281
282 @check("killdaemons", 'killdaemons.py support')
282 @check("killdaemons", 'killdaemons.py support')
283 def has_killdaemons():
283 def has_killdaemons():
284 return True
284 return True
285
285
286
286
287 @check("cacheable", "cacheable filesystem")
287 @check("cacheable", "cacheable filesystem")
288 def has_cacheable_fs():
288 def has_cacheable_fs():
289 from mercurial import util
289 from mercurial import util
290
290
291 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
291 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
292 os.close(fd)
292 os.close(fd)
293 try:
293 try:
294 return util.cachestat(path).cacheable()
294 return util.cachestat(path).cacheable()
295 finally:
295 finally:
296 os.remove(path)
296 os.remove(path)
297
297
298
298
299 @check("lsprof", "python lsprof module")
299 @check("lsprof", "python lsprof module")
300 def has_lsprof():
300 def has_lsprof():
301 try:
301 try:
302 import _lsprof
302 import _lsprof
303
303
304 _lsprof.Profiler # silence unused import warning
304 _lsprof.Profiler # silence unused import warning
305 return True
305 return True
306 except ImportError:
306 except ImportError:
307 return False
307 return False
308
308
309
309
310 def gethgversion():
310 def gethgversion():
311 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
311 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
312 if not m:
312 if not m:
313 return (0, 0)
313 return (0, 0)
314 return (int(m.group(1)), int(m.group(2)))
314 return (int(m.group(1)), int(m.group(2)))
315
315
316
316
317 @checkvers(
317 @checkvers(
318 "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)])
318 "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)])
319 )
319 )
320 def has_hg_range(v):
320 def has_hg_range(v):
321 major, minor = v.split('.')[0:2]
321 major, minor = v.split('.')[0:2]
322 return gethgversion() >= (int(major), int(minor))
322 return gethgversion() >= (int(major), int(minor))
323
323
324
324
325 @check("hg08", "Mercurial >= 0.8")
325 @check("hg08", "Mercurial >= 0.8")
326 def has_hg08():
326 def has_hg08():
327 if checks["hg09"][0]():
327 if checks["hg09"][0]():
328 return True
328 return True
329 return matchoutput('hg help annotate 2>&1', '--date')
329 return matchoutput('hg help annotate 2>&1', '--date')
330
330
331
331
332 @check("hg07", "Mercurial >= 0.7")
332 @check("hg07", "Mercurial >= 0.7")
333 def has_hg07():
333 def has_hg07():
334 if checks["hg08"][0]():
334 if checks["hg08"][0]():
335 return True
335 return True
336 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
336 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
337
337
338
338
339 @check("hg06", "Mercurial >= 0.6")
339 @check("hg06", "Mercurial >= 0.6")
340 def has_hg06():
340 def has_hg06():
341 if checks["hg07"][0]():
341 if checks["hg07"][0]():
342 return True
342 return True
343 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
343 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
344
344
345
345
346 @check("gettext", "GNU Gettext (msgfmt)")
346 @check("gettext", "GNU Gettext (msgfmt)")
347 def has_gettext():
347 def has_gettext():
348 return matchoutput('msgfmt --version', br'GNU gettext-tools')
348 return matchoutput('msgfmt --version', br'GNU gettext-tools')
349
349
350
350
351 @check("git", "git command line client")
351 @check("git", "git command line client")
352 def has_git():
352 def has_git():
353 return matchoutput('git --version 2>&1', br'^git version')
353 return matchoutput('git --version 2>&1', br'^git version')
354
354
355
355
356 def getgitversion():
356 def getgitversion():
357 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
357 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
358 if not m:
358 if not m:
359 return (0, 0)
359 return (0, 0)
360 return (int(m.group(1)), int(m.group(2)))
360 return (int(m.group(1)), int(m.group(2)))
361
361
362
362
363 # https://github.com/git-lfs/lfs-test-server
363 # https://github.com/git-lfs/lfs-test-server
364 @check("lfs-test-server", "git-lfs test server")
364 @check("lfs-test-server", "git-lfs test server")
365 def has_lfsserver():
365 def has_lfsserver():
366 exe = 'lfs-test-server'
366 exe = 'lfs-test-server'
367 if has_windows():
367 if has_windows():
368 exe = 'lfs-test-server.exe'
368 exe = 'lfs-test-server.exe'
369 return any(
369 return any(
370 os.access(os.path.join(path, exe), os.X_OK)
370 os.access(os.path.join(path, exe), os.X_OK)
371 for path in os.environ["PATH"].split(os.pathsep)
371 for path in os.environ["PATH"].split(os.pathsep)
372 )
372 )
373
373
374
374
375 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
375 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
376 def has_git_range(v):
376 def has_git_range(v):
377 major, minor = v.split('.')[0:2]
377 major, minor = v.split('.')[0:2]
378 return getgitversion() >= (int(major), int(minor))
378 return getgitversion() >= (int(major), int(minor))
379
379
380
380
381 @check("docutils", "Docutils text processing library")
381 @check("docutils", "Docutils text processing library")
382 def has_docutils():
382 def has_docutils():
383 try:
383 try:
384 import docutils.core
384 import docutils.core
385
385
386 docutils.core.publish_cmdline # silence unused import
386 docutils.core.publish_cmdline # silence unused import
387 return True
387 return True
388 except ImportError:
388 except ImportError:
389 return False
389 return False
390
390
391
391
392 def getsvnversion():
392 def getsvnversion():
393 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
393 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
394 if not m:
394 if not m:
395 return (0, 0)
395 return (0, 0)
396 return (int(m.group(1)), int(m.group(2)))
396 return (int(m.group(1)), int(m.group(2)))
397
397
398
398
399 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
399 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
400 def has_svn_range(v):
400 def has_svn_range(v):
401 major, minor = v.split('.')[0:2]
401 major, minor = v.split('.')[0:2]
402 return getsvnversion() >= (int(major), int(minor))
402 return getsvnversion() >= (int(major), int(minor))
403
403
404
404
405 @check("svn", "subversion client and admin tools")
405 @check("svn", "subversion client and admin tools")
406 def has_svn():
406 def has_svn():
407 return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput(
407 return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput(
408 'svnadmin --version 2>&1', br'^svnadmin, version'
408 'svnadmin --version 2>&1', br'^svnadmin, version'
409 )
409 )
410
410
411
411
412 @check("svn-bindings", "subversion python bindings")
412 @check("svn-bindings", "subversion python bindings")
413 def has_svn_bindings():
413 def has_svn_bindings():
414 try:
414 try:
415 import svn.core
415 import svn.core
416
416
417 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
417 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
418 if version < (1, 4):
418 if version < (1, 4):
419 return False
419 return False
420 return True
420 return True
421 except ImportError:
421 except ImportError:
422 return False
422 return False
423
423
424
424
425 @check("p4", "Perforce server and client")
425 @check("p4", "Perforce server and client")
426 def has_p4():
426 def has_p4():
427 return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput(
427 return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput(
428 'p4d -V', br'Rev\. P4D/'
428 'p4d -V', br'Rev\. P4D/'
429 )
429 )
430
430
431
431
432 @check("symlink", "symbolic links")
432 @check("symlink", "symbolic links")
433 def has_symlink():
433 def has_symlink():
434 # mercurial.windows.checklink() is a hard 'no' at the moment
434 # mercurial.windows.checklink() is a hard 'no' at the moment
435 if os.name == 'nt' or getattr(os, "symlink", None) is None:
435 if os.name == 'nt' or getattr(os, "symlink", None) is None:
436 return False
436 return False
437 name = tempfile.mktemp(dir='.', prefix=tempprefix)
437 name = tempfile.mktemp(dir='.', prefix=tempprefix)
438 try:
438 try:
439 os.symlink(".", name)
439 os.symlink(".", name)
440 os.unlink(name)
440 os.unlink(name)
441 return True
441 return True
442 except (OSError, AttributeError):
442 except (OSError, AttributeError):
443 return False
443 return False
444
444
445
445
446 @check("hardlink", "hardlinks")
446 @check("hardlink", "hardlinks")
447 def has_hardlink():
447 def has_hardlink():
448 from mercurial import util
448 from mercurial import util
449
449
450 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
450 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
451 os.close(fh)
451 os.close(fh)
452 name = tempfile.mktemp(dir='.', prefix=tempprefix)
452 name = tempfile.mktemp(dir='.', prefix=tempprefix)
453 try:
453 try:
454 util.oslink(_bytespath(fn), _bytespath(name))
454 util.oslink(_bytespath(fn), _bytespath(name))
455 os.unlink(name)
455 os.unlink(name)
456 return True
456 return True
457 except OSError:
457 except OSError:
458 return False
458 return False
459 finally:
459 finally:
460 os.unlink(fn)
460 os.unlink(fn)
461
461
462
462
463 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
463 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
464 def has_hardlink_whitelisted():
464 def has_hardlink_whitelisted():
465 from mercurial import util
465 from mercurial import util
466
466
467 try:
467 try:
468 fstype = util.getfstype(b'.')
468 fstype = util.getfstype(b'.')
469 except OSError:
469 except OSError:
470 return False
470 return False
471 return fstype in util._hardlinkfswhitelist
471 return fstype in util._hardlinkfswhitelist
472
472
473
473
474 @check("rmcwd", "can remove current working directory")
474 @check("rmcwd", "can remove current working directory")
475 def has_rmcwd():
475 def has_rmcwd():
476 ocwd = os.getcwd()
476 ocwd = os.getcwd()
477 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
477 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
478 try:
478 try:
479 os.chdir(temp)
479 os.chdir(temp)
480 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
480 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
481 # On Solaris and Windows, the cwd can't be removed by any names.
481 # On Solaris and Windows, the cwd can't be removed by any names.
482 os.rmdir(os.getcwd())
482 os.rmdir(os.getcwd())
483 return True
483 return True
484 except OSError:
484 except OSError:
485 return False
485 return False
486 finally:
486 finally:
487 os.chdir(ocwd)
487 os.chdir(ocwd)
488 # clean up temp dir on platforms where cwd can't be removed
488 # clean up temp dir on platforms where cwd can't be removed
489 try:
489 try:
490 os.rmdir(temp)
490 os.rmdir(temp)
491 except OSError:
491 except OSError:
492 pass
492 pass
493
493
494
494
495 @check("tla", "GNU Arch tla client")
495 @check("tla", "GNU Arch tla client")
496 def has_tla():
496 def has_tla():
497 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
497 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
498
498
499
499
500 @check("gpg", "gpg client")
500 @check("gpg", "gpg client")
501 def has_gpg():
501 def has_gpg():
502 return matchoutput('gpg --version 2>&1', br'GnuPG')
502 return matchoutput('gpg --version 2>&1', br'GnuPG')
503
503
504
504
505 @check("gpg2", "gpg client v2")
505 @check("gpg2", "gpg client v2")
506 def has_gpg2():
506 def has_gpg2():
507 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
507 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
508
508
509
509
510 @check("gpg21", "gpg client v2.1+")
510 @check("gpg21", "gpg client v2.1+")
511 def has_gpg21():
511 def has_gpg21():
512 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
512 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
513
513
514
514
515 @check("unix-permissions", "unix-style permissions")
515 @check("unix-permissions", "unix-style permissions")
516 def has_unix_permissions():
516 def has_unix_permissions():
517 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
517 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
518 try:
518 try:
519 fname = os.path.join(d, 'foo')
519 fname = os.path.join(d, 'foo')
520 for umask in (0o77, 0o07, 0o22):
520 for umask in (0o77, 0o07, 0o22):
521 os.umask(umask)
521 os.umask(umask)
522 f = open(fname, 'w')
522 f = open(fname, 'w')
523 f.close()
523 f.close()
524 mode = os.stat(fname).st_mode
524 mode = os.stat(fname).st_mode
525 os.unlink(fname)
525 os.unlink(fname)
526 if mode & 0o777 != ~umask & 0o666:
526 if mode & 0o777 != ~umask & 0o666:
527 return False
527 return False
528 return True
528 return True
529 finally:
529 finally:
530 os.rmdir(d)
530 os.rmdir(d)
531
531
532
532
533 @check("unix-socket", "AF_UNIX socket family")
533 @check("unix-socket", "AF_UNIX socket family")
534 def has_unix_socket():
534 def has_unix_socket():
535 return getattr(socket, 'AF_UNIX', None) is not None
535 return getattr(socket, 'AF_UNIX', None) is not None
536
536
537
537
538 @check("root", "root permissions")
538 @check("root", "root permissions")
539 def has_root():
539 def has_root():
540 return getattr(os, 'geteuid', None) and os.geteuid() == 0
540 return getattr(os, 'geteuid', None) and os.geteuid() == 0
541
541
542
542
543 @check("pyflakes", "Pyflakes python linter")
543 @check("pyflakes", "Pyflakes python linter")
544 def has_pyflakes():
544 def has_pyflakes():
545 return matchoutput(
545 return matchoutput(
546 "sh -c \"echo 'import re' 2>&1 | pyflakes\"",
546 "sh -c \"echo 'import re' 2>&1 | pyflakes\"",
547 br"<stdin>:1: 're' imported but unused",
547 br"<stdin>:1: 're' imported but unused",
548 True,
548 True,
549 )
549 )
550
550
551
551
552 @check("pylint", "Pylint python linter")
552 @check("pylint", "Pylint python linter")
553 def has_pylint():
553 def has_pylint():
554 return matchoutput("pylint --help", br"Usage: pylint", True)
554 return matchoutput("pylint --help", br"Usage: pylint", True)
555
555
556
556
557 @check("clang-format", "clang-format C code formatter")
557 @check("clang-format", "clang-format C code formatter")
558 def has_clang_format():
558 def has_clang_format():
559 m = matchoutput('clang-format --version', br'clang-format version (\d)')
559 m = matchoutput('clang-format --version', br'clang-format version (\d)')
560 # style changed somewhere between 4.x and 6.x
560 # style changed somewhere between 4.x and 6.x
561 return m and int(m.group(1)) >= 6
561 return m and int(m.group(1)) >= 6
562
562
563
563
564 @check("jshint", "JSHint static code analysis tool")
564 @check("jshint", "JSHint static code analysis tool")
565 def has_jshint():
565 def has_jshint():
566 return matchoutput("jshint --version 2>&1", br"jshint v")
566 return matchoutput("jshint --version 2>&1", br"jshint v")
567
567
568
568
569 @check("pygments", "Pygments source highlighting library")
569 @check("pygments", "Pygments source highlighting library")
570 def has_pygments():
570 def has_pygments():
571 try:
571 try:
572 import pygments
572 import pygments
573
573
574 pygments.highlight # silence unused import warning
574 pygments.highlight # silence unused import warning
575 return True
575 return True
576 except ImportError:
576 except ImportError:
577 return False
577 return False
578
578
579
579
580 @check("pygments25", "Pygments version >= 2.5")
581 def pygments25():
582 try:
583 import pygments
584
585 v = pygments.__version__
586 except ImportError:
587 return False
588
589 parts = v.split(".")
590 major = int(parts[0])
591 minor = int(parts[1])
592
593 return (major, minor) >= (2, 5)
594
595
580 @check("outer-repo", "outer repo")
596 @check("outer-repo", "outer repo")
581 def has_outer_repo():
597 def has_outer_repo():
582 # failing for other reasons than 'no repo' imply that there is a repo
598 # failing for other reasons than 'no repo' imply that there is a repo
583 return not matchoutput('hg root 2>&1', br'abort: no repository found', True)
599 return not matchoutput('hg root 2>&1', br'abort: no repository found', True)
584
600
585
601
586 @check("ssl", "ssl module available")
602 @check("ssl", "ssl module available")
587 def has_ssl():
603 def has_ssl():
588 try:
604 try:
589 import ssl
605 import ssl
590
606
591 ssl.CERT_NONE
607 ssl.CERT_NONE
592 return True
608 return True
593 except ImportError:
609 except ImportError:
594 return False
610 return False
595
611
596
612
597 @check("sslcontext", "python >= 2.7.9 ssl")
613 @check("sslcontext", "python >= 2.7.9 ssl")
598 def has_sslcontext():
614 def has_sslcontext():
599 try:
615 try:
600 import ssl
616 import ssl
601
617
602 ssl.SSLContext
618 ssl.SSLContext
603 return True
619 return True
604 except (ImportError, AttributeError):
620 except (ImportError, AttributeError):
605 return False
621 return False
606
622
607
623
608 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
624 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
609 def has_defaultcacerts():
625 def has_defaultcacerts():
610 from mercurial import sslutil, ui as uimod
626 from mercurial import sslutil, ui as uimod
611
627
612 ui = uimod.ui.load()
628 ui = uimod.ui.load()
613 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
629 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
614
630
615
631
616 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
632 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
617 def has_defaultcacertsloaded():
633 def has_defaultcacertsloaded():
618 import ssl
634 import ssl
619 from mercurial import sslutil, ui as uimod
635 from mercurial import sslutil, ui as uimod
620
636
621 if not has_defaultcacerts():
637 if not has_defaultcacerts():
622 return False
638 return False
623 if not has_sslcontext():
639 if not has_sslcontext():
624 return False
640 return False
625
641
626 ui = uimod.ui.load()
642 ui = uimod.ui.load()
627 cafile = sslutil._defaultcacerts(ui)
643 cafile = sslutil._defaultcacerts(ui)
628 ctx = ssl.create_default_context()
644 ctx = ssl.create_default_context()
629 if cafile:
645 if cafile:
630 ctx.load_verify_locations(cafile=cafile)
646 ctx.load_verify_locations(cafile=cafile)
631 else:
647 else:
632 ctx.load_default_certs()
648 ctx.load_default_certs()
633
649
634 return len(ctx.get_ca_certs()) > 0
650 return len(ctx.get_ca_certs()) > 0
635
651
636
652
637 @check("tls1.2", "TLS 1.2 protocol support")
653 @check("tls1.2", "TLS 1.2 protocol support")
638 def has_tls1_2():
654 def has_tls1_2():
639 from mercurial import sslutil
655 from mercurial import sslutil
640
656
641 return b'tls1.2' in sslutil.supportedprotocols
657 return b'tls1.2' in sslutil.supportedprotocols
642
658
643
659
644 @check("windows", "Windows")
660 @check("windows", "Windows")
645 def has_windows():
661 def has_windows():
646 return os.name == 'nt'
662 return os.name == 'nt'
647
663
648
664
649 @check("system-sh", "system() uses sh")
665 @check("system-sh", "system() uses sh")
650 def has_system_sh():
666 def has_system_sh():
651 return os.name != 'nt'
667 return os.name != 'nt'
652
668
653
669
654 @check("serve", "platform and python can manage 'hg serve -d'")
670 @check("serve", "platform and python can manage 'hg serve -d'")
655 def has_serve():
671 def has_serve():
656 return True
672 return True
657
673
658
674
659 @check("test-repo", "running tests from repository")
675 @check("test-repo", "running tests from repository")
660 def has_test_repo():
676 def has_test_repo():
661 t = os.environ["TESTDIR"]
677 t = os.environ["TESTDIR"]
662 return os.path.isdir(os.path.join(t, "..", ".hg"))
678 return os.path.isdir(os.path.join(t, "..", ".hg"))
663
679
664
680
665 @check("tic", "terminfo compiler and curses module")
681 @check("tic", "terminfo compiler and curses module")
666 def has_tic():
682 def has_tic():
667 try:
683 try:
668 import curses
684 import curses
669
685
670 curses.COLOR_BLUE
686 curses.COLOR_BLUE
671 return matchoutput('test -x "`which tic`"', br'')
687 return matchoutput('test -x "`which tic`"', br'')
672 except ImportError:
688 except ImportError:
673 return False
689 return False
674
690
675
691
676 @check("xz", "xz compression utility")
692 @check("xz", "xz compression utility")
677 def has_xz():
693 def has_xz():
678 # When Windows invokes a subprocess in shell mode, it uses `cmd.exe`, which
694 # When Windows invokes a subprocess in shell mode, it uses `cmd.exe`, which
679 # only knows `where`, not `which`. So invoke MSYS shell explicitly.
695 # only knows `where`, not `which`. So invoke MSYS shell explicitly.
680 return matchoutput("sh -c 'test -x \"`which xz`\"'", b'')
696 return matchoutput("sh -c 'test -x \"`which xz`\"'", b'')
681
697
682
698
683 @check("msys", "Windows with MSYS")
699 @check("msys", "Windows with MSYS")
684 def has_msys():
700 def has_msys():
685 return os.getenv('MSYSTEM')
701 return os.getenv('MSYSTEM')
686
702
687
703
688 @check("aix", "AIX")
704 @check("aix", "AIX")
689 def has_aix():
705 def has_aix():
690 return sys.platform.startswith("aix")
706 return sys.platform.startswith("aix")
691
707
692
708
693 @check("osx", "OS X")
709 @check("osx", "OS X")
694 def has_osx():
710 def has_osx():
695 return sys.platform == 'darwin'
711 return sys.platform == 'darwin'
696
712
697
713
698 @check("osxpackaging", "OS X packaging tools")
714 @check("osxpackaging", "OS X packaging tools")
699 def has_osxpackaging():
715 def has_osxpackaging():
700 try:
716 try:
701 return (
717 return (
702 matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
718 matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
703 and matchoutput(
719 and matchoutput(
704 'productbuild', br'Usage: productbuild ', ignorestatus=1
720 'productbuild', br'Usage: productbuild ', ignorestatus=1
705 )
721 )
706 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
722 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
707 and matchoutput('xar --help', br'Usage: xar', ignorestatus=1)
723 and matchoutput('xar --help', br'Usage: xar', ignorestatus=1)
708 )
724 )
709 except ImportError:
725 except ImportError:
710 return False
726 return False
711
727
712
728
713 @check('linuxormacos', 'Linux or MacOS')
729 @check('linuxormacos', 'Linux or MacOS')
714 def has_linuxormacos():
730 def has_linuxormacos():
715 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
731 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
716 return sys.platform.startswith(('linux', 'darwin'))
732 return sys.platform.startswith(('linux', 'darwin'))
717
733
718
734
719 @check("docker", "docker support")
735 @check("docker", "docker support")
720 def has_docker():
736 def has_docker():
721 pat = br'A self-sufficient runtime for'
737 pat = br'A self-sufficient runtime for'
722 if matchoutput('docker --help', pat):
738 if matchoutput('docker --help', pat):
723 if 'linux' not in sys.platform:
739 if 'linux' not in sys.platform:
724 # TODO: in theory we should be able to test docker-based
740 # TODO: in theory we should be able to test docker-based
725 # package creation on non-linux using boot2docker, but in
741 # package creation on non-linux using boot2docker, but in
726 # practice that requires extra coordination to make sure
742 # practice that requires extra coordination to make sure
727 # $TESTTEMP is going to be visible at the same path to the
743 # $TESTTEMP is going to be visible at the same path to the
728 # boot2docker VM. If we figure out how to verify that, we
744 # boot2docker VM. If we figure out how to verify that, we
729 # can use the following instead of just saying False:
745 # can use the following instead of just saying False:
730 # return 'DOCKER_HOST' in os.environ
746 # return 'DOCKER_HOST' in os.environ
731 return False
747 return False
732
748
733 return True
749 return True
734 return False
750 return False
735
751
736
752
737 @check("debhelper", "debian packaging tools")
753 @check("debhelper", "debian packaging tools")
738 def has_debhelper():
754 def has_debhelper():
739 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
755 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
740 # quote), so just accept anything in that spot.
756 # quote), so just accept anything in that spot.
741 dpkg = matchoutput(
757 dpkg = matchoutput(
742 'dpkg --version', br"Debian .dpkg' package management program"
758 'dpkg --version', br"Debian .dpkg' package management program"
743 )
759 )
744 dh = matchoutput(
760 dh = matchoutput(
745 'dh --help', br'dh is a part of debhelper.', ignorestatus=True
761 'dh --help', br'dh is a part of debhelper.', ignorestatus=True
746 )
762 )
747 dh_py2 = matchoutput(
763 dh_py2 = matchoutput(
748 'dh_python2 --help', br'other supported Python versions'
764 'dh_python2 --help', br'other supported Python versions'
749 )
765 )
750 # debuild comes from the 'devscripts' package, though you might want
766 # debuild comes from the 'devscripts' package, though you might want
751 # the 'build-debs' package instead, which has a dependency on devscripts.
767 # the 'build-debs' package instead, which has a dependency on devscripts.
752 debuild = matchoutput(
768 debuild = matchoutput(
753 'debuild --help', br'to run debian/rules with given parameter'
769 'debuild --help', br'to run debian/rules with given parameter'
754 )
770 )
755 return dpkg and dh and dh_py2 and debuild
771 return dpkg and dh and dh_py2 and debuild
756
772
757
773
758 @check(
774 @check(
759 "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)"
775 "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)"
760 )
776 )
761 def has_debdeps():
777 def has_debdeps():
762 # just check exit status (ignoring output)
778 # just check exit status (ignoring output)
763 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR']
779 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR']
764 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
780 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
765
781
766
782
767 @check("demandimport", "demandimport enabled")
783 @check("demandimport", "demandimport enabled")
768 def has_demandimport():
784 def has_demandimport():
769 # chg disables demandimport intentionally for performance wins.
785 # chg disables demandimport intentionally for performance wins.
770 return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable'
786 return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable'
771
787
772
788
773 # Add "py27", "py35", ... as possible feature checks. Note that there's no
789 # Add "py27", "py35", ... as possible feature checks. Note that there's no
774 # punctuation here.
790 # punctuation here.
775 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9))
791 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9))
776 def has_python_range(v):
792 def has_python_range(v):
777 major, minor = v.split('.')[0:2]
793 major, minor = v.split('.')[0:2]
778 py_major, py_minor = sys.version_info.major, sys.version_info.minor
794 py_major, py_minor = sys.version_info.major, sys.version_info.minor
779
795
780 return (py_major, py_minor) >= (int(major), int(minor))
796 return (py_major, py_minor) >= (int(major), int(minor))
781
797
782
798
783 @check("py3", "running with Python 3.x")
799 @check("py3", "running with Python 3.x")
784 def has_py3():
800 def has_py3():
785 return 3 == sys.version_info[0]
801 return 3 == sys.version_info[0]
786
802
787
803
788 @check("py3exe", "a Python 3.x interpreter is available")
804 @check("py3exe", "a Python 3.x interpreter is available")
789 def has_python3exe():
805 def has_python3exe():
790 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)')
806 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)')
791
807
792
808
793 @check("pure", "running with pure Python code")
809 @check("pure", "running with pure Python code")
794 def has_pure():
810 def has_pure():
795 return any(
811 return any(
796 [
812 [
797 os.environ.get("HGMODULEPOLICY") == "py",
813 os.environ.get("HGMODULEPOLICY") == "py",
798 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
814 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
799 ]
815 ]
800 )
816 )
801
817
802
818
803 @check("slow", "allow slow tests (use --allow-slow-tests)")
819 @check("slow", "allow slow tests (use --allow-slow-tests)")
804 def has_slow():
820 def has_slow():
805 return os.environ.get('HGTEST_SLOW') == 'slow'
821 return os.environ.get('HGTEST_SLOW') == 'slow'
806
822
807
823
808 @check("hypothesis", "Hypothesis automated test generation")
824 @check("hypothesis", "Hypothesis automated test generation")
809 def has_hypothesis():
825 def has_hypothesis():
810 try:
826 try:
811 import hypothesis
827 import hypothesis
812
828
813 hypothesis.given
829 hypothesis.given
814 return True
830 return True
815 except ImportError:
831 except ImportError:
816 return False
832 return False
817
833
818
834
819 @check("unziplinks", "unzip(1) understands and extracts symlinks")
835 @check("unziplinks", "unzip(1) understands and extracts symlinks")
820 def unzip_understands_symlinks():
836 def unzip_understands_symlinks():
821 return matchoutput('unzip --help', br'Info-ZIP')
837 return matchoutput('unzip --help', br'Info-ZIP')
822
838
823
839
824 @check("zstd", "zstd Python module available")
840 @check("zstd", "zstd Python module available")
825 def has_zstd():
841 def has_zstd():
826 try:
842 try:
827 import mercurial.zstd
843 import mercurial.zstd
828
844
829 mercurial.zstd.__version__
845 mercurial.zstd.__version__
830 return True
846 return True
831 except ImportError:
847 except ImportError:
832 return False
848 return False
833
849
834
850
835 @check("devfull", "/dev/full special file")
851 @check("devfull", "/dev/full special file")
836 def has_dev_full():
852 def has_dev_full():
837 return os.path.exists('/dev/full')
853 return os.path.exists('/dev/full')
838
854
839
855
840 @check("ensurepip", "ensurepip module")
856 @check("ensurepip", "ensurepip module")
841 def has_ensurepip():
857 def has_ensurepip():
842 try:
858 try:
843 import ensurepip
859 import ensurepip
844
860
845 ensurepip.bootstrap
861 ensurepip.bootstrap
846 return True
862 return True
847 except ImportError:
863 except ImportError:
848 return False
864 return False
849
865
850
866
851 @check("virtualenv", "Python virtualenv support")
867 @check("virtualenv", "Python virtualenv support")
852 def has_virtualenv():
868 def has_virtualenv():
853 try:
869 try:
854 import virtualenv
870 import virtualenv
855
871
856 virtualenv.ACTIVATE_SH
872 virtualenv.ACTIVATE_SH
857 return True
873 return True
858 except ImportError:
874 except ImportError:
859 return False
875 return False
860
876
861
877
862 @check("fsmonitor", "running tests with fsmonitor")
878 @check("fsmonitor", "running tests with fsmonitor")
863 def has_fsmonitor():
879 def has_fsmonitor():
864 return 'HGFSMONITOR_TESTS' in os.environ
880 return 'HGFSMONITOR_TESTS' in os.environ
865
881
866
882
867 @check("fuzzywuzzy", "Fuzzy string matching library")
883 @check("fuzzywuzzy", "Fuzzy string matching library")
868 def has_fuzzywuzzy():
884 def has_fuzzywuzzy():
869 try:
885 try:
870 import fuzzywuzzy
886 import fuzzywuzzy
871
887
872 fuzzywuzzy.__version__
888 fuzzywuzzy.__version__
873 return True
889 return True
874 except ImportError:
890 except ImportError:
875 return False
891 return False
876
892
877
893
878 @check("clang-libfuzzer", "clang new enough to include libfuzzer")
894 @check("clang-libfuzzer", "clang new enough to include libfuzzer")
879 def has_clang_libfuzzer():
895 def has_clang_libfuzzer():
880 mat = matchoutput('clang --version', br'clang version (\d)')
896 mat = matchoutput('clang --version', br'clang version (\d)')
881 if mat:
897 if mat:
882 # libfuzzer is new in clang 6
898 # libfuzzer is new in clang 6
883 return int(mat.group(1)) > 5
899 return int(mat.group(1)) > 5
884 return False
900 return False
885
901
886
902
887 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)")
903 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)")
888 def has_clang60():
904 def has_clang60():
889 return matchoutput('clang-6.0 --version', br'clang version 6\.')
905 return matchoutput('clang-6.0 --version', br'clang version 6\.')
890
906
891
907
892 @check("xdiff", "xdiff algorithm")
908 @check("xdiff", "xdiff algorithm")
893 def has_xdiff():
909 def has_xdiff():
894 try:
910 try:
895 from mercurial import policy
911 from mercurial import policy
896
912
897 bdiff = policy.importmod('bdiff')
913 bdiff = policy.importmod('bdiff')
898 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)]
914 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)]
899 except (ImportError, AttributeError):
915 except (ImportError, AttributeError):
900 return False
916 return False
901
917
902
918
903 @check('extraextensions', 'whether tests are running with extra extensions')
919 @check('extraextensions', 'whether tests are running with extra extensions')
904 def has_extraextensions():
920 def has_extraextensions():
905 return 'HGTESTEXTRAEXTENSIONS' in os.environ
921 return 'HGTESTEXTRAEXTENSIONS' in os.environ
906
922
907
923
908 def getrepofeatures():
924 def getrepofeatures():
909 """Obtain set of repository features in use.
925 """Obtain set of repository features in use.
910
926
911 HGREPOFEATURES can be used to define or remove features. It contains
927 HGREPOFEATURES can be used to define or remove features. It contains
912 a space-delimited list of feature strings. Strings beginning with ``-``
928 a space-delimited list of feature strings. Strings beginning with ``-``
913 mean to remove.
929 mean to remove.
914 """
930 """
915 # Default list provided by core.
931 # Default list provided by core.
916 features = {
932 features = {
917 'bundlerepo',
933 'bundlerepo',
918 'revlogstore',
934 'revlogstore',
919 'fncache',
935 'fncache',
920 }
936 }
921
937
922 # Features that imply other features.
938 # Features that imply other features.
923 implies = {
939 implies = {
924 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'],
940 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'],
925 }
941 }
926
942
927 for override in os.environ.get('HGREPOFEATURES', '').split(' '):
943 for override in os.environ.get('HGREPOFEATURES', '').split(' '):
928 if not override:
944 if not override:
929 continue
945 continue
930
946
931 if override.startswith('-'):
947 if override.startswith('-'):
932 if override[1:] in features:
948 if override[1:] in features:
933 features.remove(override[1:])
949 features.remove(override[1:])
934 else:
950 else:
935 features.add(override)
951 features.add(override)
936
952
937 for imply in implies.get(override, []):
953 for imply in implies.get(override, []):
938 if imply.startswith('-'):
954 if imply.startswith('-'):
939 if imply[1:] in features:
955 if imply[1:] in features:
940 features.remove(imply[1:])
956 features.remove(imply[1:])
941 else:
957 else:
942 features.add(imply)
958 features.add(imply)
943
959
944 return features
960 return features
945
961
946
962
947 @check('reporevlogstore', 'repository using the default revlog store')
963 @check('reporevlogstore', 'repository using the default revlog store')
948 def has_reporevlogstore():
964 def has_reporevlogstore():
949 return 'revlogstore' in getrepofeatures()
965 return 'revlogstore' in getrepofeatures()
950
966
951
967
952 @check('reposimplestore', 'repository using simple storage extension')
968 @check('reposimplestore', 'repository using simple storage extension')
953 def has_reposimplestore():
969 def has_reposimplestore():
954 return 'simplestore' in getrepofeatures()
970 return 'simplestore' in getrepofeatures()
955
971
956
972
957 @check('repobundlerepo', 'whether we can open bundle files as repos')
973 @check('repobundlerepo', 'whether we can open bundle files as repos')
958 def has_repobundlerepo():
974 def has_repobundlerepo():
959 return 'bundlerepo' in getrepofeatures()
975 return 'bundlerepo' in getrepofeatures()
960
976
961
977
962 @check('repofncache', 'repository has an fncache')
978 @check('repofncache', 'repository has an fncache')
963 def has_repofncache():
979 def has_repofncache():
964 return 'fncache' in getrepofeatures()
980 return 'fncache' in getrepofeatures()
965
981
966
982
967 @check('sqlite', 'sqlite3 module is available')
983 @check('sqlite', 'sqlite3 module is available')
968 def has_sqlite():
984 def has_sqlite():
969 try:
985 try:
970 import sqlite3
986 import sqlite3
971
987
972 version = sqlite3.sqlite_version_info
988 version = sqlite3.sqlite_version_info
973 except ImportError:
989 except ImportError:
974 return False
990 return False
975
991
976 if version < (3, 8, 3):
992 if version < (3, 8, 3):
977 # WITH clause not supported
993 # WITH clause not supported
978 return False
994 return False
979
995
980 return matchoutput('sqlite3 -version', br'^3\.\d+')
996 return matchoutput('sqlite3 -version', br'^3\.\d+')
981
997
982
998
983 @check('vcr', 'vcr http mocking library')
999 @check('vcr', 'vcr http mocking library')
984 def has_vcr():
1000 def has_vcr():
985 try:
1001 try:
986 import vcr
1002 import vcr
987
1003
988 vcr.VCR
1004 vcr.VCR
989 return True
1005 return True
990 except (ImportError, AttributeError):
1006 except (ImportError, AttributeError):
991 pass
1007 pass
992 return False
1008 return False
993
1009
994
1010
995 @check('emacs', 'GNU Emacs')
1011 @check('emacs', 'GNU Emacs')
996 def has_emacs():
1012 def has_emacs():
997 # Our emacs lisp uses `with-eval-after-load` which is new in emacs
1013 # Our emacs lisp uses `with-eval-after-load` which is new in emacs
998 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last
1014 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last
999 # 24 release)
1015 # 24 release)
1000 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
1016 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
1001
1017
1002
1018
1003 @check('black', 'the black formatter for python')
1019 @check('black', 'the black formatter for python')
1004 def has_black():
1020 def has_black():
1005 blackcmd = 'black --version'
1021 blackcmd = 'black --version'
1006 version_regex = b'black, version ([0-9a-b.]+)'
1022 version_regex = b'black, version ([0-9a-b.]+)'
1007 version = matchoutput(blackcmd, version_regex)
1023 version = matchoutput(blackcmd, version_regex)
1008 sv = distutils.version.StrictVersion
1024 sv = distutils.version.StrictVersion
1009 return version and sv(_strpath(version.group(1))) >= sv('19.10b0')
1025 return version and sv(_strpath(version.group(1))) >= sv('19.10b0')
1010
1026
1011
1027
1012 @check('pytype', 'the pytype type checker')
1028 @check('pytype', 'the pytype type checker')
1013 def has_pytype():
1029 def has_pytype():
1014 pytypecmd = 'pytype --version'
1030 pytypecmd = 'pytype --version'
1015 version = matchoutput(pytypecmd, b'[0-9a-b.]+')
1031 version = matchoutput(pytypecmd, b'[0-9a-b.]+')
1016 sv = distutils.version.StrictVersion
1032 sv = distutils.version.StrictVersion
1017 return version and sv(_strpath(version.group(0))) >= sv('2019.10.17')
1033 return version and sv(_strpath(version.group(0))) >= sv('2019.10.17')
1018
1034
1019
1035
1020 @check("rustfmt", "rustfmt tool")
1036 @check("rustfmt", "rustfmt tool")
1021 def has_rustfmt():
1037 def has_rustfmt():
1022 # We use Nightly's rustfmt due to current unstable config options.
1038 # We use Nightly's rustfmt due to current unstable config options.
1023 return matchoutput(
1039 return matchoutput(
1024 '`rustup which --toolchain nightly rustfmt` --version', b'rustfmt'
1040 '`rustup which --toolchain nightly rustfmt` --version', b'rustfmt'
1025 )
1041 )
@@ -1,1038 +1,1040 b''
1 #require pygments serve
1 #require pygments serve
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [extensions]
4 > [extensions]
5 > highlight =
5 > highlight =
6 > [web]
6 > [web]
7 > pygments_style = friendly
7 > pygments_style = friendly
8 > highlightfiles = **.py and size('<100KB')
8 > highlightfiles = **.py and size('<100KB')
9 > EOF
9 > EOF
10 $ hg init test
10 $ hg init test
11 $ cd test
11 $ cd test
12
12
13 $ filterhtml () {
13 $ filterhtml () {
14 > sed -e "s/class=\"k\"/class=\"kn\"/g" \
14 > sed -e "s/class=\"k\"/class=\"kn\"/g" \
15 > -e "s/class=\"mf\"/class=\"mi\"/g" \
15 > -e "s/class=\"mf\"/class=\"mi\"/g" \
16 > -e "s/class=\"vm\"/class=\"n\"/g" \
16 > -e "s/class=\"vm\"/class=\"n\"/g" \
17 > -e "s/class=\"\([cs]\)[h12]\"/class=\"\1\"/g"
17 > -e "s/class=\"\([cs]\)[h12]\"/class=\"\1\"/g"
18 > }
18 > }
19
19
20 create random Python file to exercise Pygments
20 create random Python file to exercise Pygments
21
21
22 $ cat <<NO_CHECK_EOF > primes.py
22 $ cat <<NO_CHECK_EOF > primes.py
23 > """Fun with generators. Corresponding Haskell implementation:
23 > """Fun with generators. Corresponding Haskell implementation:
24 >
24 >
25 > primes = 2 : sieve [3, 5..]
25 > primes = 2 : sieve [3, 5..]
26 > where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]
26 > where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]
27 > """
27 > """
28 >
28 >
29 > import itertools
29 > import itertools
30 >
30 >
31 > def primes():
31 > def primes():
32 > """Generate all primes."""
32 > """Generate all primes."""
33 > def sieve(ns):
33 > def sieve(ns):
34 > p = ns.next()
34 > p = ns.next()
35 > # It is important to yield *here* in order to stop the
35 > # It is important to yield *here* in order to stop the
36 > # infinite recursion.
36 > # infinite recursion.
37 > yield p
37 > yield p
38 > ns = itertools.ifilter(lambda n: n % p != 0, ns)
38 > ns = itertools.ifilter(lambda n: n % p != 0, ns)
39 > for n in sieve(ns):
39 > for n in sieve(ns):
40 > yield n
40 > yield n
41 >
41 >
42 > odds = itertools.ifilter(lambda i: i % 2 == 1, itertools.count())
42 > odds = itertools.ifilter(lambda i: i % 2 == 1, itertools.count())
43 > dropwhile = itertools.dropwhile
43 > dropwhile = itertools.dropwhile
44 > return itertools.chain([2], sieve(dropwhile(lambda n: n < 3, odds)))
44 > return itertools.chain([2], sieve(dropwhile(lambda n: n < 3, odds)))
45 >
45 >
46 > if __name__ == "__main__":
46 > if __name__ == "__main__":
47 > import sys
47 > import sys
48 > try:
48 > try:
49 > n = int(sys.argv[1])
49 > n = int(sys.argv[1])
50 > except (ValueError, IndexError):
50 > except (ValueError, IndexError):
51 > n = 10
51 > n = 10
52 > p = primes()
52 > p = primes()
53 > print("The first %d primes: %s" % (n, list(itertools.islice(p, n))))
53 > print("The first %d primes: %s" % (n, list(itertools.islice(p, n))))
54 > NO_CHECK_EOF
54 > NO_CHECK_EOF
55 $ echo >> primes.py # to test html markup with an empty line just before EOF
55 $ echo >> primes.py # to test html markup with an empty line just before EOF
56 $ hg ci -Ama
56 $ hg ci -Ama
57 adding primes.py
57 adding primes.py
58
58
59 hg serve
59 hg serve
60
60
61 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
61 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
62 $ cat hg.pid >> $DAEMON_PIDS
62 $ cat hg.pid >> $DAEMON_PIDS
63
63
64 hgweb filerevision, html
64 hgweb filerevision, html
65
65
66 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py') | filterhtml
66 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py') | filterhtml
67 200 Script output follows
67 200 Script output follows
68
68
69 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
69 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
70 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
70 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
71 <head>
71 <head>
72 <link rel="icon" href="/static/hgicon.png" type="image/png" />
72 <link rel="icon" href="/static/hgicon.png" type="image/png" />
73 <meta name="robots" content="index, nofollow" />
73 <meta name="robots" content="index, nofollow" />
74 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
74 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
75 <script type="text/javascript" src="/static/mercurial.js"></script>
75 <script type="text/javascript" src="/static/mercurial.js"></script>
76
76
77 <link rel="stylesheet" href="/highlightcss" type="text/css" />
77 <link rel="stylesheet" href="/highlightcss" type="text/css" />
78 <title>test: 687f2d169546 primes.py</title>
78 <title>test: 687f2d169546 primes.py</title>
79 </head>
79 </head>
80 <body>
80 <body>
81
81
82 <div class="container">
82 <div class="container">
83 <div class="menu">
83 <div class="menu">
84 <div class="logo">
84 <div class="logo">
85 <a href="https://mercurial-scm.org/">
85 <a href="https://mercurial-scm.org/">
86 <img src="/static/hglogo.png" alt="mercurial" /></a>
86 <img src="/static/hglogo.png" alt="mercurial" /></a>
87 </div>
87 </div>
88 <ul>
88 <ul>
89 <li><a href="/shortlog/tip">log</a></li>
89 <li><a href="/shortlog/tip">log</a></li>
90 <li><a href="/graph/tip">graph</a></li>
90 <li><a href="/graph/tip">graph</a></li>
91 <li><a href="/tags">tags</a></li>
91 <li><a href="/tags">tags</a></li>
92 <li><a href="/bookmarks">bookmarks</a></li>
92 <li><a href="/bookmarks">bookmarks</a></li>
93 <li><a href="/branches">branches</a></li>
93 <li><a href="/branches">branches</a></li>
94 </ul>
94 </ul>
95 <ul>
95 <ul>
96 <li><a href="/rev/tip">changeset</a></li>
96 <li><a href="/rev/tip">changeset</a></li>
97 <li><a href="/file/tip/">browse</a></li>
97 <li><a href="/file/tip/">browse</a></li>
98 </ul>
98 </ul>
99 <ul>
99 <ul>
100 <li class="active">file</li>
100 <li class="active">file</li>
101 <li><a href="/file/tip/primes.py">latest</a></li>
101 <li><a href="/file/tip/primes.py">latest</a></li>
102 <li><a href="/diff/tip/primes.py">diff</a></li>
102 <li><a href="/diff/tip/primes.py">diff</a></li>
103 <li><a href="/comparison/tip/primes.py">comparison</a></li>
103 <li><a href="/comparison/tip/primes.py">comparison</a></li>
104 <li><a href="/annotate/tip/primes.py">annotate</a></li>
104 <li><a href="/annotate/tip/primes.py">annotate</a></li>
105 <li><a href="/log/tip/primes.py">file log</a></li>
105 <li><a href="/log/tip/primes.py">file log</a></li>
106 <li><a href="/raw-file/tip/primes.py">raw</a></li>
106 <li><a href="/raw-file/tip/primes.py">raw</a></li>
107 </ul>
107 </ul>
108 <ul>
108 <ul>
109 <li><a href="/help">help</a></li>
109 <li><a href="/help">help</a></li>
110 </ul>
110 </ul>
111 </div>
111 </div>
112
112
113 <div class="main">
113 <div class="main">
114 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
114 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
115 <h3>
115 <h3>
116 view primes.py @ 0:<a href="/rev/687f2d169546">687f2d169546</a>
116 view primes.py @ 0:<a href="/rev/687f2d169546">687f2d169546</a>
117 <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span>
117 <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span>
118 </h3>
118 </h3>
119
119
120
120
121 <form class="search" action="/log">
121 <form class="search" action="/log">
122
122
123 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
123 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
124 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
124 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
125 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
125 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
126 </form>
126 </form>
127
127
128 <div class="description">a</div>
128 <div class="description">a</div>
129
129
130 <table id="changesetEntry">
130 <table id="changesetEntry">
131 <tr>
131 <tr>
132 <th class="author">author</th>
132 <th class="author">author</th>
133 <td class="author">&#116;&#101;&#115;&#116;</td>
133 <td class="author">&#116;&#101;&#115;&#116;</td>
134 </tr>
134 </tr>
135 <tr>
135 <tr>
136 <th class="date">date</th>
136 <th class="date">date</th>
137 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
137 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
138 </tr>
138 </tr>
139 <tr>
139 <tr>
140 <th class="author">parents</th>
140 <th class="author">parents</th>
141 <td class="author"></td>
141 <td class="author"></td>
142 </tr>
142 </tr>
143 <tr>
143 <tr>
144 <th class="author">children</th>
144 <th class="author">children</th>
145 <td class="author"></td>
145 <td class="author"></td>
146 </tr>
146 </tr>
147 </table>
147 </table>
148
148
149 <div class="overflow">
149 <div class="overflow">
150 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
150 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
151 <div class="sourcefirst"> line source</div>
151 <div class="sourcefirst"> line source</div>
152 <pre class="sourcelines stripes4 wrap bottomline"
152 <pre class="sourcelines stripes4 wrap bottomline"
153 data-logurl="/log/tip/primes.py"
153 data-logurl="/log/tip/primes.py"
154 data-selectabletag="SPAN"
154 data-selectabletag="SPAN"
155 data-ishead="1">
155 data-ishead="1">
156
156
157 <span id="l1"><span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l1"></a>
157 <span id="l1"><span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l1"></a>
158 <span id="l2"></span><a href="#l2"></a>
158 <span id="l2"></span><a href="#l2"></a>
159 <span id="l3"><span class="sd">primes = 2 : sieve [3, 5..]</span></span><a href="#l3"></a>
159 <span id="l3"><span class="sd">primes = 2 : sieve [3, 5..]</span></span><a href="#l3"></a>
160 <span id="l4"><span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></span><a href="#l4"></a>
160 <span id="l4"><span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></span><a href="#l4"></a>
161 <span id="l5"><span class="sd">&quot;&quot;&quot;</span></span><a href="#l5"></a>
161 <span id="l5"><span class="sd">&quot;&quot;&quot;</span></span><a href="#l5"></a>
162 <span id="l6"></span><a href="#l6"></a>
162 <span id="l6"></span><a href="#l6"></a>
163 <span id="l7"><span class="kn">import</span> <span class="nn">itertools</span></span><a href="#l7"></a>
163 <span id="l7"><span class="kn">import</span> <span class="nn">itertools</span></span><a href="#l7"></a>
164 <span id="l8"></span><a href="#l8"></a>
164 <span id="l8"></span><a href="#l8"></a>
165 <span id="l9"><span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></span><a href="#l9"></a>
165 <span id="l9"><span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></span><a href="#l9"></a>
166 <span id="l10"> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></span><a href="#l10"></a>
166 <span id="l10"> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></span><a href="#l10"></a>
167 <span id="l11"> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l11"></a>
167 <span id="l11"> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l11"></a>
168 <span id="l12"> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></span><a href="#l12"></a>
168 <span id="l12"> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></span><a href="#l12"></a>
169 <span id="l13"> <span class="c"># It is important to yield *here* in order to stop the</span></span><a href="#l13"></a>
169 <span id="l13"> <span class="c"># It is important to yield *here* in order to stop the</span></span><a href="#l13"></a>
170 <span id="l14"> <span class="c"># infinite recursion.</span></span><a href="#l14"></a>
170 <span id="l14"> <span class="c"># infinite recursion.</span></span><a href="#l14"></a>
171 <span id="l15"> <span class="kn">yield</span> <span class="n">p</span></span><a href="#l15"></a>
171 <span id="l15"> <span class="kn">yield</span> <span class="n">p</span></span><a href="#l15"></a>
172 <span id="l16"> <span class="n">ns</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></span><a href="#l16"></a>
172 <span id="l16"> <span class="n">ns</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></span><a href="#l16"></a>
173 <span id="l17"> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l17"></a>
173 <span id="l17"> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l17"></a>
174 <span id="l18"> <span class="kn">yield</span> <span class="n">n</span></span><a href="#l18"></a>
174 <span id="l18"> <span class="kn">yield</span> <span class="n">n</span></span><a href="#l18"></a>
175 <span id="l19"></span><a href="#l19"></a>
175 <span id="l19"></span><a href="#l19"></a>
176 <span id="l20"> <span class="n">odds</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></span><a href="#l20"></a>
176 <span id="l20"> <span class="n">odds</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></span><a href="#l20"></a>
177 <span id="l21"> <span class="n">dropwhile</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">dropwhile</span></span><a href="#l21"></a>
177 <span id="l21"> <span class="n">dropwhile</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">dropwhile</span></span><a href="#l21"></a>
178 <span id="l22"> <span class="kn">return</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></span><a href="#l22"></a>
178 <span id="l22"> <span class="kn">return</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></span><a href="#l22"></a>
179 <span id="l23"></span><a href="#l23"></a>
179 <span id="l23"></span><a href="#l23"></a>
180 <span id="l24"><span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></span><a href="#l24"></a>
180 <span id="l24"><span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></span><a href="#l24"></a>
181 <span id="l25"> <span class="kn">import</span> <span class="nn">sys</span></span><a href="#l25"></a>
181 <span id="l25"> <span class="kn">import</span> <span class="nn">sys</span></span><a href="#l25"></a>
182 <span id="l26"> <span class="kn">try</span><span class="p">:</span></span><a href="#l26"></a>
182 <span id="l26"> <span class="kn">try</span><span class="p">:</span></span><a href="#l26"></a>
183 <span id="l27"> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></span><a href="#l27"></a>
183 <span id="l27"> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></span><a href="#l27"></a>
184 <span id="l28"> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></span><a href="#l28"></a>
184 <span id="l28"> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></span><a href="#l28"></a>
185 <span id="l29"> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l29"></a>
185 <span id="l29"> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l29"></a>
186 <span id="l30"> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l30"></a>
186 <span id="l30"> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l30"></a>
187 <span id="l31"> <span class="kn">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></span><a href="#l31"></a>
187 <span id="l31"> <span class="nb">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></span><a href="#l31"></a> (pygments25 !)
188 <span id="l31"> <span class="kn">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></span><a href="#l31"></a> (no-pygments25 !)
188 <span id="l32"></span><a href="#l32"></a>
189 <span id="l32"></span><a href="#l32"></a>
189 </pre>
190 </pre>
190 </div>
191 </div>
191
192
192 <script type="text/javascript" src="/static/followlines.js"></script>
193 <script type="text/javascript" src="/static/followlines.js"></script>
193
194
194 </div>
195 </div>
195 </div>
196 </div>
196
197
197
198
198
199
199 </body>
200 </body>
200 </html>
201 </html>
201
202
202
203
203 hgweb fileannotate, html
204 hgweb fileannotate, html
204
205
205 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py') | filterhtml
206 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py') | filterhtml
206 200 Script output follows
207 200 Script output follows
207
208
208 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
209 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
209 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
210 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
210 <head>
211 <head>
211 <link rel="icon" href="/static/hgicon.png" type="image/png" />
212 <link rel="icon" href="/static/hgicon.png" type="image/png" />
212 <meta name="robots" content="index, nofollow" />
213 <meta name="robots" content="index, nofollow" />
213 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
214 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
214 <script type="text/javascript" src="/static/mercurial.js"></script>
215 <script type="text/javascript" src="/static/mercurial.js"></script>
215
216
216 <link rel="stylesheet" href="/highlightcss" type="text/css" />
217 <link rel="stylesheet" href="/highlightcss" type="text/css" />
217 <title>test: primes.py annotate</title>
218 <title>test: primes.py annotate</title>
218 </head>
219 </head>
219 <body>
220 <body>
220
221
221 <div class="container">
222 <div class="container">
222 <div class="menu">
223 <div class="menu">
223 <div class="logo">
224 <div class="logo">
224 <a href="https://mercurial-scm.org/">
225 <a href="https://mercurial-scm.org/">
225 <img src="/static/hglogo.png" alt="mercurial" /></a>
226 <img src="/static/hglogo.png" alt="mercurial" /></a>
226 </div>
227 </div>
227 <ul>
228 <ul>
228 <li><a href="/shortlog/tip">log</a></li>
229 <li><a href="/shortlog/tip">log</a></li>
229 <li><a href="/graph/tip">graph</a></li>
230 <li><a href="/graph/tip">graph</a></li>
230 <li><a href="/tags">tags</a></li>
231 <li><a href="/tags">tags</a></li>
231 <li><a href="/bookmarks">bookmarks</a></li>
232 <li><a href="/bookmarks">bookmarks</a></li>
232 <li><a href="/branches">branches</a></li>
233 <li><a href="/branches">branches</a></li>
233 </ul>
234 </ul>
234
235
235 <ul>
236 <ul>
236 <li><a href="/rev/tip">changeset</a></li>
237 <li><a href="/rev/tip">changeset</a></li>
237 <li><a href="/file/tip/">browse</a></li>
238 <li><a href="/file/tip/">browse</a></li>
238 </ul>
239 </ul>
239 <ul>
240 <ul>
240 <li><a href="/file/tip/primes.py">file</a></li>
241 <li><a href="/file/tip/primes.py">file</a></li>
241 <li><a href="/file/tip/primes.py">latest</a></li>
242 <li><a href="/file/tip/primes.py">latest</a></li>
242 <li><a href="/diff/tip/primes.py">diff</a></li>
243 <li><a href="/diff/tip/primes.py">diff</a></li>
243 <li><a href="/comparison/tip/primes.py">comparison</a></li>
244 <li><a href="/comparison/tip/primes.py">comparison</a></li>
244 <li class="active">annotate</li>
245 <li class="active">annotate</li>
245 <li><a href="/log/tip/primes.py">file log</a></li>
246 <li><a href="/log/tip/primes.py">file log</a></li>
246 <li><a href="/raw-file/tip/primes.py">raw</a></li>
247 <li><a href="/raw-file/tip/primes.py">raw</a></li>
247 </ul>
248 </ul>
248 <ul>
249 <ul>
249 <li><a href="/help">help</a></li>
250 <li><a href="/help">help</a></li>
250 </ul>
251 </ul>
251 </div>
252 </div>
252
253
253 <div class="main">
254 <div class="main">
254 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
255 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
255 <h3>
256 <h3>
256 annotate primes.py @ 0:<a href="/rev/687f2d169546">687f2d169546</a>
257 annotate primes.py @ 0:<a href="/rev/687f2d169546">687f2d169546</a>
257 <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span>
258 <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span>
258 </h3>
259 </h3>
259
260
260
261
261 <form class="search" action="/log">
262 <form class="search" action="/log">
262
263
263 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
264 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
264 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
265 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
265 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
266 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
266 </form>
267 </form>
267
268
268 <div class="description">a</div>
269 <div class="description">a</div>
269
270
270 <table id="changesetEntry">
271 <table id="changesetEntry">
271 <tr>
272 <tr>
272 <th class="author">author</th>
273 <th class="author">author</th>
273 <td class="author">&#116;&#101;&#115;&#116;</td>
274 <td class="author">&#116;&#101;&#115;&#116;</td>
274 </tr>
275 </tr>
275 <tr>
276 <tr>
276 <th class="date">date</th>
277 <th class="date">date</th>
277 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
278 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
278 </tr>
279 </tr>
279 <tr>
280 <tr>
280 <th class="author">parents</th>
281 <th class="author">parents</th>
281 <td class="author"></td>
282 <td class="author"></td>
282 </tr>
283 </tr>
283 <tr>
284 <tr>
284 <th class="author">children</th>
285 <th class="author">children</th>
285 <td class="author"></td>
286 <td class="author"></td>
286 </tr>
287 </tr>
287 </table>
288 </table>
288
289
289
290
290 <form id="diffopts-form"
291 <form id="diffopts-form"
291 data-ignorews="0"
292 data-ignorews="0"
292 data-ignorewsamount="0"
293 data-ignorewsamount="0"
293 data-ignorewseol="0"
294 data-ignorewseol="0"
294 data-ignoreblanklines="0">
295 data-ignoreblanklines="0">
295 <span>Ignore whitespace changes - </span>
296 <span>Ignore whitespace changes - </span>
296 <span>Everywhere:</span>
297 <span>Everywhere:</span>
297 <input id="ignorews-checkbox" type="checkbox" />
298 <input id="ignorews-checkbox" type="checkbox" />
298 <span>Within whitespace:</span>
299 <span>Within whitespace:</span>
299 <input id="ignorewsamount-checkbox" type="checkbox" />
300 <input id="ignorewsamount-checkbox" type="checkbox" />
300 <span>At end of lines:</span>
301 <span>At end of lines:</span>
301 <input id="ignorewseol-checkbox" type="checkbox" />
302 <input id="ignorewseol-checkbox" type="checkbox" />
302 </form>
303 </form>
303
304
304 <script type="text/javascript">
305 <script type="text/javascript">
305 renderDiffOptsForm();
306 renderDiffOptsForm();
306 </script>
307 </script>
307
308
308 <div class="overflow">
309 <div class="overflow">
309 <table class="bigtable">
310 <table class="bigtable">
310 <thead>
311 <thead>
311 <tr>
312 <tr>
312 <th class="annotate">rev</th>
313 <th class="annotate">rev</th>
313 <th class="line">&nbsp;&nbsp;line source</th>
314 <th class="line">&nbsp;&nbsp;line source</th>
314 </tr>
315 </tr>
315 </thead>
316 </thead>
316 <tbody class="stripes2 sourcelines"
317 <tbody class="stripes2 sourcelines"
317 data-logurl="/log/tip/primes.py"
318 data-logurl="/log/tip/primes.py"
318 data-selectabletag="TR"
319 data-selectabletag="TR"
319 data-ishead="1">
320 data-ishead="1">
320
321
321 <tr id="l1" class="thisrev">
322 <tr id="l1" class="thisrev">
322 <td class="annotate parity0">
323 <td class="annotate parity0">
323 <a href="/annotate/687f2d169546/primes.py#l1">
324 <a href="/annotate/687f2d169546/primes.py#l1">
324 0
325 0
325 </a>
326 </a>
326 <div class="annotate-info">
327 <div class="annotate-info">
327 <div>
328 <div>
328 <a href="/annotate/687f2d169546/primes.py#l1">
329 <a href="/annotate/687f2d169546/primes.py#l1">
329 687f2d169546</a>
330 687f2d169546</a>
330 a
331 a
331 </div>
332 </div>
332 <div><em>&#116;&#101;&#115;&#116;</em></div>
333 <div><em>&#116;&#101;&#115;&#116;</em></div>
333 <div>parents: </div>
334 <div>parents: </div>
334 <a href="/diff/687f2d169546/primes.py">diff</a>
335 <a href="/diff/687f2d169546/primes.py">diff</a>
335 <a href="/rev/687f2d169546">changeset</a>
336 <a href="/rev/687f2d169546">changeset</a>
336 </div>
337 </div>
337 </td>
338 </td>
338 <td class="source followlines-btn-parent"><a href="#l1"> 1</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
339 <td class="source followlines-btn-parent"><a href="#l1"> 1</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
339 </tr>
340 </tr>
340 <tr id="l2" class="thisrev">
341 <tr id="l2" class="thisrev">
341 <td class="annotate parity0">
342 <td class="annotate parity0">
342
343
343 <div class="annotate-info">
344 <div class="annotate-info">
344 <div>
345 <div>
345 <a href="/annotate/687f2d169546/primes.py#l2">
346 <a href="/annotate/687f2d169546/primes.py#l2">
346 687f2d169546</a>
347 687f2d169546</a>
347 a
348 a
348 </div>
349 </div>
349 <div><em>&#116;&#101;&#115;&#116;</em></div>
350 <div><em>&#116;&#101;&#115;&#116;</em></div>
350 <div>parents: </div>
351 <div>parents: </div>
351 <a href="/diff/687f2d169546/primes.py">diff</a>
352 <a href="/diff/687f2d169546/primes.py">diff</a>
352 <a href="/rev/687f2d169546">changeset</a>
353 <a href="/rev/687f2d169546">changeset</a>
353 </div>
354 </div>
354 </td>
355 </td>
355 <td class="source followlines-btn-parent"><a href="#l2"> 2</a> </td>
356 <td class="source followlines-btn-parent"><a href="#l2"> 2</a> </td>
356 </tr>
357 </tr>
357 <tr id="l3" class="thisrev">
358 <tr id="l3" class="thisrev">
358 <td class="annotate parity0">
359 <td class="annotate parity0">
359
360
360 <div class="annotate-info">
361 <div class="annotate-info">
361 <div>
362 <div>
362 <a href="/annotate/687f2d169546/primes.py#l3">
363 <a href="/annotate/687f2d169546/primes.py#l3">
363 687f2d169546</a>
364 687f2d169546</a>
364 a
365 a
365 </div>
366 </div>
366 <div><em>&#116;&#101;&#115;&#116;</em></div>
367 <div><em>&#116;&#101;&#115;&#116;</em></div>
367 <div>parents: </div>
368 <div>parents: </div>
368 <a href="/diff/687f2d169546/primes.py">diff</a>
369 <a href="/diff/687f2d169546/primes.py">diff</a>
369 <a href="/rev/687f2d169546">changeset</a>
370 <a href="/rev/687f2d169546">changeset</a>
370 </div>
371 </div>
371 </td>
372 </td>
372 <td class="source followlines-btn-parent"><a href="#l3"> 3</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
373 <td class="source followlines-btn-parent"><a href="#l3"> 3</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
373 </tr>
374 </tr>
374 <tr id="l4" class="thisrev">
375 <tr id="l4" class="thisrev">
375 <td class="annotate parity0">
376 <td class="annotate parity0">
376
377
377 <div class="annotate-info">
378 <div class="annotate-info">
378 <div>
379 <div>
379 <a href="/annotate/687f2d169546/primes.py#l4">
380 <a href="/annotate/687f2d169546/primes.py#l4">
380 687f2d169546</a>
381 687f2d169546</a>
381 a
382 a
382 </div>
383 </div>
383 <div><em>&#116;&#101;&#115;&#116;</em></div>
384 <div><em>&#116;&#101;&#115;&#116;</em></div>
384 <div>parents: </div>
385 <div>parents: </div>
385 <a href="/diff/687f2d169546/primes.py">diff</a>
386 <a href="/diff/687f2d169546/primes.py">diff</a>
386 <a href="/rev/687f2d169546">changeset</a>
387 <a href="/rev/687f2d169546">changeset</a>
387 </div>
388 </div>
388 </td>
389 </td>
389 <td class="source followlines-btn-parent"><a href="#l4"> 4</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
390 <td class="source followlines-btn-parent"><a href="#l4"> 4</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
390 </tr>
391 </tr>
391 <tr id="l5" class="thisrev">
392 <tr id="l5" class="thisrev">
392 <td class="annotate parity0">
393 <td class="annotate parity0">
393
394
394 <div class="annotate-info">
395 <div class="annotate-info">
395 <div>
396 <div>
396 <a href="/annotate/687f2d169546/primes.py#l5">
397 <a href="/annotate/687f2d169546/primes.py#l5">
397 687f2d169546</a>
398 687f2d169546</a>
398 a
399 a
399 </div>
400 </div>
400 <div><em>&#116;&#101;&#115;&#116;</em></div>
401 <div><em>&#116;&#101;&#115;&#116;</em></div>
401 <div>parents: </div>
402 <div>parents: </div>
402 <a href="/diff/687f2d169546/primes.py">diff</a>
403 <a href="/diff/687f2d169546/primes.py">diff</a>
403 <a href="/rev/687f2d169546">changeset</a>
404 <a href="/rev/687f2d169546">changeset</a>
404 </div>
405 </div>
405 </td>
406 </td>
406 <td class="source followlines-btn-parent"><a href="#l5"> 5</a> <span class="sd">&quot;&quot;&quot;</span></td>
407 <td class="source followlines-btn-parent"><a href="#l5"> 5</a> <span class="sd">&quot;&quot;&quot;</span></td>
407 </tr>
408 </tr>
408 <tr id="l6" class="thisrev">
409 <tr id="l6" class="thisrev">
409 <td class="annotate parity0">
410 <td class="annotate parity0">
410
411
411 <div class="annotate-info">
412 <div class="annotate-info">
412 <div>
413 <div>
413 <a href="/annotate/687f2d169546/primes.py#l6">
414 <a href="/annotate/687f2d169546/primes.py#l6">
414 687f2d169546</a>
415 687f2d169546</a>
415 a
416 a
416 </div>
417 </div>
417 <div><em>&#116;&#101;&#115;&#116;</em></div>
418 <div><em>&#116;&#101;&#115;&#116;</em></div>
418 <div>parents: </div>
419 <div>parents: </div>
419 <a href="/diff/687f2d169546/primes.py">diff</a>
420 <a href="/diff/687f2d169546/primes.py">diff</a>
420 <a href="/rev/687f2d169546">changeset</a>
421 <a href="/rev/687f2d169546">changeset</a>
421 </div>
422 </div>
422 </td>
423 </td>
423 <td class="source followlines-btn-parent"><a href="#l6"> 6</a> </td>
424 <td class="source followlines-btn-parent"><a href="#l6"> 6</a> </td>
424 </tr>
425 </tr>
425 <tr id="l7" class="thisrev">
426 <tr id="l7" class="thisrev">
426 <td class="annotate parity0">
427 <td class="annotate parity0">
427
428
428 <div class="annotate-info">
429 <div class="annotate-info">
429 <div>
430 <div>
430 <a href="/annotate/687f2d169546/primes.py#l7">
431 <a href="/annotate/687f2d169546/primes.py#l7">
431 687f2d169546</a>
432 687f2d169546</a>
432 a
433 a
433 </div>
434 </div>
434 <div><em>&#116;&#101;&#115;&#116;</em></div>
435 <div><em>&#116;&#101;&#115;&#116;</em></div>
435 <div>parents: </div>
436 <div>parents: </div>
436 <a href="/diff/687f2d169546/primes.py">diff</a>
437 <a href="/diff/687f2d169546/primes.py">diff</a>
437 <a href="/rev/687f2d169546">changeset</a>
438 <a href="/rev/687f2d169546">changeset</a>
438 </div>
439 </div>
439 </td>
440 </td>
440 <td class="source followlines-btn-parent"><a href="#l7"> 7</a> <span class="kn">import</span> <span class="nn">itertools</span></td>
441 <td class="source followlines-btn-parent"><a href="#l7"> 7</a> <span class="kn">import</span> <span class="nn">itertools</span></td>
441 </tr>
442 </tr>
442 <tr id="l8" class="thisrev">
443 <tr id="l8" class="thisrev">
443 <td class="annotate parity0">
444 <td class="annotate parity0">
444
445
445 <div class="annotate-info">
446 <div class="annotate-info">
446 <div>
447 <div>
447 <a href="/annotate/687f2d169546/primes.py#l8">
448 <a href="/annotate/687f2d169546/primes.py#l8">
448 687f2d169546</a>
449 687f2d169546</a>
449 a
450 a
450 </div>
451 </div>
451 <div><em>&#116;&#101;&#115;&#116;</em></div>
452 <div><em>&#116;&#101;&#115;&#116;</em></div>
452 <div>parents: </div>
453 <div>parents: </div>
453 <a href="/diff/687f2d169546/primes.py">diff</a>
454 <a href="/diff/687f2d169546/primes.py">diff</a>
454 <a href="/rev/687f2d169546">changeset</a>
455 <a href="/rev/687f2d169546">changeset</a>
455 </div>
456 </div>
456 </td>
457 </td>
457 <td class="source followlines-btn-parent"><a href="#l8"> 8</a> </td>
458 <td class="source followlines-btn-parent"><a href="#l8"> 8</a> </td>
458 </tr>
459 </tr>
459 <tr id="l9" class="thisrev">
460 <tr id="l9" class="thisrev">
460 <td class="annotate parity0">
461 <td class="annotate parity0">
461
462
462 <div class="annotate-info">
463 <div class="annotate-info">
463 <div>
464 <div>
464 <a href="/annotate/687f2d169546/primes.py#l9">
465 <a href="/annotate/687f2d169546/primes.py#l9">
465 687f2d169546</a>
466 687f2d169546</a>
466 a
467 a
467 </div>
468 </div>
468 <div><em>&#116;&#101;&#115;&#116;</em></div>
469 <div><em>&#116;&#101;&#115;&#116;</em></div>
469 <div>parents: </div>
470 <div>parents: </div>
470 <a href="/diff/687f2d169546/primes.py">diff</a>
471 <a href="/diff/687f2d169546/primes.py">diff</a>
471 <a href="/rev/687f2d169546">changeset</a>
472 <a href="/rev/687f2d169546">changeset</a>
472 </div>
473 </div>
473 </td>
474 </td>
474 <td class="source followlines-btn-parent"><a href="#l9"> 9</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
475 <td class="source followlines-btn-parent"><a href="#l9"> 9</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
475 </tr>
476 </tr>
476 <tr id="l10" class="thisrev">
477 <tr id="l10" class="thisrev">
477 <td class="annotate parity0">
478 <td class="annotate parity0">
478
479
479 <div class="annotate-info">
480 <div class="annotate-info">
480 <div>
481 <div>
481 <a href="/annotate/687f2d169546/primes.py#l10">
482 <a href="/annotate/687f2d169546/primes.py#l10">
482 687f2d169546</a>
483 687f2d169546</a>
483 a
484 a
484 </div>
485 </div>
485 <div><em>&#116;&#101;&#115;&#116;</em></div>
486 <div><em>&#116;&#101;&#115;&#116;</em></div>
486 <div>parents: </div>
487 <div>parents: </div>
487 <a href="/diff/687f2d169546/primes.py">diff</a>
488 <a href="/diff/687f2d169546/primes.py">diff</a>
488 <a href="/rev/687f2d169546">changeset</a>
489 <a href="/rev/687f2d169546">changeset</a>
489 </div>
490 </div>
490 </td>
491 </td>
491 <td class="source followlines-btn-parent"><a href="#l10"> 10</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
492 <td class="source followlines-btn-parent"><a href="#l10"> 10</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
492 </tr>
493 </tr>
493 <tr id="l11" class="thisrev">
494 <tr id="l11" class="thisrev">
494 <td class="annotate parity0">
495 <td class="annotate parity0">
495
496
496 <div class="annotate-info">
497 <div class="annotate-info">
497 <div>
498 <div>
498 <a href="/annotate/687f2d169546/primes.py#l11">
499 <a href="/annotate/687f2d169546/primes.py#l11">
499 687f2d169546</a>
500 687f2d169546</a>
500 a
501 a
501 </div>
502 </div>
502 <div><em>&#116;&#101;&#115;&#116;</em></div>
503 <div><em>&#116;&#101;&#115;&#116;</em></div>
503 <div>parents: </div>
504 <div>parents: </div>
504 <a href="/diff/687f2d169546/primes.py">diff</a>
505 <a href="/diff/687f2d169546/primes.py">diff</a>
505 <a href="/rev/687f2d169546">changeset</a>
506 <a href="/rev/687f2d169546">changeset</a>
506 </div>
507 </div>
507 </td>
508 </td>
508 <td class="source followlines-btn-parent"><a href="#l11"> 11</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
509 <td class="source followlines-btn-parent"><a href="#l11"> 11</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
509 </tr>
510 </tr>
510 <tr id="l12" class="thisrev">
511 <tr id="l12" class="thisrev">
511 <td class="annotate parity0">
512 <td class="annotate parity0">
512
513
513 <div class="annotate-info">
514 <div class="annotate-info">
514 <div>
515 <div>
515 <a href="/annotate/687f2d169546/primes.py#l12">
516 <a href="/annotate/687f2d169546/primes.py#l12">
516 687f2d169546</a>
517 687f2d169546</a>
517 a
518 a
518 </div>
519 </div>
519 <div><em>&#116;&#101;&#115;&#116;</em></div>
520 <div><em>&#116;&#101;&#115;&#116;</em></div>
520 <div>parents: </div>
521 <div>parents: </div>
521 <a href="/diff/687f2d169546/primes.py">diff</a>
522 <a href="/diff/687f2d169546/primes.py">diff</a>
522 <a href="/rev/687f2d169546">changeset</a>
523 <a href="/rev/687f2d169546">changeset</a>
523 </div>
524 </div>
524 </td>
525 </td>
525 <td class="source followlines-btn-parent"><a href="#l12"> 12</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
526 <td class="source followlines-btn-parent"><a href="#l12"> 12</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
526 </tr>
527 </tr>
527 <tr id="l13" class="thisrev">
528 <tr id="l13" class="thisrev">
528 <td class="annotate parity0">
529 <td class="annotate parity0">
529
530
530 <div class="annotate-info">
531 <div class="annotate-info">
531 <div>
532 <div>
532 <a href="/annotate/687f2d169546/primes.py#l13">
533 <a href="/annotate/687f2d169546/primes.py#l13">
533 687f2d169546</a>
534 687f2d169546</a>
534 a
535 a
535 </div>
536 </div>
536 <div><em>&#116;&#101;&#115;&#116;</em></div>
537 <div><em>&#116;&#101;&#115;&#116;</em></div>
537 <div>parents: </div>
538 <div>parents: </div>
538 <a href="/diff/687f2d169546/primes.py">diff</a>
539 <a href="/diff/687f2d169546/primes.py">diff</a>
539 <a href="/rev/687f2d169546">changeset</a>
540 <a href="/rev/687f2d169546">changeset</a>
540 </div>
541 </div>
541 </td>
542 </td>
542 <td class="source followlines-btn-parent"><a href="#l13"> 13</a> <span class="c"># It is important to yield *here* in order to stop the</span></td>
543 <td class="source followlines-btn-parent"><a href="#l13"> 13</a> <span class="c"># It is important to yield *here* in order to stop the</span></td>
543 </tr>
544 </tr>
544 <tr id="l14" class="thisrev">
545 <tr id="l14" class="thisrev">
545 <td class="annotate parity0">
546 <td class="annotate parity0">
546
547
547 <div class="annotate-info">
548 <div class="annotate-info">
548 <div>
549 <div>
549 <a href="/annotate/687f2d169546/primes.py#l14">
550 <a href="/annotate/687f2d169546/primes.py#l14">
550 687f2d169546</a>
551 687f2d169546</a>
551 a
552 a
552 </div>
553 </div>
553 <div><em>&#116;&#101;&#115;&#116;</em></div>
554 <div><em>&#116;&#101;&#115;&#116;</em></div>
554 <div>parents: </div>
555 <div>parents: </div>
555 <a href="/diff/687f2d169546/primes.py">diff</a>
556 <a href="/diff/687f2d169546/primes.py">diff</a>
556 <a href="/rev/687f2d169546">changeset</a>
557 <a href="/rev/687f2d169546">changeset</a>
557 </div>
558 </div>
558 </td>
559 </td>
559 <td class="source followlines-btn-parent"><a href="#l14"> 14</a> <span class="c"># infinite recursion.</span></td>
560 <td class="source followlines-btn-parent"><a href="#l14"> 14</a> <span class="c"># infinite recursion.</span></td>
560 </tr>
561 </tr>
561 <tr id="l15" class="thisrev">
562 <tr id="l15" class="thisrev">
562 <td class="annotate parity0">
563 <td class="annotate parity0">
563
564
564 <div class="annotate-info">
565 <div class="annotate-info">
565 <div>
566 <div>
566 <a href="/annotate/687f2d169546/primes.py#l15">
567 <a href="/annotate/687f2d169546/primes.py#l15">
567 687f2d169546</a>
568 687f2d169546</a>
568 a
569 a
569 </div>
570 </div>
570 <div><em>&#116;&#101;&#115;&#116;</em></div>
571 <div><em>&#116;&#101;&#115;&#116;</em></div>
571 <div>parents: </div>
572 <div>parents: </div>
572 <a href="/diff/687f2d169546/primes.py">diff</a>
573 <a href="/diff/687f2d169546/primes.py">diff</a>
573 <a href="/rev/687f2d169546">changeset</a>
574 <a href="/rev/687f2d169546">changeset</a>
574 </div>
575 </div>
575 </td>
576 </td>
576 <td class="source followlines-btn-parent"><a href="#l15"> 15</a> <span class="kn">yield</span> <span class="n">p</span></td>
577 <td class="source followlines-btn-parent"><a href="#l15"> 15</a> <span class="kn">yield</span> <span class="n">p</span></td>
577 </tr>
578 </tr>
578 <tr id="l16" class="thisrev">
579 <tr id="l16" class="thisrev">
579 <td class="annotate parity0">
580 <td class="annotate parity0">
580
581
581 <div class="annotate-info">
582 <div class="annotate-info">
582 <div>
583 <div>
583 <a href="/annotate/687f2d169546/primes.py#l16">
584 <a href="/annotate/687f2d169546/primes.py#l16">
584 687f2d169546</a>
585 687f2d169546</a>
585 a
586 a
586 </div>
587 </div>
587 <div><em>&#116;&#101;&#115;&#116;</em></div>
588 <div><em>&#116;&#101;&#115;&#116;</em></div>
588 <div>parents: </div>
589 <div>parents: </div>
589 <a href="/diff/687f2d169546/primes.py">diff</a>
590 <a href="/diff/687f2d169546/primes.py">diff</a>
590 <a href="/rev/687f2d169546">changeset</a>
591 <a href="/rev/687f2d169546">changeset</a>
591 </div>
592 </div>
592 </td>
593 </td>
593 <td class="source followlines-btn-parent"><a href="#l16"> 16</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
594 <td class="source followlines-btn-parent"><a href="#l16"> 16</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
594 </tr>
595 </tr>
595 <tr id="l17" class="thisrev">
596 <tr id="l17" class="thisrev">
596 <td class="annotate parity0">
597 <td class="annotate parity0">
597
598
598 <div class="annotate-info">
599 <div class="annotate-info">
599 <div>
600 <div>
600 <a href="/annotate/687f2d169546/primes.py#l17">
601 <a href="/annotate/687f2d169546/primes.py#l17">
601 687f2d169546</a>
602 687f2d169546</a>
602 a
603 a
603 </div>
604 </div>
604 <div><em>&#116;&#101;&#115;&#116;</em></div>
605 <div><em>&#116;&#101;&#115;&#116;</em></div>
605 <div>parents: </div>
606 <div>parents: </div>
606 <a href="/diff/687f2d169546/primes.py">diff</a>
607 <a href="/diff/687f2d169546/primes.py">diff</a>
607 <a href="/rev/687f2d169546">changeset</a>
608 <a href="/rev/687f2d169546">changeset</a>
608 </div>
609 </div>
609 </td>
610 </td>
610 <td class="source followlines-btn-parent"><a href="#l17"> 17</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
611 <td class="source followlines-btn-parent"><a href="#l17"> 17</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
611 </tr>
612 </tr>
612 <tr id="l18" class="thisrev">
613 <tr id="l18" class="thisrev">
613 <td class="annotate parity0">
614 <td class="annotate parity0">
614
615
615 <div class="annotate-info">
616 <div class="annotate-info">
616 <div>
617 <div>
617 <a href="/annotate/687f2d169546/primes.py#l18">
618 <a href="/annotate/687f2d169546/primes.py#l18">
618 687f2d169546</a>
619 687f2d169546</a>
619 a
620 a
620 </div>
621 </div>
621 <div><em>&#116;&#101;&#115;&#116;</em></div>
622 <div><em>&#116;&#101;&#115;&#116;</em></div>
622 <div>parents: </div>
623 <div>parents: </div>
623 <a href="/diff/687f2d169546/primes.py">diff</a>
624 <a href="/diff/687f2d169546/primes.py">diff</a>
624 <a href="/rev/687f2d169546">changeset</a>
625 <a href="/rev/687f2d169546">changeset</a>
625 </div>
626 </div>
626 </td>
627 </td>
627 <td class="source followlines-btn-parent"><a href="#l18"> 18</a> <span class="kn">yield</span> <span class="n">n</span></td>
628 <td class="source followlines-btn-parent"><a href="#l18"> 18</a> <span class="kn">yield</span> <span class="n">n</span></td>
628 </tr>
629 </tr>
629 <tr id="l19" class="thisrev">
630 <tr id="l19" class="thisrev">
630 <td class="annotate parity0">
631 <td class="annotate parity0">
631
632
632 <div class="annotate-info">
633 <div class="annotate-info">
633 <div>
634 <div>
634 <a href="/annotate/687f2d169546/primes.py#l19">
635 <a href="/annotate/687f2d169546/primes.py#l19">
635 687f2d169546</a>
636 687f2d169546</a>
636 a
637 a
637 </div>
638 </div>
638 <div><em>&#116;&#101;&#115;&#116;</em></div>
639 <div><em>&#116;&#101;&#115;&#116;</em></div>
639 <div>parents: </div>
640 <div>parents: </div>
640 <a href="/diff/687f2d169546/primes.py">diff</a>
641 <a href="/diff/687f2d169546/primes.py">diff</a>
641 <a href="/rev/687f2d169546">changeset</a>
642 <a href="/rev/687f2d169546">changeset</a>
642 </div>
643 </div>
643 </td>
644 </td>
644 <td class="source followlines-btn-parent"><a href="#l19"> 19</a> </td>
645 <td class="source followlines-btn-parent"><a href="#l19"> 19</a> </td>
645 </tr>
646 </tr>
646 <tr id="l20" class="thisrev">
647 <tr id="l20" class="thisrev">
647 <td class="annotate parity0">
648 <td class="annotate parity0">
648
649
649 <div class="annotate-info">
650 <div class="annotate-info">
650 <div>
651 <div>
651 <a href="/annotate/687f2d169546/primes.py#l20">
652 <a href="/annotate/687f2d169546/primes.py#l20">
652 687f2d169546</a>
653 687f2d169546</a>
653 a
654 a
654 </div>
655 </div>
655 <div><em>&#116;&#101;&#115;&#116;</em></div>
656 <div><em>&#116;&#101;&#115;&#116;</em></div>
656 <div>parents: </div>
657 <div>parents: </div>
657 <a href="/diff/687f2d169546/primes.py">diff</a>
658 <a href="/diff/687f2d169546/primes.py">diff</a>
658 <a href="/rev/687f2d169546">changeset</a>
659 <a href="/rev/687f2d169546">changeset</a>
659 </div>
660 </div>
660 </td>
661 </td>
661 <td class="source followlines-btn-parent"><a href="#l20"> 20</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></td>
662 <td class="source followlines-btn-parent"><a href="#l20"> 20</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">())</span></td>
662 </tr>
663 </tr>
663 <tr id="l21" class="thisrev">
664 <tr id="l21" class="thisrev">
664 <td class="annotate parity0">
665 <td class="annotate parity0">
665
666
666 <div class="annotate-info">
667 <div class="annotate-info">
667 <div>
668 <div>
668 <a href="/annotate/687f2d169546/primes.py#l21">
669 <a href="/annotate/687f2d169546/primes.py#l21">
669 687f2d169546</a>
670 687f2d169546</a>
670 a
671 a
671 </div>
672 </div>
672 <div><em>&#116;&#101;&#115;&#116;</em></div>
673 <div><em>&#116;&#101;&#115;&#116;</em></div>
673 <div>parents: </div>
674 <div>parents: </div>
674 <a href="/diff/687f2d169546/primes.py">diff</a>
675 <a href="/diff/687f2d169546/primes.py">diff</a>
675 <a href="/rev/687f2d169546">changeset</a>
676 <a href="/rev/687f2d169546">changeset</a>
676 </div>
677 </div>
677 </td>
678 </td>
678 <td class="source followlines-btn-parent"><a href="#l21"> 21</a> <span class="n">dropwhile</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">dropwhile</span></td>
679 <td class="source followlines-btn-parent"><a href="#l21"> 21</a> <span class="n">dropwhile</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">dropwhile</span></td>
679 </tr>
680 </tr>
680 <tr id="l22" class="thisrev">
681 <tr id="l22" class="thisrev">
681 <td class="annotate parity0">
682 <td class="annotate parity0">
682
683
683 <div class="annotate-info">
684 <div class="annotate-info">
684 <div>
685 <div>
685 <a href="/annotate/687f2d169546/primes.py#l22">
686 <a href="/annotate/687f2d169546/primes.py#l22">
686 687f2d169546</a>
687 687f2d169546</a>
687 a
688 a
688 </div>
689 </div>
689 <div><em>&#116;&#101;&#115;&#116;</em></div>
690 <div><em>&#116;&#101;&#115;&#116;</em></div>
690 <div>parents: </div>
691 <div>parents: </div>
691 <a href="/diff/687f2d169546/primes.py">diff</a>
692 <a href="/diff/687f2d169546/primes.py">diff</a>
692 <a href="/rev/687f2d169546">changeset</a>
693 <a href="/rev/687f2d169546">changeset</a>
693 </div>
694 </div>
694 </td>
695 </td>
695 <td class="source followlines-btn-parent"><a href="#l22"> 22</a> <span class="kn">return</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
696 <td class="source followlines-btn-parent"><a href="#l22"> 22</a> <span class="kn">return</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
696 </tr>
697 </tr>
697 <tr id="l23" class="thisrev">
698 <tr id="l23" class="thisrev">
698 <td class="annotate parity0">
699 <td class="annotate parity0">
699
700
700 <div class="annotate-info">
701 <div class="annotate-info">
701 <div>
702 <div>
702 <a href="/annotate/687f2d169546/primes.py#l23">
703 <a href="/annotate/687f2d169546/primes.py#l23">
703 687f2d169546</a>
704 687f2d169546</a>
704 a
705 a
705 </div>
706 </div>
706 <div><em>&#116;&#101;&#115;&#116;</em></div>
707 <div><em>&#116;&#101;&#115;&#116;</em></div>
707 <div>parents: </div>
708 <div>parents: </div>
708 <a href="/diff/687f2d169546/primes.py">diff</a>
709 <a href="/diff/687f2d169546/primes.py">diff</a>
709 <a href="/rev/687f2d169546">changeset</a>
710 <a href="/rev/687f2d169546">changeset</a>
710 </div>
711 </div>
711 </td>
712 </td>
712 <td class="source followlines-btn-parent"><a href="#l23"> 23</a> </td>
713 <td class="source followlines-btn-parent"><a href="#l23"> 23</a> </td>
713 </tr>
714 </tr>
714 <tr id="l24" class="thisrev">
715 <tr id="l24" class="thisrev">
715 <td class="annotate parity0">
716 <td class="annotate parity0">
716
717
717 <div class="annotate-info">
718 <div class="annotate-info">
718 <div>
719 <div>
719 <a href="/annotate/687f2d169546/primes.py#l24">
720 <a href="/annotate/687f2d169546/primes.py#l24">
720 687f2d169546</a>
721 687f2d169546</a>
721 a
722 a
722 </div>
723 </div>
723 <div><em>&#116;&#101;&#115;&#116;</em></div>
724 <div><em>&#116;&#101;&#115;&#116;</em></div>
724 <div>parents: </div>
725 <div>parents: </div>
725 <a href="/diff/687f2d169546/primes.py">diff</a>
726 <a href="/diff/687f2d169546/primes.py">diff</a>
726 <a href="/rev/687f2d169546">changeset</a>
727 <a href="/rev/687f2d169546">changeset</a>
727 </div>
728 </div>
728 </td>
729 </td>
729 <td class="source followlines-btn-parent"><a href="#l24"> 24</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
730 <td class="source followlines-btn-parent"><a href="#l24"> 24</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
730 </tr>
731 </tr>
731 <tr id="l25" class="thisrev">
732 <tr id="l25" class="thisrev">
732 <td class="annotate parity0">
733 <td class="annotate parity0">
733
734
734 <div class="annotate-info">
735 <div class="annotate-info">
735 <div>
736 <div>
736 <a href="/annotate/687f2d169546/primes.py#l25">
737 <a href="/annotate/687f2d169546/primes.py#l25">
737 687f2d169546</a>
738 687f2d169546</a>
738 a
739 a
739 </div>
740 </div>
740 <div><em>&#116;&#101;&#115;&#116;</em></div>
741 <div><em>&#116;&#101;&#115;&#116;</em></div>
741 <div>parents: </div>
742 <div>parents: </div>
742 <a href="/diff/687f2d169546/primes.py">diff</a>
743 <a href="/diff/687f2d169546/primes.py">diff</a>
743 <a href="/rev/687f2d169546">changeset</a>
744 <a href="/rev/687f2d169546">changeset</a>
744 </div>
745 </div>
745 </td>
746 </td>
746 <td class="source followlines-btn-parent"><a href="#l25"> 25</a> <span class="kn">import</span> <span class="nn">sys</span></td>
747 <td class="source followlines-btn-parent"><a href="#l25"> 25</a> <span class="kn">import</span> <span class="nn">sys</span></td>
747 </tr>
748 </tr>
748 <tr id="l26" class="thisrev">
749 <tr id="l26" class="thisrev">
749 <td class="annotate parity0">
750 <td class="annotate parity0">
750
751
751 <div class="annotate-info">
752 <div class="annotate-info">
752 <div>
753 <div>
753 <a href="/annotate/687f2d169546/primes.py#l26">
754 <a href="/annotate/687f2d169546/primes.py#l26">
754 687f2d169546</a>
755 687f2d169546</a>
755 a
756 a
756 </div>
757 </div>
757 <div><em>&#116;&#101;&#115;&#116;</em></div>
758 <div><em>&#116;&#101;&#115;&#116;</em></div>
758 <div>parents: </div>
759 <div>parents: </div>
759 <a href="/diff/687f2d169546/primes.py">diff</a>
760 <a href="/diff/687f2d169546/primes.py">diff</a>
760 <a href="/rev/687f2d169546">changeset</a>
761 <a href="/rev/687f2d169546">changeset</a>
761 </div>
762 </div>
762 </td>
763 </td>
763 <td class="source followlines-btn-parent"><a href="#l26"> 26</a> <span class="kn">try</span><span class="p">:</span></td>
764 <td class="source followlines-btn-parent"><a href="#l26"> 26</a> <span class="kn">try</span><span class="p">:</span></td>
764 </tr>
765 </tr>
765 <tr id="l27" class="thisrev">
766 <tr id="l27" class="thisrev">
766 <td class="annotate parity0">
767 <td class="annotate parity0">
767
768
768 <div class="annotate-info">
769 <div class="annotate-info">
769 <div>
770 <div>
770 <a href="/annotate/687f2d169546/primes.py#l27">
771 <a href="/annotate/687f2d169546/primes.py#l27">
771 687f2d169546</a>
772 687f2d169546</a>
772 a
773 a
773 </div>
774 </div>
774 <div><em>&#116;&#101;&#115;&#116;</em></div>
775 <div><em>&#116;&#101;&#115;&#116;</em></div>
775 <div>parents: </div>
776 <div>parents: </div>
776 <a href="/diff/687f2d169546/primes.py">diff</a>
777 <a href="/diff/687f2d169546/primes.py">diff</a>
777 <a href="/rev/687f2d169546">changeset</a>
778 <a href="/rev/687f2d169546">changeset</a>
778 </div>
779 </div>
779 </td>
780 </td>
780 <td class="source followlines-btn-parent"><a href="#l27"> 27</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></td>
781 <td class="source followlines-btn-parent"><a href="#l27"> 27</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></td>
781 </tr>
782 </tr>
782 <tr id="l28" class="thisrev">
783 <tr id="l28" class="thisrev">
783 <td class="annotate parity0">
784 <td class="annotate parity0">
784
785
785 <div class="annotate-info">
786 <div class="annotate-info">
786 <div>
787 <div>
787 <a href="/annotate/687f2d169546/primes.py#l28">
788 <a href="/annotate/687f2d169546/primes.py#l28">
788 687f2d169546</a>
789 687f2d169546</a>
789 a
790 a
790 </div>
791 </div>
791 <div><em>&#116;&#101;&#115;&#116;</em></div>
792 <div><em>&#116;&#101;&#115;&#116;</em></div>
792 <div>parents: </div>
793 <div>parents: </div>
793 <a href="/diff/687f2d169546/primes.py">diff</a>
794 <a href="/diff/687f2d169546/primes.py">diff</a>
794 <a href="/rev/687f2d169546">changeset</a>
795 <a href="/rev/687f2d169546">changeset</a>
795 </div>
796 </div>
796 </td>
797 </td>
797 <td class="source followlines-btn-parent"><a href="#l28"> 28</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
798 <td class="source followlines-btn-parent"><a href="#l28"> 28</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
798 </tr>
799 </tr>
799 <tr id="l29" class="thisrev">
800 <tr id="l29" class="thisrev">
800 <td class="annotate parity0">
801 <td class="annotate parity0">
801
802
802 <div class="annotate-info">
803 <div class="annotate-info">
803 <div>
804 <div>
804 <a href="/annotate/687f2d169546/primes.py#l29">
805 <a href="/annotate/687f2d169546/primes.py#l29">
805 687f2d169546</a>
806 687f2d169546</a>
806 a
807 a
807 </div>
808 </div>
808 <div><em>&#116;&#101;&#115;&#116;</em></div>
809 <div><em>&#116;&#101;&#115;&#116;</em></div>
809 <div>parents: </div>
810 <div>parents: </div>
810 <a href="/diff/687f2d169546/primes.py">diff</a>
811 <a href="/diff/687f2d169546/primes.py">diff</a>
811 <a href="/rev/687f2d169546">changeset</a>
812 <a href="/rev/687f2d169546">changeset</a>
812 </div>
813 </div>
813 </td>
814 </td>
814 <td class="source followlines-btn-parent"><a href="#l29"> 29</a> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></td>
815 <td class="source followlines-btn-parent"><a href="#l29"> 29</a> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></td>
815 </tr>
816 </tr>
816 <tr id="l30" class="thisrev">
817 <tr id="l30" class="thisrev">
817 <td class="annotate parity0">
818 <td class="annotate parity0">
818
819
819 <div class="annotate-info">
820 <div class="annotate-info">
820 <div>
821 <div>
821 <a href="/annotate/687f2d169546/primes.py#l30">
822 <a href="/annotate/687f2d169546/primes.py#l30">
822 687f2d169546</a>
823 687f2d169546</a>
823 a
824 a
824 </div>
825 </div>
825 <div><em>&#116;&#101;&#115;&#116;</em></div>
826 <div><em>&#116;&#101;&#115;&#116;</em></div>
826 <div>parents: </div>
827 <div>parents: </div>
827 <a href="/diff/687f2d169546/primes.py">diff</a>
828 <a href="/diff/687f2d169546/primes.py">diff</a>
828 <a href="/rev/687f2d169546">changeset</a>
829 <a href="/rev/687f2d169546">changeset</a>
829 </div>
830 </div>
830 </td>
831 </td>
831 <td class="source followlines-btn-parent"><a href="#l30"> 30</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
832 <td class="source followlines-btn-parent"><a href="#l30"> 30</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
832 </tr>
833 </tr>
833 <tr id="l31" class="thisrev">
834 <tr id="l31" class="thisrev">
834 <td class="annotate parity0">
835 <td class="annotate parity0">
835
836
836 <div class="annotate-info">
837 <div class="annotate-info">
837 <div>
838 <div>
838 <a href="/annotate/687f2d169546/primes.py#l31">
839 <a href="/annotate/687f2d169546/primes.py#l31">
839 687f2d169546</a>
840 687f2d169546</a>
840 a
841 a
841 </div>
842 </div>
842 <div><em>&#116;&#101;&#115;&#116;</em></div>
843 <div><em>&#116;&#101;&#115;&#116;</em></div>
843 <div>parents: </div>
844 <div>parents: </div>
844 <a href="/diff/687f2d169546/primes.py">diff</a>
845 <a href="/diff/687f2d169546/primes.py">diff</a>
845 <a href="/rev/687f2d169546">changeset</a>
846 <a href="/rev/687f2d169546">changeset</a>
846 </div>
847 </div>
847 </td>
848 </td>
848 <td class="source followlines-btn-parent"><a href="#l31"> 31</a> <span class="kn">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></td>
849 <td class="source followlines-btn-parent"><a href="#l31"> 31</a> <span class="nb">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></td> (pygments25 !)
850 <td class="source followlines-btn-parent"><a href="#l31"> 31</a> <span class="kn">print</span><span class="p">(</span><span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">))))</span></td> (no-pygments25 !)
849 </tr>
851 </tr>
850 <tr id="l32" class="thisrev">
852 <tr id="l32" class="thisrev">
851 <td class="annotate parity0">
853 <td class="annotate parity0">
852
854
853 <div class="annotate-info">
855 <div class="annotate-info">
854 <div>
856 <div>
855 <a href="/annotate/687f2d169546/primes.py#l32">
857 <a href="/annotate/687f2d169546/primes.py#l32">
856 687f2d169546</a>
858 687f2d169546</a>
857 a
859 a
858 </div>
860 </div>
859 <div><em>&#116;&#101;&#115;&#116;</em></div>
861 <div><em>&#116;&#101;&#115;&#116;</em></div>
860 <div>parents: </div>
862 <div>parents: </div>
861 <a href="/diff/687f2d169546/primes.py">diff</a>
863 <a href="/diff/687f2d169546/primes.py">diff</a>
862 <a href="/rev/687f2d169546">changeset</a>
864 <a href="/rev/687f2d169546">changeset</a>
863 </div>
865 </div>
864 </td>
866 </td>
865 <td class="source followlines-btn-parent"><a href="#l32"> 32</a> </td>
867 <td class="source followlines-btn-parent"><a href="#l32"> 32</a> </td>
866 </tr>
868 </tr>
867 </tbody>
869 </tbody>
868 </table>
870 </table>
869 </div>
871 </div>
870 </div>
872 </div>
871 </div>
873 </div>
872
874
873 <script type="text/javascript" src="/static/followlines.js"></script>
875 <script type="text/javascript" src="/static/followlines.js"></script>
874
876
875
877
876
878
877 </body>
879 </body>
878 </html>
880 </html>
879
881
880
882
881 hgweb fileannotate, raw
883 hgweb fileannotate, raw
882
884
883 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
885 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
884 > | sed "s/test@//" > a
886 > | sed "s/test@//" > a
885 $ echo "200 Script output follows" > b
887 $ echo "200 Script output follows" > b
886 $ echo "" >> b
888 $ echo "" >> b
887 $ echo "" >> b
889 $ echo "" >> b
888 $ hg annotate "primes.py" >> b
890 $ hg annotate "primes.py" >> b
889 $ echo "" >> b
891 $ echo "" >> b
890 $ echo "" >> b
892 $ echo "" >> b
891 $ echo "" >> b
893 $ echo "" >> b
892 $ echo "" >> b
894 $ echo "" >> b
893 $ cmp b a || diff -u b a
895 $ cmp b a || diff -u b a
894
896
895 hgweb filerevision, raw
897 hgweb filerevision, raw
896
898
897 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py?style=raw') \
899 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py?style=raw') \
898 > > a
900 > > a
899 $ echo "200 Script output follows" > b
901 $ echo "200 Script output follows" > b
900 $ echo "" >> b
902 $ echo "" >> b
901 $ hg cat primes.py >> b
903 $ hg cat primes.py >> b
902 $ cmp b a || diff -u b a
904 $ cmp b a || diff -u b a
903
905
904 hgweb highlightcss friendly
906 hgweb highlightcss friendly
905
907
906 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
908 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
907 $ head -n 4 out
909 $ head -n 4 out
908 200 Script output follows
910 200 Script output follows
909
911
910 /* pygments_style = friendly */
912 /* pygments_style = friendly */
911
913
912 $ rm out
914 $ rm out
913
915
914 errors encountered
916 errors encountered
915
917
916 $ cat errors.log
918 $ cat errors.log
917 $ killdaemons.py
919 $ killdaemons.py
918
920
919 Change the pygments style
921 Change the pygments style
920
922
921 $ cat > .hg/hgrc <<EOF
923 $ cat > .hg/hgrc <<EOF
922 > [web]
924 > [web]
923 > pygments_style = fruity
925 > pygments_style = fruity
924 > EOF
926 > EOF
925
927
926 hg serve again
928 hg serve again
927
929
928 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
930 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
929 $ cat hg.pid >> $DAEMON_PIDS
931 $ cat hg.pid >> $DAEMON_PIDS
930
932
931 hgweb highlightcss fruity
933 hgweb highlightcss fruity
932
934
933 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
935 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
934 $ head -n 4 out
936 $ head -n 4 out
935 200 Script output follows
937 200 Script output follows
936
938
937 /* pygments_style = fruity */
939 /* pygments_style = fruity */
938
940
939 $ rm out
941 $ rm out
940
942
941 errors encountered
943 errors encountered
942
944
943 $ cat errors.log
945 $ cat errors.log
944 $ killdaemons.py
946 $ killdaemons.py
945
947
946 only highlight C source files
948 only highlight C source files
947
949
948 $ cat > .hg/hgrc <<EOF
950 $ cat > .hg/hgrc <<EOF
949 > [web]
951 > [web]
950 > highlightfiles = **.c
952 > highlightfiles = **.c
951 > EOF
953 > EOF
952
954
953 hg serve again
955 hg serve again
954
956
955 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
957 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
956 $ cat hg.pid >> $DAEMON_PIDS
958 $ cat hg.pid >> $DAEMON_PIDS
957
959
958 test that fileset in highlightfiles works and primes.py is not highlighted
960 test that fileset in highlightfiles works and primes.py is not highlighted
959
961
960 $ get-with-headers.py localhost:$HGPORT 'file/tip/primes.py' | grep 'id="l11"'
962 $ get-with-headers.py localhost:$HGPORT 'file/tip/primes.py' | grep 'id="l11"'
961 <span id="l11"> def sieve(ns):</span><a href="#l11"></a>
963 <span id="l11"> def sieve(ns):</span><a href="#l11"></a>
962
964
963 errors encountered
965 errors encountered
964
966
965 $ cat errors.log
967 $ cat errors.log
966 $ cd ..
968 $ cd ..
967 $ hg init eucjp
969 $ hg init eucjp
968 $ cd eucjp
970 $ cd eucjp
969 >>> with open('eucjp.txt', 'wb') as fh:
971 >>> with open('eucjp.txt', 'wb') as fh:
970 ... # Japanese kanji "Kyo"
972 ... # Japanese kanji "Kyo"
971 ... fh.write(u'\265\376'.encode('utf-8')) and None
973 ... fh.write(u'\265\376'.encode('utf-8')) and None
972 $ hg ci -Ama
974 $ hg ci -Ama
973 adding eucjp.txt
975 adding eucjp.txt
974 $ hgserveget () {
976 $ hgserveget () {
975 > killdaemons.py
977 > killdaemons.py
976 > echo % HGENCODING="$1" hg serve
978 > echo % HGENCODING="$1" hg serve
977 > HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
979 > HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
978 > cat hg.pid >> $DAEMON_PIDS
980 > cat hg.pid >> $DAEMON_PIDS
979 >
981 >
980 > echo % hgweb filerevision, html
982 > echo % hgweb filerevision, html
981 > get-with-headers.py localhost:$HGPORT "file/tip/$2" \
983 > get-with-headers.py localhost:$HGPORT "file/tip/$2" \
982 > | grep '<div class="parity0 source">'
984 > | grep '<div class="parity0 source">'
983 > echo % errors encountered
985 > echo % errors encountered
984 > cat errors.log
986 > cat errors.log
985 > }
987 > }
986 $ hgserveget euc-jp eucjp.txt
988 $ hgserveget euc-jp eucjp.txt
987 % HGENCODING=euc-jp hg serve
989 % HGENCODING=euc-jp hg serve
988 % hgweb filerevision, html
990 % hgweb filerevision, html
989 % errors encountered
991 % errors encountered
990 $ hgserveget utf-8 eucjp.txt
992 $ hgserveget utf-8 eucjp.txt
991 % HGENCODING=utf-8 hg serve
993 % HGENCODING=utf-8 hg serve
992 % hgweb filerevision, html
994 % hgweb filerevision, html
993 % errors encountered
995 % errors encountered
994 $ hgserveget us-ascii eucjp.txt
996 $ hgserveget us-ascii eucjp.txt
995 % HGENCODING=us-ascii hg serve
997 % HGENCODING=us-ascii hg serve
996 % hgweb filerevision, html
998 % hgweb filerevision, html
997 % errors encountered
999 % errors encountered
998
1000
999 We attempt to highlight unknown files by default
1001 We attempt to highlight unknown files by default
1000
1002
1001 $ killdaemons.py
1003 $ killdaemons.py
1002
1004
1003 $ cat > .hg/hgrc << EOF
1005 $ cat > .hg/hgrc << EOF
1004 > [web]
1006 > [web]
1005 > highlightfiles = **
1007 > highlightfiles = **
1006 > EOF
1008 > EOF
1007
1009
1008 $ cat > unknownfile << EOF
1010 $ cat > unknownfile << EOF
1009 > #!$PYTHON
1011 > #!$PYTHON
1010 > def foo():
1012 > def foo():
1011 > pass
1013 > pass
1012 > EOF
1014 > EOF
1013
1015
1014 $ hg add unknownfile
1016 $ hg add unknownfile
1015 $ hg commit -m unknown unknownfile
1017 $ hg commit -m unknown unknownfile
1016
1018
1017 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
1019 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
1018 $ cat hg.pid >> $DAEMON_PIDS
1020 $ cat hg.pid >> $DAEMON_PIDS
1019
1021
1020 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
1022 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
1021 <span id="l2"><span class="k">def</span> <span class="nf">foo</span><span class="p">():</span></span><a href="#l2"></a>
1023 <span id="l2"><span class="k">def</span> <span class="nf">foo</span><span class="p">():</span></span><a href="#l2"></a>
1022
1024
1023 We can prevent Pygments from falling back to a non filename-based
1025 We can prevent Pygments from falling back to a non filename-based
1024 detection mode
1026 detection mode
1025
1027
1026 $ cat > .hg/hgrc << EOF
1028 $ cat > .hg/hgrc << EOF
1027 > [web]
1029 > [web]
1028 > highlightfiles = **
1030 > highlightfiles = **
1029 > highlightonlymatchfilename = true
1031 > highlightonlymatchfilename = true
1030 > EOF
1032 > EOF
1031
1033
1032 $ killdaemons.py
1034 $ killdaemons.py
1033 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
1035 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
1034 $ cat hg.pid >> $DAEMON_PIDS
1036 $ cat hg.pid >> $DAEMON_PIDS
1035 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
1037 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
1036 <span id="l2">def foo():</span><a href="#l2"></a>
1038 <span id="l2">def foo():</span><a href="#l2"></a>
1037
1039
1038 $ cd ..
1040 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now