##// END OF EJS Templates
black: blacken scripts...
Gregory Szorc -
r44058:99e231af default
parent child Browse files
Show More
@@ -1,103 +1,115 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # Copyright 2014 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # A tool/hook to run basic sanity checks on commits/patches for
6 6 # submission to Mercurial. Install by adding the following to your
7 7 # .hg/hgrc:
8 8 #
9 9 # [hooks]
10 10 # pretxncommit = contrib/check-commit
11 11 #
12 12 # The hook can be temporarily bypassed with:
13 13 #
14 14 # $ BYPASS= hg commit
15 15 #
16 16 # See also: https://mercurial-scm.org/wiki/ContributingChanges
17 17
18 18 from __future__ import absolute_import, print_function
19 19
20 20 import os
21 21 import re
22 22 import sys
23 23
24 24 commitheader = r"^(?:# [^\n]*\n)*"
25 25 afterheader = commitheader + r"(?!#)"
26 26 beforepatch = afterheader + r"(?!\n(?!@@))"
27 27
28 28 errors = [
29 29 (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"),
30 (beforepatch + r".*[(]issue \d\d\d",
31 "no space allowed between issue and number"),
30 (
31 beforepatch + r".*[(]issue \d\d\d",
32 "no space allowed between issue and number",
33 ),
32 34 (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
33 35 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
34 (commitheader + r"(?!merge with )[^#]\S+[^:] ",
35 "summary line doesn't start with 'topic: '"),
36 (
37 commitheader + r"(?!merge with )[^#]\S+[^:] ",
38 "summary line doesn't start with 'topic: '",
39 ),
36 40 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
37 41 (afterheader + r"^\S+: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
38 (afterheader + r"\S*[^A-Za-z0-9-_]\S*: ",
39 "summary keyword should be most user-relevant one-word command or topic"),
42 (
43 afterheader + r"\S*[^A-Za-z0-9-_]\S*: ",
44 "summary keyword should be most user-relevant one-word command or topic",
45 ),
40 46 (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"),
41 47 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
42 48 ]
43 49
44 50 word = re.compile(r'\S')
51
52
45 53 def nonempty(first, second):
46 54 if word.search(first):
47 55 return first
48 56 return second
49 57
58
50 59 def checkcommit(commit, node=None):
51 60 exitcode = 0
52 61 printed = node is None
53 62 hits = []
54 signtag = (afterheader +
55 r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}')
63 signtag = (
64 afterheader + r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}'
65 )
56 66 if re.search(signtag, commit):
57 67 return 0
58 68 for exp, msg in errors:
59 69 for m in re.finditer(exp, commit):
60 70 end = m.end()
61 71 trailing = re.search(r'(\\n)+$', exp)
62 72 if trailing:
63 73 end -= len(trailing.group()) / 2
64 74 hits.append((end, exp, msg))
65 75 if hits:
66 76 hits.sort()
67 77 pos = 0
68 78 last = ''
69 79 for n, l in enumerate(commit.splitlines(True)):
70 80 pos += len(l)
71 81 while len(hits):
72 82 end, exp, msg = hits[0]
73 83 if pos < end:
74 84 break
75 85 if not printed:
76 86 printed = True
77 87 print("node: %s" % node)
78 88 print("%d: %s" % (n, msg))
79 89 print(" %s" % nonempty(l, last)[:-1])
80 90 if "BYPASS" not in os.environ:
81 91 exitcode = 1
82 92 del hits[0]
83 93 last = nonempty(l, last)
84 94
85 95 return exitcode
86 96
97
87 98 def readcommit(node):
88 99 return os.popen("hg export %s" % node).read()
89 100
101
90 102 if __name__ == "__main__":
91 103 exitcode = 0
92 104 node = os.environ.get("HG_NODE")
93 105
94 106 if node:
95 107 commit = readcommit(node)
96 108 exitcode = checkcommit(commit)
97 109 elif sys.argv[1:]:
98 110 for node in sys.argv[1:]:
99 111 exitcode |= checkcommit(readcommit(node), node)
100 112 else:
101 113 commit = sys.stdin.read()
102 114 exitcode = checkcommit(commit)
103 115 sys.exit(exitcode)
@@ -1,44 +1,47 b''
1 1 #!/usr/bin/env python
2 2 # Dump revlogs as raw data stream
3 3 # $ find .hg/store/ -name "*.i" | xargs dumprevlog > repo.dump
4 4
5 5 from __future__ import absolute_import, print_function
6 6
7 7 import sys
8 8 from mercurial import (
9 9 encoding,
10 10 node,
11 11 pycompat,
12 12 revlog,
13 13 )
14 from mercurial.utils import (
15 procutil,
16 )
14 from mercurial.utils import procutil
17 15
18 16 for fp in (sys.stdin, sys.stdout, sys.stderr):
19 17 procutil.setbinary(fp)
20 18
19
21 20 def binopen(path, mode=b'rb'):
22 21 if b'b' not in mode:
23 22 mode = mode + b'b'
24 23 return open(path, pycompat.sysstr(mode))
24
25
25 26 binopen.options = {}
26 27
28
27 29 def printb(data, end=b'\n'):
28 30 sys.stdout.flush()
29 31 pycompat.stdout.write(data + end)
30 32
33
31 34 for f in sys.argv[1:]:
32 35 r = revlog.revlog(binopen, encoding.strtolocal(f))
33 36 print("file:", f)
34 37 for i in r:
35 38 n = r.node(i)
36 39 p = r.parents(n)
37 40 d = r.revision(n)
38 41 printb(b"node: %s" % node.hex(n))
39 42 printb(b"linkrev: %d" % r.linkrev(i))
40 43 printb(b"parents: %s %s" % (node.hex(p[0]), node.hex(p[1])))
41 44 printb(b"length: %d" % len(d))
42 45 printb(b"-start-")
43 46 printb(d)
44 47 printb(b"-end-")
@@ -1,97 +1,111 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # Copyright 2005-2007 by Intevation GmbH <intevation@intevation.de>
4 4 #
5 5 # Author(s):
6 6 # Thomas Arendsen Hein <thomas@intevation.de>
7 7 #
8 8 # This software may be used and distributed according to the terms of the
9 9 # GNU General Public License version 2 or any later version.
10 10
11 11 """
12 12 hg-ssh - a wrapper for ssh access to a limited set of mercurial repos
13 13
14 14 To be used in ~/.ssh/authorized_keys with the "command" option, see sshd(8):
15 15 command="hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4" ssh-dss ...
16 16 (probably together with these other useful options:
17 17 no-port-forwarding,no-X11-forwarding,no-agent-forwarding)
18 18
19 19 This allows pull/push over ssh from/to the repositories given as arguments.
20 20
21 21 If all your repositories are subdirectories of a common directory, you can
22 22 allow shorter paths with:
23 23 command="cd path/to/my/repositories && hg-ssh repo1 subdir/repo2"
24 24
25 25 You can use pattern matching of your normal shell, e.g.:
26 26 command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}"
27 27
28 28 You can also add a --read-only flag to allow read-only access to a key, e.g.:
29 29 command="hg-ssh --read-only repos/*"
30 30 """
31 31 from __future__ import absolute_import
32 32
33 33 import os
34 34 import shlex
35 35 import sys
36 36
37 37 # enable importing on demand to reduce startup time
38 import hgdemandimport ; hgdemandimport.enable()
38 import hgdemandimport
39
40 hgdemandimport.enable()
39 41
40 42 from mercurial import (
41 43 dispatch,
42 44 pycompat,
43 45 ui as uimod,
44 46 )
45 47
48
46 49 def main():
47 50 # Prevent insertion/deletion of CRs
48 51 dispatch.initstdio()
49 52
50 53 cwd = os.getcwd()
51 54 readonly = False
52 55 args = sys.argv[1:]
53 56 while len(args):
54 57 if args[0] == '--read-only':
55 58 readonly = True
56 59 args.pop(0)
57 60 else:
58 61 break
59 allowed_paths = [os.path.normpath(os.path.join(cwd,
60 os.path.expanduser(path)))
61 for path in args]
62 allowed_paths = [
63 os.path.normpath(os.path.join(cwd, os.path.expanduser(path)))
64 for path in args
65 ]
62 66 orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?')
63 67 try:
64 68 cmdargv = shlex.split(orig_cmd)
65 69 except ValueError as e:
66 70 sys.stderr.write('Illegal command "%s": %s\n' % (orig_cmd, e))
67 71 sys.exit(255)
68 72
69 73 if cmdargv[:2] == ['hg', '-R'] and cmdargv[3:] == ['serve', '--stdio']:
70 74 path = cmdargv[2]
71 75 repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path)))
72 76 if repo in allowed_paths:
73 77 cmd = [b'-R', pycompat.fsencode(repo), b'serve', b'--stdio']
74 78 req = dispatch.request(cmd)
75 79 if readonly:
76 80 if not req.ui:
77 81 req.ui = uimod.ui.load()
78 req.ui.setconfig(b'hooks', b'pretxnopen.hg-ssh',
79 b'python:__main__.rejectpush', b'hg-ssh')
80 req.ui.setconfig(b'hooks', b'prepushkey.hg-ssh',
81 b'python:__main__.rejectpush', b'hg-ssh')
82 req.ui.setconfig(
83 b'hooks',
84 b'pretxnopen.hg-ssh',
85 b'python:__main__.rejectpush',
86 b'hg-ssh',
87 )
88 req.ui.setconfig(
89 b'hooks',
90 b'prepushkey.hg-ssh',
91 b'python:__main__.rejectpush',
92 b'hg-ssh',
93 )
82 94 dispatch.dispatch(req)
83 95 else:
84 96 sys.stderr.write('Illegal repository "%s"\n' % repo)
85 97 sys.exit(255)
86 98 else:
87 99 sys.stderr.write('Illegal command "%s"\n' % orig_cmd)
88 100 sys.exit(255)
89 101
102
90 103 def rejectpush(ui, **kwargs):
91 104 ui.warn((b"Permission denied\n"))
92 105 # mercurial hooks use unix process conventions for hook return values
93 106 # so a truthy return means failure
94 107 return True
95 108
109
96 110 if __name__ == '__main__':
97 111 main()
@@ -1,97 +1,112 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # hgperf - measure performance of Mercurial commands
4 4 #
5 5 # Copyright 2014 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 '''measure performance of Mercurial commands
11 11
12 12 Using ``hgperf`` instead of ``hg`` measures performance of the target
13 13 Mercurial command. For example, the execution below measures
14 14 performance of :hg:`heads --topo`::
15 15
16 16 $ hgperf heads --topo
17 17
18 18 All command output via ``ui`` is suppressed, and just measurement
19 19 result is displayed: see also "perf" extension in "contrib".
20 20
21 21 Costs of processing before dispatching to the command function like
22 22 below are not measured::
23 23
24 24 - parsing command line (e.g. option validity check)
25 25 - reading configuration files in
26 26
27 27 But ``pre-`` and ``post-`` hook invocation for the target command is
28 28 measured, even though these are invoked before or after dispatching to
29 29 the command function, because these may be required to repeat
30 30 execution of the target command correctly.
31 31 '''
32 32
33 33 import os
34 34 import sys
35 35
36 36 libdir = '@LIBDIR@'
37 37
38 38 if libdir != '@' 'LIBDIR' '@':
39 39 if not os.path.isabs(libdir):
40 libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
41 libdir)
40 libdir = os.path.join(
41 os.path.dirname(os.path.realpath(__file__)), libdir
42 )
42 43 libdir = os.path.abspath(libdir)
43 44 sys.path.insert(0, libdir)
44 45
45 46 # enable importing on demand to reduce startup time
46 47 try:
47 from mercurial import demandimport; demandimport.enable()
48 from mercurial import demandimport
49
50 demandimport.enable()
48 51 except ImportError:
49 52 import sys
50 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
51 ' '.join(sys.path))
53
54 sys.stderr.write(
55 "abort: couldn't find mercurial libraries in [%s]\n"
56 % ' '.join(sys.path)
57 )
52 58 sys.stderr.write("(check your install and PYTHONPATH)\n")
53 59 sys.exit(-1)
54 60
55 61 from mercurial import (
56 62 dispatch,
57 63 util,
58 64 )
59 65
66
60 67 def timer(func, title=None):
61 68 results = []
62 69 begin = util.timer()
63 70 count = 0
64 71 while True:
65 72 ostart = os.times()
66 73 cstart = util.timer()
67 74 r = func()
68 75 cstop = util.timer()
69 76 ostop = os.times()
70 77 count += 1
71 78 a, b = ostart, ostop
72 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
79 results.append((cstop - cstart, b[0] - a[0], b[1] - a[1]))
73 80 if cstop - begin > 3 and count >= 100:
74 81 break
75 82 if cstop - begin > 10 and count >= 3:
76 83 break
77 84 if title:
78 85 sys.stderr.write("! %s\n" % title)
79 86 if r:
80 87 sys.stderr.write("! result: %s\n" % r)
81 88 m = min(results)
82 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
83 % (m[0], m[1] + m[2], m[1], m[2], count))
89 sys.stderr.write(
90 "! wall %f comb %f user %f sys %f (best of %d)\n"
91 % (m[0], m[1] + m[2], m[1], m[2], count)
92 )
93
84 94
85 95 orgruncommand = dispatch.runcommand
86 96
97
87 98 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
88 99 ui.pushbuffer()
89 100 lui.pushbuffer()
90 timer(lambda : orgruncommand(lui, repo, cmd, fullargs, ui,
91 options, d, cmdpats, cmdoptions))
101 timer(
102 lambda: orgruncommand(
103 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
104 )
105 )
92 106 ui.popbuffer()
93 107 lui.popbuffer()
94 108
109
95 110 dispatch.runcommand = runcommand
96 111
97 112 dispatch.run()
@@ -1,19 +1,22 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # An example FastCGI script for use with flup, edit as necessary
4 4
5 5 # Path to repo or hgweb config to serve (see 'hg help hgweb')
6 6 config = "/path/to/repo/or/config"
7 7
8 8 # Uncomment and adjust if Mercurial is not installed system-wide
9 9 # (consult "installed modules" path from 'hg debuginstall'):
10 #import sys; sys.path.insert(0, "/path/to/python/lib")
10 # import sys; sys.path.insert(0, "/path/to/python/lib")
11 11
12 12 # Uncomment to send python tracebacks to the browser if an error occurs:
13 #import cgitb; cgitb.enable()
13 # import cgitb; cgitb.enable()
14 14
15 from mercurial import demandimport; demandimport.enable()
15 from mercurial import demandimport
16
17 demandimport.enable()
16 18 from mercurial.hgweb import hgweb
17 19 from flup.server.fcgi import WSGIServer
20
18 21 application = hgweb(config)
19 22 WSGIServer(application).run()
@@ -1,116 +1,129 b''
1 1 #!/usr/bin/env python3
2 2 #
3 3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import argparse
9 9 import pathlib
10 10 import shutil
11 11 import subprocess
12 12 import sys
13 13
14
14 15 def get_docker() -> str:
15 16 docker = shutil.which('docker.io') or shutil.which('docker')
16 17 if not docker:
17 18 print('could not find docker executable')
18 19 return 1
19 20
20 21 try:
21 22 out = subprocess.check_output([docker, '-h'], stderr=subprocess.STDOUT)
22 23
23 24 if b'Jansens' in out:
24 print('%s is the Docking System Tray; try installing docker.io' %
25 docker)
25 print(
26 '%s is the Docking System Tray; try installing docker.io'
27 % docker
28 )
26 29 sys.exit(1)
27 30 except subprocess.CalledProcessError as e:
28 31 print('error calling `%s -h`: %s' % (docker, e.output))
29 32 sys.exit(1)
30 33
31 out = subprocess.check_output([docker, 'version'],
32 stderr=subprocess.STDOUT)
34 out = subprocess.check_output([docker, 'version'], stderr=subprocess.STDOUT)
33 35
34 36 lines = out.splitlines()
35 37 if not any(l.startswith((b'Client:', b'Client version:')) for l in lines):
36 38 print('`%s version` does not look like Docker' % docker)
37 39 sys.exit(1)
38 40
39 41 if not any(l.startswith((b'Server:', b'Server version:')) for l in lines):
40 42 print('`%s version` does not look like Docker' % docker)
41 43 sys.exit(1)
42 44
43 45 return docker
44 46
47
45 48 def get_dockerfile(path: pathlib.Path, args: list) -> bytes:
46 49 with path.open('rb') as fh:
47 50 df = fh.read()
48 51
49 52 for k, v in args:
50 53 df = df.replace(bytes('%%%s%%' % k.decode(), 'utf-8'), v)
51 54
52 55 return df
53 56
57
54 58 def build_docker_image(dockerfile: pathlib.Path, params: list, tag: str):
55 59 """Build a Docker image from a templatized Dockerfile."""
56 60 docker = get_docker()
57 61
58 62 dockerfile_path = pathlib.Path(dockerfile)
59 63
60 64 dockerfile = get_dockerfile(dockerfile_path, params)
61 65
62 66 print('building Dockerfile:')
63 67 print(dockerfile.decode('utf-8', 'replace'))
64 68
65 69 args = [
66 70 docker,
67 71 'build',
68 '--build-arg', 'http_proxy',
69 '--build-arg', 'https_proxy',
70 '--tag', tag,
72 '--build-arg',
73 'http_proxy',
74 '--build-arg',
75 'https_proxy',
76 '--tag',
77 tag,
71 78 '-',
72 79 ]
73 80
74 81 print('executing: %r' % args)
75 82 p = subprocess.Popen(args, stdin=subprocess.PIPE)
76 83 p.communicate(input=dockerfile)
77 84 if p.returncode:
78 85 raise subprocess.CalledProcessException(
79 p.returncode, 'failed to build docker image: %s %s'
80 % (p.stdout, p.stderr))
86 p.returncode,
87 'failed to build docker image: %s %s' % (p.stdout, p.stderr),
88 )
89
81 90
82 91 def command_build(args):
83 92 build_args = []
84 93 for arg in args.build_arg:
85 94 k, v = arg.split('=', 1)
86 95 build_args.append((k.encode('utf-8'), v.encode('utf-8')))
87 96
88 build_docker_image(pathlib.Path(args.dockerfile),
89 build_args,
90 args.tag)
97 build_docker_image(pathlib.Path(args.dockerfile), build_args, args.tag)
98
91 99
92 100 def command_docker(args):
93 101 print(get_docker())
94 102
103
95 104 def main() -> int:
96 105 parser = argparse.ArgumentParser()
97 106
98 107 subparsers = parser.add_subparsers(title='subcommands')
99 108
100 109 build = subparsers.add_parser('build', help='Build a Docker image')
101 110 build.set_defaults(func=command_build)
102 build.add_argument('--build-arg', action='append', default=[],
103 help='Substitution to perform in Dockerfile; '
104 'format: key=value')
111 build.add_argument(
112 '--build-arg',
113 action='append',
114 default=[],
115 help='Substitution to perform in Dockerfile; ' 'format: key=value',
116 )
105 117 build.add_argument('dockerfile', help='path to Dockerfile to use')
106 118 build.add_argument('tag', help='Tag to apply to created image')
107 119
108 120 docker = subparsers.add_parser('docker-path', help='Resolve path to Docker')
109 121 docker.set_defaults(func=command_docker)
110 122
111 123 args = parser.parse_args()
112 124
113 125 return args.func(args)
114 126
127
115 128 if __name__ == '__main__':
116 129 sys.exit(main())
@@ -1,204 +1,207 b''
1 1 #!/usr/bin/env python3
2 2 """Generate release notes from our commit log.
3 3
4 4 This uses the relnotes extension directives when they're available,
5 5 and falls back to our old pre-relnotes logic that used to live in the
6 6 release-tools repo.
7 7 """
8 8 import argparse
9 9 import re
10 10 import subprocess
11 11
12 12 rules = {
13 13 # keep
14 14 r"\(issue": 100,
15 15 r"\(BC\)": 100,
16 16 r"\(API\)": 100,
17 17 r"\(SEC\)": 100,
18 18 # core commands, bump up
19 19 r"(commit|files|log|pull|push|patch|status|tag|summary)(|s|es):": 20,
20 20 r"(annotate|alias|branch|bookmark|clone|graft|import|verify).*:": 20,
21 21 # extensions, bump up
22 22 r"(mq|shelve|rebase):": 20,
23 23 # newsy
24 24 r": deprecate": 20,
25 25 r": new.*(extension|flag|module)": 10,
26 26 r"( ability|command|feature|option|support)": 10,
27 27 # experimental
28 28 r"hg-experimental": 20,
29 29 r"(from|graduate).*experimental": 15,
30 30 r"(hide|mark).*experimental": -10,
31 31 # bug-like?
32 32 r"(fix|don't break|improve)": 7,
33 33 r"(not|n't|avoid|fix|prevent).*crash": 10,
34 34 r"vulnerab": 10,
35 35 # boring stuff, bump down
36 36 r"^contrib": -5,
37 37 r"debug": -5,
38 38 r"help": -5,
39 39 r"minor": -5,
40 40 r"(doc|metavar|bundle2|obsolete|obsmarker|rpm|setup|debug\S+:)": -15,
41 41 r"(check-code|check-commit|check-config|import-checker)": -20,
42 42 r"(flake8|lintian|pyflakes|pylint)": -20,
43 43 # cleanups and refactoring
44 44 r"(clean ?up|white ?space|spelling|quoting)": -20,
45 45 r"(flatten|dedent|indent|nesting|unnest)": -20,
46 46 r"(typo|hint|note|comment|TODO|FIXME)": -20,
47 47 r"(style:|convention|one-?liner)": -20,
48 48 r"(argument|absolute_import|attribute|assignment|mutable)": -15,
49 49 r"(scope|True|False)": -10,
50 50 r"(unused|useless|unnecessar|superfluous|duplicate|deprecated)": -10,
51 51 r"(redundant|pointless|confusing|uninitialized|meaningless|dead)": -10,
52 52 r": (drop|remove|delete|rip out)": -10,
53 53 r": (inherit|rename|simplify|naming|inline)": -10,
54 54 r"(correct doc|docstring|document .* method)": -20,
55 55 r"(abstract|factor|extract|prepare|split|replace| import)": -20,
56 56 r": add.*(function|method|implementation|example)": -10,
57 57 r": (move|extract) .* (to|into|from|out of)": -20,
58 58 r": implement ": -5,
59 59 r": use .* implementation": -20,
60 60 r": use .* instead of": -20,
61 61 # code
62 62 r"_": -10,
63 63 r"__": -5,
64 64 r"\(\)": -5,
65 65 r"\S\S\S+\.\S\S\S\S+": -5,
66 66 # dumb keywords
67 67 r"\S+/\S+:": -10,
68 68 r"\S+\.\S+:": -10,
69 69 # python compatibility
70 70 r"[Pp]y(|thon) ?[23]": -20,
71 71 r"pycompat": -20,
72 72 r"(coerce|convert|encode) .*to (byte|sys|)(s|str|string)": -20,
73 73 # tests
74 74 r"^test(|s|ing|runner|-\S+):": -20,
75 75 r"^(f|hghave|run-tests):": -20,
76 76 r"add.* tests?": -20,
77 77 r"(buildbot|fuzz|mock|ratchet)": -10,
78 78 # drop
79 79 r"^i18n-": -50,
80 80 r"^i18n:.*(hint|comment)": -50,
81 81 r"perf:": -50,
82 82 r"Added.*for changeset": -50,
83 83 r"^_": -50,
84 84 }
85 85
86 86 cutoff = 10
87 87 commits = []
88 88
89 89 groupings = [
90 90 (r"util|parsers|repo|ctx|context|revlog|filelog|alias|cmdutil", "core"),
91 91 (r"revset|template|ui|dirstate|hook|i18n|transaction|wire|vfs", "core"),
92 92 (r"dispatch|exchange|localrepo|streamclone|color|pager", "core"),
93 93 (r"hgweb|paper|coal|gitweb|monoblue|spartan", "hgweb"),
94 94 (r"pull|push|revert|resolve|annotate|bookmark|branch|clone", "commands"),
95 95 (r"commands|commit|config|files|graft|import|log|merge|patch", "commands"),
96 96 (r"phases|status|summary|amend|tag|help|verify", "commands"),
97 97 (r"rebase|mq|convert|eol|histedit|largefiles", "extensions"),
98 98 (r"shelve|unshelve", "extensions"),
99 99 ]
100 100
101
101 102 def wikify(desc):
102 103 desc = desc.replace("(issue", "(Bts:issue")
103 104 desc = re.sub(r"\b([0-9a-f]{12})\b", r"Cset:\1", desc)
104 105 # stop ParseError from being recognized as a (nonexistent) wiki page
105 106 desc = re.sub(r" ([A-Z][a-z]+[A-Z][a-z]+)\b", r" !\1", desc)
106 107 # prevent wiki markup of magic methods
107 108 desc = re.sub(r"\b(\S*__\S*)\b", r"`\1`", desc)
108 109 return desc
109 110
111
110 112 def main():
111 113 desc = "example: %(prog)s 4.7.2 --stoprev 4.8rc0"
112 114 ap = argparse.ArgumentParser(description=desc)
113 115 ap.add_argument(
114 116 "startrev",
115 117 metavar="REV",
116 118 type=str,
117 119 help=(
118 120 "Starting revision for the release notes. This revision "
119 121 "won't be included, but later revisions will."
120 122 ),
121 123 )
122 124 ap.add_argument(
123 125 "--stoprev",
124 126 metavar="REV",
125 127 type=str,
126 128 default="@",
127 129 help=(
128 130 "Stop revision for release notes. This revision will be included,"
129 131 " but no later revisions will. This revision needs to be "
130 132 "a descendant of startrev."
131 133 ),
132 134 )
133 135 args = ap.parse_args()
134 136 fromext = subprocess.check_output(
135 137 [
136 138 "hg",
137 139 "--config",
138 140 "extensions.releasenotes=",
139 141 "releasenotes",
140 142 "-r",
141 143 "only(%s, %s)" % (args.stoprev, args.startrev),
142 144 ]
143 145 ).decode("utf-8")
144 146 # Find all release notes from un-relnotes-flagged commits.
145 147 for entry in sorted(
146 148 subprocess.check_output(
147 149 [
148 150 "hg",
149 151 "log",
150 152 "-r",
151 153 "only(%s, %s) - merge()" % (args.stoprev, args.startrev),
152 154 "-T",
153 155 r"{desc|firstline}\n",
154 156 ]
155 157 )
156 158 .decode("utf-8")
157 159 .splitlines()
158 160 ):
159 161 desc = entry.replace("`", "'")
160 162
161 163 score = 0
162 164 for rule, val in rules.items():
163 165 if re.search(rule, desc):
164 166 score += val
165 167
166 168 if score >= cutoff:
167 169 commits.append(wikify(desc))
168 170 # Group unflagged notes.
169 171 groups = {}
170 172 bcs = []
171 173 apis = []
172 174
173 175 for d in commits:
174 176 if "(BC)" in d:
175 177 bcs.append(d)
176 178 if "(API)" in d:
177 179 apis.append(d)
178 180 for rule, g in groupings:
179 181 if re.match(rule, d):
180 182 groups.setdefault(g, []).append(d)
181 183 break
182 184 else:
183 185 groups.setdefault("unsorted", []).append(d)
184 186 print(fromext)
185 187 # print legacy release notes sections
186 188 for g in sorted(groups):
187 189 print("\n=== %s ===" % g)
188 190 for d in sorted(groups[g]):
189 191 print(" * %s" % d)
190 192
191 193 if bcs:
192 194 print("\n=== Behavior Changes ===\n")
193 195
194 196 for d in sorted(bcs):
195 197 print(" * %s" % d)
196 198
197 199 if apis:
198 200 print("\n=== Internal API Changes ===\n")
199 201
200 202 for d in sorted(apis):
201 203 print(" * %s" % d)
202 204
205
203 206 if __name__ == "__main__":
204 207 main()
@@ -1,87 +1,102 b''
1 1 #!/usr/bin/env python
2 2 from __future__ import absolute_import
3 3
4 4 import getopt
5 5 import sys
6 6
7 7 import hgdemandimport
8
8 9 hgdemandimport.enable()
9 10
10 11 from mercurial.i18n import _
11 12 from mercurial import (
12 13 context,
13 14 error,
14 15 fancyopts,
15 16 pycompat,
16 17 simplemerge,
17 18 ui as uimod,
18 19 )
19 from mercurial.utils import (
20 procutil,
21 stringutil
22 )
20 from mercurial.utils import procutil, stringutil
23 21
24 options = [(b'L', b'label', [], _(b'labels to use on conflict markers')),
25 (b'a', b'text', None, _(b'treat all files as text')),
26 (b'p', b'print', None,
27 _(b'print results instead of overwriting LOCAL')),
28 (b'', b'no-minimal', None, _(b'no effect (DEPRECATED)')),
29 (b'h', b'help', None, _(b'display help and exit')),
30 (b'q', b'quiet', None, _(b'suppress output'))]
22 options = [
23 (b'L', b'label', [], _(b'labels to use on conflict markers')),
24 (b'a', b'text', None, _(b'treat all files as text')),
25 (b'p', b'print', None, _(b'print results instead of overwriting LOCAL')),
26 (b'', b'no-minimal', None, _(b'no effect (DEPRECATED)')),
27 (b'h', b'help', None, _(b'display help and exit')),
28 (b'q', b'quiet', None, _(b'suppress output')),
29 ]
31 30
32 usage = _(b'''simplemerge [OPTS] LOCAL BASE OTHER
31 usage = _(
32 b'''simplemerge [OPTS] LOCAL BASE OTHER
33 33
34 34 Simple three-way file merge utility with a minimal feature set.
35 35
36 36 Apply to LOCAL the changes necessary to go from BASE to OTHER.
37 37
38 38 By default, LOCAL is overwritten with the results of this operation.
39 ''')
39 '''
40 )
41
40 42
41 43 class ParseError(Exception):
42 44 """Exception raised on errors in parsing the command line."""
43 45
46
44 47 def showhelp():
45 48 pycompat.stdout.write(usage)
46 49 pycompat.stdout.write(b'\noptions:\n')
47 50
48 51 out_opts = []
49 52 for shortopt, longopt, default, desc in options:
50 out_opts.append((b'%2s%s' % (shortopt and b'-%s' % shortopt,
51 longopt and b' --%s' % longopt),
52 b'%s' % desc))
53 out_opts.append(
54 (
55 b'%2s%s'
56 % (
57 shortopt and b'-%s' % shortopt,
58 longopt and b' --%s' % longopt,
59 ),
60 b'%s' % desc,
61 )
62 )
53 63 opts_len = max([len(opt[0]) for opt in out_opts])
54 64 for first, second in out_opts:
55 65 pycompat.stdout.write(b' %-*s %s\n' % (opts_len, first, second))
56 66
67
57 68 try:
58 69 for fp in (sys.stdin, pycompat.stdout, sys.stderr):
59 70 procutil.setbinary(fp)
60 71
61 72 opts = {}
62 73 try:
63 74 bargv = [a.encode('utf8') for a in sys.argv[1:]]
64 75 args = fancyopts.fancyopts(bargv, options, opts)
65 76 except getopt.GetoptError as e:
66 77 raise ParseError(e)
67 78 if opts[b'help']:
68 79 showhelp()
69 80 sys.exit(0)
70 81 if len(args) != 3:
71 raise ParseError(_(b'wrong number of arguments').decode('utf8'))
82 raise ParseError(_(b'wrong number of arguments').decode('utf8'))
72 83 local, base, other = args
73 sys.exit(simplemerge.simplemerge(uimod.ui.load(),
74 context.arbitraryfilectx(local),
75 context.arbitraryfilectx(base),
76 context.arbitraryfilectx(other),
77 **pycompat.strkwargs(opts)))
84 sys.exit(
85 simplemerge.simplemerge(
86 uimod.ui.load(),
87 context.arbitraryfilectx(local),
88 context.arbitraryfilectx(base),
89 context.arbitraryfilectx(other),
90 **pycompat.strkwargs(opts)
91 )
92 )
78 93 except ParseError as e:
79 94 e = stringutil.forcebytestr(e)
80 95 pycompat.stdout.write(b"%s: %s\n" % (sys.argv[0].encode('utf8'), e))
81 96 showhelp()
82 97 sys.exit(1)
83 98 except error.Abort as e:
84 99 pycompat.stderr.write(b"abort: %s\n" % e)
85 100 sys.exit(255)
86 101 except KeyboardInterrupt:
87 102 sys.exit(255)
@@ -1,50 +1,49 b''
1 1 #!/usr/bin/env python
2 2 # Undump a dump from dumprevlog
3 3 # $ hg init
4 4 # $ undumprevlog < repo.dump
5 5
6 6 from __future__ import absolute_import, print_function
7 7
8 8 import sys
9 9 from mercurial import (
10 10 encoding,
11 11 node,
12 12 pycompat,
13 13 revlog,
14 14 transaction,
15 15 vfs as vfsmod,
16 16 )
17 from mercurial.utils import (
18 procutil,
19 )
17 from mercurial.utils import procutil
20 18
21 19 for fp in (sys.stdin, sys.stdout, sys.stderr):
22 20 procutil.setbinary(fp)
23 21
24 22 opener = vfsmod.vfs(b'.', False)
25 tr = transaction.transaction(sys.stderr.write, opener, {b'store': opener},
26 b"undump.journal")
23 tr = transaction.transaction(
24 sys.stderr.write, opener, {b'store': opener}, b"undump.journal"
25 )
27 26 while True:
28 27 l = sys.stdin.readline()
29 28 if not l:
30 29 break
31 30 if l.startswith("file:"):
32 31 f = encoding.strtolocal(l[6:-1])
33 32 r = revlog.revlog(opener, f)
34 33 pycompat.stdout.write(b'%s\n' % f)
35 34 elif l.startswith("node:"):
36 35 n = node.bin(l[6:-1])
37 36 elif l.startswith("linkrev:"):
38 37 lr = int(l[9:-1])
39 38 elif l.startswith("parents:"):
40 39 p = l[9:-1].split()
41 40 p1 = node.bin(p[0])
42 41 p2 = node.bin(p[1])
43 42 elif l.startswith("length:"):
44 43 length = int(l[8:-1])
45 sys.stdin.readline() # start marker
44 sys.stdin.readline() # start marker
46 45 d = encoding.strtolocal(sys.stdin.read(length))
47 sys.stdin.readline() # end marker
46 sys.stdin.readline() # end marker
48 47 r.addrevision(d, tr, lr, p1, p2)
49 48
50 49 tr.close()
@@ -1,36 +1,43 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # mercurial - scalable distributed SCM
4 4 #
5 5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9 from __future__ import absolute_import
10 10
11 11 import os
12 12 import sys
13 13
14 14 libdir = '@LIBDIR@'
15 15
16 16 if libdir != '@' 'LIBDIR' '@':
17 17 if not os.path.isabs(libdir):
18 libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
19 libdir)
18 libdir = os.path.join(
19 os.path.dirname(os.path.realpath(__file__)), libdir
20 )
20 21 libdir = os.path.abspath(libdir)
21 22 sys.path.insert(0, libdir)
22 23
23 24 from hgdemandimport import tracing
25
24 26 with tracing.log('hg script'):
25 27 # enable importing on demand to reduce startup time
26 28 try:
27 29 if sys.version_info[0] < 3 or sys.version_info >= (3, 6):
28 import hgdemandimport; hgdemandimport.enable()
30 import hgdemandimport
31
32 hgdemandimport.enable()
29 33 except ImportError:
30 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
31 ' '.join(sys.path))
34 sys.stderr.write(
35 "abort: couldn't find mercurial libraries in [%s]\n"
36 % ' '.join(sys.path)
37 )
32 38 sys.stderr.write("(check your install and PYTHONPATH)\n")
33 39 sys.exit(-1)
34 40
35 41 from mercurial import dispatch
42
36 43 dispatch.run()
General Comments 0
You need to be logged in to leave comments. Login now