Show More
@@ -0,0 +1,99 b'' | |||||
|
1 | # fetch.py - pull and merge remote changes | |||
|
2 | # | |||
|
3 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from mercurial.demandload import * | |||
|
9 | from mercurial.i18n import gettext as _ | |||
|
10 | from mercurial.node import * | |||
|
11 | demandload(globals(), 'mercurial:commands,hg,node,util') | |||
|
12 | ||||
|
13 | def fetch(ui, repo, source='default', **opts): | |||
|
14 | '''Pull changes from a remote repository, merge new changes if needed. | |||
|
15 | ||||
|
16 | This finds all changes from the repository at the specified path | |||
|
17 | or URL and adds them to the local repository. | |||
|
18 | ||||
|
19 | If the pulled changes add a new head, the head is automatically | |||
|
20 | merged, and the result of the merge is committed. Otherwise, the | |||
|
21 | working directory is updated.''' | |||
|
22 | ||||
|
23 | def postincoming(other, modheads): | |||
|
24 | if modheads == 0: | |||
|
25 | return 0 | |||
|
26 | if modheads == 1: | |||
|
27 | return hg.clean(repo, repo.changelog.tip(), wlock=wlock) | |||
|
28 | newheads = repo.heads(parent) | |||
|
29 | newchildren = [n for n in repo.heads(parent) if n != parent] | |||
|
30 | newparent = parent | |||
|
31 | if newchildren: | |||
|
32 | newparent = newchildren[0] | |||
|
33 | hg.clean(repo, newparent, wlock=wlock) | |||
|
34 | newheads = [n for n in repo.heads() if n != newparent] | |||
|
35 | err = False | |||
|
36 | if newheads: | |||
|
37 | ui.status(_('merging with new head %d:%s\n') % | |||
|
38 | (repo.changelog.rev(newheads[0]), short(newheads[0]))) | |||
|
39 | err = hg.merge(repo, newheads[0], remind=False, wlock=wlock) | |||
|
40 | if not err and len(newheads) > 1: | |||
|
41 | ui.status(_('not merging with %d other new heads ' | |||
|
42 | '(use "hg heads" and "hg merge" to merge them)') % | |||
|
43 | (len(newheads) - 1)) | |||
|
44 | if not err: | |||
|
45 | mod, add, rem = repo.status(wlock=wlock)[:3] | |||
|
46 | message = (commands.logmessage(opts) or | |||
|
47 | (_('Automated merge with %s') % other.url())) | |||
|
48 | n = repo.commit(mod + add + rem, message, | |||
|
49 | opts['user'], opts['date'], lock=lock, wlock=wlock, | |||
|
50 | force_editor=opts.get('force_editor')) | |||
|
51 | ui.status(_('new changeset %d:%s merges remote changes ' | |||
|
52 | 'with local\n') % (repo.changelog.rev(n), | |||
|
53 | short(n))) | |||
|
54 | def pull(): | |||
|
55 | commands.setremoteconfig(ui, opts) | |||
|
56 | ||||
|
57 | other = hg.repository(ui, ui.expandpath(source)) | |||
|
58 | ui.status(_('pulling from %s\n') % ui.expandpath(source)) | |||
|
59 | revs = None | |||
|
60 | if opts['rev'] and not other.local(): | |||
|
61 | raise util.Abort(_("fetch -r doesn't work for remote repositories yet")) | |||
|
62 | elif opts['rev']: | |||
|
63 | revs = [other.lookup(rev) for rev in opts['rev']] | |||
|
64 | modheads = repo.pull(other, heads=revs, lock=lock) | |||
|
65 | return postincoming(other, modheads) | |||
|
66 | ||||
|
67 | parent, p2 = repo.dirstate.parents() | |||
|
68 | if parent != repo.changelog.tip(): | |||
|
69 | raise util.Abort(_('working dir not at tip ' | |||
|
70 | '(use "hg update" to check out tip)')) | |||
|
71 | if p2 != nullid: | |||
|
72 | raise util.Abort(_('outstanding uncommitted merge')) | |||
|
73 | wlock = repo.wlock() | |||
|
74 | lock = repo.lock() | |||
|
75 | try: | |||
|
76 | mod, add, rem = repo.status(wlock=wlock)[:3] | |||
|
77 | if mod or add or rem: | |||
|
78 | raise util.Abort(_('outstanding uncommitted changes')) | |||
|
79 | if len(repo.heads()) > 1: | |||
|
80 | raise util.Abort(_('multiple heads in this repository ' | |||
|
81 | '(use "hg heads" and "hg merge" to merge)')) | |||
|
82 | return pull() | |||
|
83 | finally: | |||
|
84 | lock.release() | |||
|
85 | wlock.release() | |||
|
86 | ||||
|
87 | cmdtable = { | |||
|
88 | 'fetch': | |||
|
89 | (fetch, | |||
|
90 | [('e', 'ssh', '', _('specify ssh command to use')), | |||
|
91 | ('m', 'message', '', _('use <text> as commit message')), | |||
|
92 | ('l', 'logfile', '', _('read the commit message from <file>')), | |||
|
93 | ('d', 'date', '', _('record datecode as commit date')), | |||
|
94 | ('u', 'user', '', _('record user as commiter')), | |||
|
95 | ('r', 'rev', [], _('a specific revision you would like to pull')), | |||
|
96 | ('f', 'force-editor', None, _('edit commit message')), | |||
|
97 | ('', 'remotecmd', '', _('hg command to run on the remote side'))], | |||
|
98 | 'hg fetch [SOURCE]'), | |||
|
99 | } |
@@ -0,0 +1,111 b'' | |||||
|
1 | # commands.py - command processing for mercurial | |||
|
2 | # | |||
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from demandload import demandload | |||
|
9 | from node import * | |||
|
10 | from i18n import gettext as _ | |||
|
11 | demandload(globals(), 'util') | |||
|
12 | demandload(globals(), 'os sys') | |||
|
13 | ||||
|
14 | def make_filename(repo, pat, node, | |||
|
15 | total=None, seqno=None, revwidth=None, pathname=None): | |||
|
16 | node_expander = { | |||
|
17 | 'H': lambda: hex(node), | |||
|
18 | 'R': lambda: str(repo.changelog.rev(node)), | |||
|
19 | 'h': lambda: short(node), | |||
|
20 | } | |||
|
21 | expander = { | |||
|
22 | '%': lambda: '%', | |||
|
23 | 'b': lambda: os.path.basename(repo.root), | |||
|
24 | } | |||
|
25 | ||||
|
26 | try: | |||
|
27 | if node: | |||
|
28 | expander.update(node_expander) | |||
|
29 | if node and revwidth is not None: | |||
|
30 | expander['r'] = (lambda: | |||
|
31 | str(repo.changelog.rev(node)).zfill(revwidth)) | |||
|
32 | if total is not None: | |||
|
33 | expander['N'] = lambda: str(total) | |||
|
34 | if seqno is not None: | |||
|
35 | expander['n'] = lambda: str(seqno) | |||
|
36 | if total is not None and seqno is not None: | |||
|
37 | expander['n'] = lambda:str(seqno).zfill(len(str(total))) | |||
|
38 | if pathname is not None: | |||
|
39 | expander['s'] = lambda: os.path.basename(pathname) | |||
|
40 | expander['d'] = lambda: os.path.dirname(pathname) or '.' | |||
|
41 | expander['p'] = lambda: pathname | |||
|
42 | ||||
|
43 | newname = [] | |||
|
44 | patlen = len(pat) | |||
|
45 | i = 0 | |||
|
46 | while i < patlen: | |||
|
47 | c = pat[i] | |||
|
48 | if c == '%': | |||
|
49 | i += 1 | |||
|
50 | c = pat[i] | |||
|
51 | c = expander[c]() | |||
|
52 | newname.append(c) | |||
|
53 | i += 1 | |||
|
54 | return ''.join(newname) | |||
|
55 | except KeyError, inst: | |||
|
56 | raise util.Abort(_("invalid format spec '%%%s' in output file name"), | |||
|
57 | inst.args[0]) | |||
|
58 | ||||
|
59 | def make_file(repo, pat, node=None, | |||
|
60 | total=None, seqno=None, revwidth=None, mode='wb', pathname=None): | |||
|
61 | if not pat or pat == '-': | |||
|
62 | return 'w' in mode and sys.stdout or sys.stdin | |||
|
63 | if hasattr(pat, 'write') and 'w' in mode: | |||
|
64 | return pat | |||
|
65 | if hasattr(pat, 'read') and 'r' in mode: | |||
|
66 | return pat | |||
|
67 | return open(make_filename(repo, pat, node, total, seqno, revwidth, | |||
|
68 | pathname), | |||
|
69 | mode) | |||
|
70 | ||||
|
71 | def matchpats(repo, pats=[], opts={}, head=''): | |||
|
72 | cwd = repo.getcwd() | |||
|
73 | if not pats and cwd: | |||
|
74 | opts['include'] = [os.path.join(cwd, i) | |||
|
75 | for i in opts.get('include', [])] | |||
|
76 | opts['exclude'] = [os.path.join(cwd, x) | |||
|
77 | for x in opts.get('exclude', [])] | |||
|
78 | cwd = '' | |||
|
79 | return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), | |||
|
80 | opts.get('exclude'), head) | |||
|
81 | ||||
|
82 | def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None): | |||
|
83 | files, matchfn, anypats = matchpats(repo, pats, opts, head) | |||
|
84 | exact = dict(zip(files, files)) | |||
|
85 | def walk(): | |||
|
86 | for src, fn in repo.walk(node=node, files=files, match=matchfn, | |||
|
87 | badmatch=badmatch): | |||
|
88 | yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact | |||
|
89 | return files, matchfn, walk() | |||
|
90 | ||||
|
91 | def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None): | |||
|
92 | files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) | |||
|
93 | for r in results: | |||
|
94 | yield r | |||
|
95 | ||||
|
96 | def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None): | |||
|
97 | if dry_run is None: | |||
|
98 | dry_run = opts.get('dry_run') | |||
|
99 | add, remove = [], [] | |||
|
100 | for src, abs, rel, exact in walk(repo, pats, opts): | |||
|
101 | if src == 'f' and repo.dirstate.state(abs) == '?': | |||
|
102 | add.append(abs) | |||
|
103 | if repo.ui.verbose or not exact: | |||
|
104 | repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) | |||
|
105 | if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): | |||
|
106 | remove.append(abs) | |||
|
107 | if repo.ui.verbose or not exact: | |||
|
108 | repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) | |||
|
109 | if not dry_run: | |||
|
110 | repo.add(add, wlock=wlock) | |||
|
111 | repo.remove(remove, wlock=wlock) |
@@ -0,0 +1,68 b'' | |||||
|
1 | # mail.py - mail sending bits for mercurial | |||
|
2 | # | |||
|
3 | # Copyright 2006 Matt Mackall <mpm@selenic.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from i18n import gettext as _ | |||
|
9 | from demandload import * | |||
|
10 | demandload(globals(), "os re smtplib templater util") | |||
|
11 | ||||
|
12 | def _smtp(ui): | |||
|
13 | '''send mail using smtp.''' | |||
|
14 | ||||
|
15 | local_hostname = ui.config('smtp', 'local_hostname') | |||
|
16 | s = smtplib.SMTP(local_hostname=local_hostname) | |||
|
17 | mailhost = ui.config('smtp', 'host') | |||
|
18 | if not mailhost: | |||
|
19 | raise util.Abort(_('no [smtp]host in hgrc - cannot send mail')) | |||
|
20 | mailport = int(ui.config('smtp', 'port', 25)) | |||
|
21 | self.note(_('sending mail: smtp host %s, port %s\n') % | |||
|
22 | (mailhost, mailport)) | |||
|
23 | s.connect(host=mailhost, port=mailport) | |||
|
24 | if ui.configbool('smtp', 'tls'): | |||
|
25 | ui.note(_('(using tls)\n')) | |||
|
26 | s.ehlo() | |||
|
27 | s.starttls() | |||
|
28 | s.ehlo() | |||
|
29 | username = ui.config('smtp', 'username') | |||
|
30 | password = ui.config('smtp', 'password') | |||
|
31 | if username and password: | |||
|
32 | ui.note(_('(authenticating to mail server as %s)\n') % | |||
|
33 | (username)) | |||
|
34 | s.login(username, password) | |||
|
35 | return s | |||
|
36 | ||||
|
37 | class _sendmail(object): | |||
|
38 | '''send mail using sendmail.''' | |||
|
39 | ||||
|
40 | def __init__(self, ui, program): | |||
|
41 | self.ui = ui | |||
|
42 | self.program = program | |||
|
43 | ||||
|
44 | def sendmail(self, sender, recipients, msg): | |||
|
45 | cmdline = '%s -f %s %s' % ( | |||
|
46 | self.program, templater.email(sender), | |||
|
47 | ' '.join(map(templater.email, recipients))) | |||
|
48 | self.ui.note(_('sending mail: %s\n') % cmdline) | |||
|
49 | fp = os.popen(cmdline, 'w') | |||
|
50 | fp.write(msg) | |||
|
51 | ret = fp.close() | |||
|
52 | if ret: | |||
|
53 | raise util.Abort('%s %s' % ( | |||
|
54 | os.path.basename(self.program.split(None, 1)[0]), | |||
|
55 | util.explain_exit(ret)[0])) | |||
|
56 | ||||
|
57 | def connect(ui): | |||
|
58 | '''make a mail connection. object returned has one method, sendmail. | |||
|
59 | call as sendmail(sender, list-of-recipients, msg).''' | |||
|
60 | ||||
|
61 | method = ui.config('email', 'method', 'smtp') | |||
|
62 | if method == 'smtp': | |||
|
63 | return _smtp(ui) | |||
|
64 | ||||
|
65 | return _sendmail(ui, method) | |||
|
66 | ||||
|
67 | def sendmail(ui, sender, recipients, msg): | |||
|
68 | return connect(ui).sendmail(sender, recipients, msg) |
@@ -0,0 +1,339 b'' | |||||
|
1 | # merge.py - directory-level update/merge handling for Mercurial | |||
|
2 | # | |||
|
3 | # Copyright 2006 Matt Mackall <mpm@selenic.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from node import * | |||
|
9 | from i18n import gettext as _ | |||
|
10 | from demandload import * | |||
|
11 | demandload(globals(), "util os tempfile") | |||
|
12 | ||||
|
13 | def fmerge(f, local, other, ancestor): | |||
|
14 | """merge executable flags""" | |||
|
15 | a, b, c = ancestor.execf(f), local.execf(f), other.execf(f) | |||
|
16 | return ((a^b) | (a^c)) ^ a | |||
|
17 | ||||
|
18 | def merge3(repo, fn, my, other, p1, p2): | |||
|
19 | """perform a 3-way merge in the working directory""" | |||
|
20 | ||||
|
21 | def temp(prefix, node): | |||
|
22 | pre = "%s~%s." % (os.path.basename(fn), prefix) | |||
|
23 | (fd, name) = tempfile.mkstemp(prefix=pre) | |||
|
24 | f = os.fdopen(fd, "wb") | |||
|
25 | repo.wwrite(fn, fl.read(node), f) | |||
|
26 | f.close() | |||
|
27 | return name | |||
|
28 | ||||
|
29 | fl = repo.file(fn) | |||
|
30 | base = fl.ancestor(my, other) | |||
|
31 | a = repo.wjoin(fn) | |||
|
32 | b = temp("base", base) | |||
|
33 | c = temp("other", other) | |||
|
34 | ||||
|
35 | repo.ui.note(_("resolving %s\n") % fn) | |||
|
36 | repo.ui.debug(_("file %s: my %s other %s ancestor %s\n") % | |||
|
37 | (fn, short(my), short(other), short(base))) | |||
|
38 | ||||
|
39 | cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge") | |||
|
40 | or "hgmerge") | |||
|
41 | r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root, | |||
|
42 | environ={'HG_FILE': fn, | |||
|
43 | 'HG_MY_NODE': p1, | |||
|
44 | 'HG_OTHER_NODE': p2, | |||
|
45 | 'HG_FILE_MY_NODE': hex(my), | |||
|
46 | 'HG_FILE_OTHER_NODE': hex(other), | |||
|
47 | 'HG_FILE_BASE_NODE': hex(base)}) | |||
|
48 | if r: | |||
|
49 | repo.ui.warn(_("merging %s failed!\n") % fn) | |||
|
50 | ||||
|
51 | os.unlink(b) | |||
|
52 | os.unlink(c) | |||
|
53 | return r | |||
|
54 | ||||
|
55 | def update(repo, node, branchmerge=False, force=False, partial=None, | |||
|
56 | wlock=None, show_stats=True, remind=True): | |||
|
57 | ||||
|
58 | overwrite = force and not branchmerge | |||
|
59 | forcemerge = force and branchmerge | |||
|
60 | ||||
|
61 | if not wlock: | |||
|
62 | wlock = repo.wlock() | |||
|
63 | ||||
|
64 | ### check phase | |||
|
65 | ||||
|
66 | pl = repo.dirstate.parents() | |||
|
67 | if not overwrite and pl[1] != nullid: | |||
|
68 | raise util.Abort(_("outstanding uncommitted merges")) | |||
|
69 | ||||
|
70 | p1, p2 = pl[0], node | |||
|
71 | pa = repo.changelog.ancestor(p1, p2) | |||
|
72 | ||||
|
73 | # is there a linear path from p1 to p2? | |||
|
74 | linear_path = (pa == p1 or pa == p2) | |||
|
75 | if branchmerge and linear_path: | |||
|
76 | raise util.Abort(_("there is nothing to merge, just use " | |||
|
77 | "'hg update' or look at 'hg heads'")) | |||
|
78 | ||||
|
79 | if not overwrite and not linear_path and not branchmerge: | |||
|
80 | raise util.Abort(_("update spans branches, use 'hg merge' " | |||
|
81 | "or 'hg update -C' to lose changes")) | |||
|
82 | ||||
|
83 | modified, added, removed, deleted, unknown = repo.status()[:5] | |||
|
84 | if branchmerge and not forcemerge: | |||
|
85 | if modified or added or removed: | |||
|
86 | raise util.Abort(_("outstanding uncommitted changes")) | |||
|
87 | ||||
|
88 | m1n = repo.changelog.read(p1)[0] | |||
|
89 | m2n = repo.changelog.read(p2)[0] | |||
|
90 | man = repo.manifest.ancestor(m1n, m2n) | |||
|
91 | m1 = repo.manifest.read(m1n) | |||
|
92 | m2 = repo.manifest.read(m2n).copy() | |||
|
93 | ma = repo.manifest.read(man) | |||
|
94 | ||||
|
95 | if not force: | |||
|
96 | for f in unknown: | |||
|
97 | if f in m2: | |||
|
98 | if repo.file(f).cmp(m2[f], repo.wread(f)): | |||
|
99 | raise util.Abort(_("'%s' already exists in the working" | |||
|
100 | " dir and differs from remote") % f) | |||
|
101 | ||||
|
102 | # resolve the manifest to determine which files | |||
|
103 | # we care about merging | |||
|
104 | repo.ui.note(_("resolving manifests\n")) | |||
|
105 | repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") % | |||
|
106 | (overwrite, branchmerge, bool(partial), linear_path)) | |||
|
107 | repo.ui.debug(_(" ancestor %s local %s remote %s\n") % | |||
|
108 | (short(man), short(m1n), short(m2n))) | |||
|
109 | ||||
|
110 | merge = {} | |||
|
111 | get = {} | |||
|
112 | remove = [] | |||
|
113 | forget = [] | |||
|
114 | ||||
|
115 | # construct a working dir manifest | |||
|
116 | mw = m1.copy() | |||
|
117 | umap = dict.fromkeys(unknown) | |||
|
118 | ||||
|
119 | for f in added + modified + unknown: | |||
|
120 | mw[f] = "" | |||
|
121 | # is the wfile new and matches m2? | |||
|
122 | if (f not in m1 and f in m2 and | |||
|
123 | not repo.file(f).cmp(m2[f], repo.wread(f))): | |||
|
124 | mw[f] = m2[f] | |||
|
125 | ||||
|
126 | mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f))) | |||
|
127 | ||||
|
128 | for f in deleted + removed: | |||
|
129 | if f in mw: | |||
|
130 | del mw[f] | |||
|
131 | ||||
|
132 | # If we're jumping between revisions (as opposed to merging), | |||
|
133 | # and if neither the working directory nor the target rev has | |||
|
134 | # the file, then we need to remove it from the dirstate, to | |||
|
135 | # prevent the dirstate from listing the file when it is no | |||
|
136 | # longer in the manifest. | |||
|
137 | if linear_path and f not in m2: | |||
|
138 | forget.append(f) | |||
|
139 | ||||
|
140 | # Compare manifests | |||
|
141 | for f, n in mw.iteritems(): | |||
|
142 | if partial and not partial(f): | |||
|
143 | continue | |||
|
144 | if f in m2: | |||
|
145 | s = 0 | |||
|
146 | ||||
|
147 | # are files different? | |||
|
148 | if n != m2[f]: | |||
|
149 | a = ma.get(f, nullid) | |||
|
150 | # are both different from the ancestor? | |||
|
151 | if n != a and m2[f] != a: | |||
|
152 | repo.ui.debug(_(" %s versions differ, resolve\n") % f) | |||
|
153 | merge[f] = (fmerge(f, mw, m2, ma), m1.get(f, nullid), m2[f]) | |||
|
154 | s = 1 | |||
|
155 | # are we clobbering? | |||
|
156 | # is remote's version newer? | |||
|
157 | # or are we going back in time? | |||
|
158 | elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]): | |||
|
159 | repo.ui.debug(_(" remote %s is newer, get\n") % f) | |||
|
160 | get[f] = (m2.execf(f), m2[f]) | |||
|
161 | s = 1 | |||
|
162 | elif f in umap or f in added: | |||
|
163 | # this unknown file is the same as the checkout | |||
|
164 | # we need to reset the dirstate if the file was added | |||
|
165 | get[f] = (m2.execf(f), m2[f]) | |||
|
166 | ||||
|
167 | if not s and mw.execf(f) != m2.execf(f): | |||
|
168 | if overwrite: | |||
|
169 | repo.ui.debug(_(" updating permissions for %s\n") % f) | |||
|
170 | util.set_exec(repo.wjoin(f), m2.execf(f)) | |||
|
171 | else: | |||
|
172 | if fmerge(f, mw, m2, ma) != mw.execf(f): | |||
|
173 | repo.ui.debug(_(" updating permissions for %s\n") | |||
|
174 | % f) | |||
|
175 | util.set_exec(repo.wjoin(f), mode) | |||
|
176 | del m2[f] | |||
|
177 | elif f in ma: | |||
|
178 | if n != ma[f]: | |||
|
179 | r = _("d") | |||
|
180 | if not overwrite and (linear_path or branchmerge): | |||
|
181 | r = repo.ui.prompt( | |||
|
182 | (_(" local changed %s which remote deleted\n") % f) + | |||
|
183 | _("(k)eep or (d)elete?"), _("[kd]"), _("k")) | |||
|
184 | if r == _("d"): | |||
|
185 | remove.append(f) | |||
|
186 | else: | |||
|
187 | repo.ui.debug(_("other deleted %s\n") % f) | |||
|
188 | remove.append(f) # other deleted it | |||
|
189 | else: | |||
|
190 | # file is created on branch or in working directory | |||
|
191 | if overwrite and f not in umap: | |||
|
192 | repo.ui.debug(_("remote deleted %s, clobbering\n") % f) | |||
|
193 | remove.append(f) | |||
|
194 | elif n == m1.get(f, nullid): # same as parent | |||
|
195 | if p2 == pa: # going backwards? | |||
|
196 | repo.ui.debug(_("remote deleted %s\n") % f) | |||
|
197 | remove.append(f) | |||
|
198 | else: | |||
|
199 | repo.ui.debug(_("local modified %s, keeping\n") % f) | |||
|
200 | else: | |||
|
201 | repo.ui.debug(_("working dir created %s, keeping\n") % f) | |||
|
202 | ||||
|
203 | for f, n in m2.iteritems(): | |||
|
204 | if partial and not partial(f): | |||
|
205 | continue | |||
|
206 | if f[0] == "/": | |||
|
207 | continue | |||
|
208 | if f in ma and n != ma[f]: | |||
|
209 | r = _("k") | |||
|
210 | if not overwrite and (linear_path or branchmerge): | |||
|
211 | r = repo.ui.prompt( | |||
|
212 | (_("remote changed %s which local deleted\n") % f) + | |||
|
213 | _("(k)eep or (d)elete?"), _("[kd]"), _("k")) | |||
|
214 | if r == _("k"): | |||
|
215 | get[f] = (m2.execf(f), n) | |||
|
216 | elif f not in ma: | |||
|
217 | repo.ui.debug(_("remote created %s\n") % f) | |||
|
218 | get[f] = (m2.execf(f), n) | |||
|
219 | else: | |||
|
220 | if overwrite or p2 == pa: # going backwards? | |||
|
221 | repo.ui.debug(_("local deleted %s, recreating\n") % f) | |||
|
222 | get[f] = (m2.execf(f), n) | |||
|
223 | else: | |||
|
224 | repo.ui.debug(_("local deleted %s\n") % f) | |||
|
225 | ||||
|
226 | del mw, m1, m2, ma | |||
|
227 | ||||
|
228 | ### apply phase | |||
|
229 | ||||
|
230 | if overwrite: | |||
|
231 | for f in merge: | |||
|
232 | get[f] = merge[f][:2] | |||
|
233 | merge = {} | |||
|
234 | ||||
|
235 | if linear_path or overwrite: | |||
|
236 | # we don't need to do any magic, just jump to the new rev | |||
|
237 | p1, p2 = p2, nullid | |||
|
238 | ||||
|
239 | xp1 = hex(p1) | |||
|
240 | xp2 = hex(p2) | |||
|
241 | if p2 == nullid: xxp2 = '' | |||
|
242 | else: xxp2 = xp2 | |||
|
243 | ||||
|
244 | repo.hook('preupdate', throw=True, parent1=xp1, parent2=xxp2) | |||
|
245 | ||||
|
246 | # get the files we don't need to change | |||
|
247 | files = get.keys() | |||
|
248 | files.sort() | |||
|
249 | for f in files: | |||
|
250 | flag, node = get[f] | |||
|
251 | if f[0] == "/": | |||
|
252 | continue | |||
|
253 | repo.ui.note(_("getting %s\n") % f) | |||
|
254 | t = repo.file(f).read(node) | |||
|
255 | repo.wwrite(f, t) | |||
|
256 | util.set_exec(repo.wjoin(f), flag) | |||
|
257 | ||||
|
258 | # merge the tricky bits | |||
|
259 | unresolved = [] | |||
|
260 | files = merge.keys() | |||
|
261 | files.sort() | |||
|
262 | for f in files: | |||
|
263 | repo.ui.status(_("merging %s\n") % f) | |||
|
264 | flag, my, other = merge[f] | |||
|
265 | ret = merge3(repo, f, my, other, xp1, xp2) | |||
|
266 | if ret: | |||
|
267 | unresolved.append(f) | |||
|
268 | util.set_exec(repo.wjoin(f), flag) | |||
|
269 | ||||
|
270 | remove.sort() | |||
|
271 | for f in remove: | |||
|
272 | repo.ui.note(_("removing %s\n") % f) | |||
|
273 | util.audit_path(f) | |||
|
274 | try: | |||
|
275 | util.unlink(repo.wjoin(f)) | |||
|
276 | except OSError, inst: | |||
|
277 | if inst.errno != errno.ENOENT: | |||
|
278 | repo.ui.warn(_("update failed to remove %s: %s!\n") % | |||
|
279 | (f, inst.strerror)) | |||
|
280 | ||||
|
281 | # update dirstate | |||
|
282 | if not partial: | |||
|
283 | repo.dirstate.setparents(p1, p2) | |||
|
284 | repo.dirstate.forget(forget) | |||
|
285 | if branchmerge: | |||
|
286 | repo.dirstate.update(remove, 'r') | |||
|
287 | else: | |||
|
288 | repo.dirstate.forget(remove) | |||
|
289 | ||||
|
290 | files = get.keys() | |||
|
291 | files.sort() | |||
|
292 | for f in files: | |||
|
293 | if branchmerge: | |||
|
294 | repo.dirstate.update([f], 'n', st_mtime=-1) | |||
|
295 | else: | |||
|
296 | repo.dirstate.update([f], 'n') | |||
|
297 | ||||
|
298 | files = merge.keys() | |||
|
299 | files.sort() | |||
|
300 | for f in files: | |||
|
301 | if branchmerge: | |||
|
302 | # We've done a branch merge, mark this file as merged | |||
|
303 | # so that we properly record the merger later | |||
|
304 | repo.dirstate.update([f], 'm') | |||
|
305 | else: | |||
|
306 | # We've update-merged a locally modified file, so | |||
|
307 | # we set the dirstate to emulate a normal checkout | |||
|
308 | # of that file some time in the past. Thus our | |||
|
309 | # merge will appear as a normal local file | |||
|
310 | # modification. | |||
|
311 | fl = repo.file(f) | |||
|
312 | f_len = fl.size(fl.rev(other)) | |||
|
313 | repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1) | |||
|
314 | ||||
|
315 | if show_stats: | |||
|
316 | stats = ((len(get), _("updated")), | |||
|
317 | (len(merge) - len(unresolved), _("merged")), | |||
|
318 | (len(remove), _("removed")), | |||
|
319 | (len(unresolved), _("unresolved"))) | |||
|
320 | note = ", ".join([_("%d files %s") % s for s in stats]) | |||
|
321 | repo.ui.status("%s\n" % note) | |||
|
322 | if not partial: | |||
|
323 | if branchmerge: | |||
|
324 | if unresolved: | |||
|
325 | repo.ui.status(_("There are unresolved merges," | |||
|
326 | " you can redo the full merge using:\n" | |||
|
327 | " hg update -C %s\n" | |||
|
328 | " hg merge %s\n" | |||
|
329 | % (repo.changelog.rev(p1), | |||
|
330 | repo.changelog.rev(p2)))) | |||
|
331 | elif remind: | |||
|
332 | repo.ui.status(_("(branch merge, don't forget to commit)\n")) | |||
|
333 | elif unresolved: | |||
|
334 | repo.ui.status(_("There are unresolved merges with" | |||
|
335 | " locally modified files.\n")) | |||
|
336 | ||||
|
337 | repo.hook('update', parent1=xp1, parent2=xxp2, error=len(unresolved)) | |||
|
338 | return len(unresolved) | |||
|
339 |
This diff has been collapsed as it changes many lines, (539 lines changed) Show them Hide them | |||||
@@ -0,0 +1,539 b'' | |||||
|
1 | # patch.py - patch file parsing routines | |||
|
2 | # | |||
|
3 | # Copyright 2006 Brendan Cully <brendan@kublai.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from demandload import demandload | |||
|
9 | from i18n import gettext as _ | |||
|
10 | from node import * | |||
|
11 | demandload(globals(), "cmdutil mdiff util") | |||
|
12 | demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile") | |||
|
13 | ||||
|
14 | # helper functions | |||
|
15 | ||||
|
16 | def copyfile(src, dst, basedir=None): | |||
|
17 | if not basedir: | |||
|
18 | basedir = os.getcwd() | |||
|
19 | ||||
|
20 | abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)] | |||
|
21 | if os.path.exists(absdst): | |||
|
22 | raise util.Abort(_("cannot create %s: destination already exists") % | |||
|
23 | dst) | |||
|
24 | ||||
|
25 | targetdir = os.path.dirname(absdst) | |||
|
26 | if not os.path.isdir(targetdir): | |||
|
27 | os.makedirs(targetdir) | |||
|
28 | try: | |||
|
29 | shutil.copyfile(abssrc, absdst) | |||
|
30 | shutil.copymode(abssrc, absdst) | |||
|
31 | except shutil.Error, inst: | |||
|
32 | raise util.Abort(str(inst)) | |||
|
33 | ||||
|
34 | # public functions | |||
|
35 | ||||
|
36 | def extract(ui, fileobj): | |||
|
37 | '''extract patch from data read from fileobj. | |||
|
38 | ||||
|
39 | patch can be normal patch or contained in email message. | |||
|
40 | ||||
|
41 | return tuple (filename, message, user, date). any item in returned | |||
|
42 | tuple can be None. if filename is None, fileobj did not contain | |||
|
43 | patch. caller must unlink filename when done.''' | |||
|
44 | ||||
|
45 | # attempt to detect the start of a patch | |||
|
46 | # (this heuristic is borrowed from quilt) | |||
|
47 | diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + | |||
|
48 | 'retrieving revision [0-9]+(\.[0-9]+)*$|' + | |||
|
49 | '(---|\*\*\*)[ \t])', re.MULTILINE) | |||
|
50 | ||||
|
51 | fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') | |||
|
52 | tmpfp = os.fdopen(fd, 'w') | |||
|
53 | try: | |||
|
54 | hgpatch = False | |||
|
55 | ||||
|
56 | msg = email.Parser.Parser().parse(fileobj) | |||
|
57 | ||||
|
58 | message = msg['Subject'] | |||
|
59 | user = msg['From'] | |||
|
60 | # should try to parse msg['Date'] | |||
|
61 | date = None | |||
|
62 | ||||
|
63 | if message: | |||
|
64 | message = message.replace('\n\t', ' ') | |||
|
65 | ui.debug('Subject: %s\n' % message) | |||
|
66 | if user: | |||
|
67 | ui.debug('From: %s\n' % user) | |||
|
68 | diffs_seen = 0 | |||
|
69 | ok_types = ('text/plain', 'text/x-diff', 'text/x-patch') | |||
|
70 | ||||
|
71 | for part in msg.walk(): | |||
|
72 | content_type = part.get_content_type() | |||
|
73 | ui.debug('Content-Type: %s\n' % content_type) | |||
|
74 | if content_type not in ok_types: | |||
|
75 | continue | |||
|
76 | payload = part.get_payload(decode=True) | |||
|
77 | m = diffre.search(payload) | |||
|
78 | if m: | |||
|
79 | ui.debug(_('found patch at byte %d\n') % m.start(0)) | |||
|
80 | diffs_seen += 1 | |||
|
81 | cfp = cStringIO.StringIO() | |||
|
82 | if message: | |||
|
83 | cfp.write(message) | |||
|
84 | cfp.write('\n') | |||
|
85 | for line in payload[:m.start(0)].splitlines(): | |||
|
86 | if line.startswith('# HG changeset patch'): | |||
|
87 | ui.debug(_('patch generated by hg export\n')) | |||
|
88 | hgpatch = True | |||
|
89 | # drop earlier commit message content | |||
|
90 | cfp.seek(0) | |||
|
91 | cfp.truncate() | |||
|
92 | elif hgpatch: | |||
|
93 | if line.startswith('# User '): | |||
|
94 | user = line[7:] | |||
|
95 | ui.debug('From: %s\n' % user) | |||
|
96 | elif line.startswith("# Date "): | |||
|
97 | date = line[7:] | |||
|
98 | if not line.startswith('# '): | |||
|
99 | cfp.write(line) | |||
|
100 | cfp.write('\n') | |||
|
101 | message = cfp.getvalue() | |||
|
102 | if tmpfp: | |||
|
103 | tmpfp.write(payload) | |||
|
104 | if not payload.endswith('\n'): | |||
|
105 | tmpfp.write('\n') | |||
|
106 | elif not diffs_seen and message and content_type == 'text/plain': | |||
|
107 | message += '\n' + payload | |||
|
108 | except: | |||
|
109 | tmpfp.close() | |||
|
110 | os.unlink(tmpname) | |||
|
111 | raise | |||
|
112 | ||||
|
113 | tmpfp.close() | |||
|
114 | if not diffs_seen: | |||
|
115 | os.unlink(tmpname) | |||
|
116 | return None, message, user, date | |||
|
117 | return tmpname, message, user, date | |||
|
118 | ||||
|
119 | def readgitpatch(patchname): | |||
|
120 | """extract git-style metadata about patches from <patchname>""" | |||
|
121 | class gitpatch: | |||
|
122 | "op is one of ADD, DELETE, RENAME, MODIFY or COPY" | |||
|
123 | def __init__(self, path): | |||
|
124 | self.path = path | |||
|
125 | self.oldpath = None | |||
|
126 | self.mode = None | |||
|
127 | self.op = 'MODIFY' | |||
|
128 | self.copymod = False | |||
|
129 | self.lineno = 0 | |||
|
130 | ||||
|
131 | # Filter patch for git information | |||
|
132 | gitre = re.compile('diff --git a/(.*) b/(.*)') | |||
|
133 | pf = file(patchname) | |||
|
134 | gp = None | |||
|
135 | gitpatches = [] | |||
|
136 | # Can have a git patch with only metadata, causing patch to complain | |||
|
137 | dopatch = False | |||
|
138 | ||||
|
139 | lineno = 0 | |||
|
140 | for line in pf: | |||
|
141 | lineno += 1 | |||
|
142 | if line.startswith('diff --git'): | |||
|
143 | m = gitre.match(line) | |||
|
144 | if m: | |||
|
145 | if gp: | |||
|
146 | gitpatches.append(gp) | |||
|
147 | src, dst = m.group(1,2) | |||
|
148 | gp = gitpatch(dst) | |||
|
149 | gp.lineno = lineno | |||
|
150 | elif gp: | |||
|
151 | if line.startswith('--- '): | |||
|
152 | if gp.op in ('COPY', 'RENAME'): | |||
|
153 | gp.copymod = True | |||
|
154 | dopatch = 'filter' | |||
|
155 | gitpatches.append(gp) | |||
|
156 | gp = None | |||
|
157 | if not dopatch: | |||
|
158 | dopatch = True | |||
|
159 | continue | |||
|
160 | if line.startswith('rename from '): | |||
|
161 | gp.op = 'RENAME' | |||
|
162 | gp.oldpath = line[12:].rstrip() | |||
|
163 | elif line.startswith('rename to '): | |||
|
164 | gp.path = line[10:].rstrip() | |||
|
165 | elif line.startswith('copy from '): | |||
|
166 | gp.op = 'COPY' | |||
|
167 | gp.oldpath = line[10:].rstrip() | |||
|
168 | elif line.startswith('copy to '): | |||
|
169 | gp.path = line[8:].rstrip() | |||
|
170 | elif line.startswith('deleted file'): | |||
|
171 | gp.op = 'DELETE' | |||
|
172 | elif line.startswith('new file mode '): | |||
|
173 | gp.op = 'ADD' | |||
|
174 | gp.mode = int(line.rstrip()[-3:], 8) | |||
|
175 | elif line.startswith('new mode '): | |||
|
176 | gp.mode = int(line.rstrip()[-3:], 8) | |||
|
177 | if gp: | |||
|
178 | gitpatches.append(gp) | |||
|
179 | ||||
|
180 | if not gitpatches: | |||
|
181 | dopatch = True | |||
|
182 | ||||
|
183 | return (dopatch, gitpatches) | |||
|
184 | ||||
|
185 | def dogitpatch(patchname, gitpatches): | |||
|
186 | """Preprocess git patch so that vanilla patch can handle it""" | |||
|
187 | pf = file(patchname) | |||
|
188 | pfline = 1 | |||
|
189 | ||||
|
190 | fd, patchname = tempfile.mkstemp(prefix='hg-patch-') | |||
|
191 | tmpfp = os.fdopen(fd, 'w') | |||
|
192 | ||||
|
193 | try: | |||
|
194 | for i in range(len(gitpatches)): | |||
|
195 | p = gitpatches[i] | |||
|
196 | if not p.copymod: | |||
|
197 | continue | |||
|
198 | ||||
|
199 | copyfile(p.oldpath, p.path) | |||
|
200 | ||||
|
201 | # rewrite patch hunk | |||
|
202 | while pfline < p.lineno: | |||
|
203 | tmpfp.write(pf.readline()) | |||
|
204 | pfline += 1 | |||
|
205 | tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path)) | |||
|
206 | line = pf.readline() | |||
|
207 | pfline += 1 | |||
|
208 | while not line.startswith('--- a/'): | |||
|
209 | tmpfp.write(line) | |||
|
210 | line = pf.readline() | |||
|
211 | pfline += 1 | |||
|
212 | tmpfp.write('--- a/%s\n' % p.path) | |||
|
213 | ||||
|
214 | line = pf.readline() | |||
|
215 | while line: | |||
|
216 | tmpfp.write(line) | |||
|
217 | line = pf.readline() | |||
|
218 | except: | |||
|
219 | tmpfp.close() | |||
|
220 | os.unlink(patchname) | |||
|
221 | raise | |||
|
222 | ||||
|
223 | tmpfp.close() | |||
|
224 | return patchname | |||
|
225 | ||||
|
226 | def patch(patchname, ui, strip=1, cwd=None): | |||
|
227 | """apply the patch <patchname> to the working directory. | |||
|
228 | a list of patched files is returned""" | |||
|
229 | ||||
|
230 | (dopatch, gitpatches) = readgitpatch(patchname) | |||
|
231 | ||||
|
232 | files = {} | |||
|
233 | fuzz = False | |||
|
234 | if dopatch: | |||
|
235 | if dopatch == 'filter': | |||
|
236 | patchname = dogitpatch(patchname, gitpatches) | |||
|
237 | patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') | |||
|
238 | args = [] | |||
|
239 | if cwd: | |||
|
240 | args.append('-d %s' % util.shellquote(cwd)) | |||
|
241 | fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, | |||
|
242 | util.shellquote(patchname))) | |||
|
243 | ||||
|
244 | if dopatch == 'filter': | |||
|
245 | False and os.unlink(patchname) | |||
|
246 | ||||
|
247 | for line in fp: | |||
|
248 | line = line.rstrip() | |||
|
249 | ui.note(line + '\n') | |||
|
250 | if line.startswith('patching file '): | |||
|
251 | pf = util.parse_patch_output(line) | |||
|
252 | printed_file = False | |||
|
253 | files.setdefault(pf, (None, None)) | |||
|
254 | elif line.find('with fuzz') >= 0: | |||
|
255 | fuzz = True | |||
|
256 | if not printed_file: | |||
|
257 | ui.warn(pf + '\n') | |||
|
258 | printed_file = True | |||
|
259 | ui.warn(line + '\n') | |||
|
260 | elif line.find('saving rejects to file') >= 0: | |||
|
261 | ui.warn(line + '\n') | |||
|
262 | elif line.find('FAILED') >= 0: | |||
|
263 | if not printed_file: | |||
|
264 | ui.warn(pf + '\n') | |||
|
265 | printed_file = True | |||
|
266 | ui.warn(line + '\n') | |||
|
267 | ||||
|
268 | code = fp.close() | |||
|
269 | if code: | |||
|
270 | raise util.Abort(_("patch command failed: %s") % | |||
|
271 | util.explain_exit(code)[0]) | |||
|
272 | ||||
|
273 | for gp in gitpatches: | |||
|
274 | files[gp.path] = (gp.op, gp) | |||
|
275 | ||||
|
276 | return (files, fuzz) | |||
|
277 | ||||
|
278 | def diffopts(ui, opts={}): | |||
|
279 | return mdiff.diffopts( | |||
|
280 | text=opts.get('text'), | |||
|
281 | git=(opts.get('git') or | |||
|
282 | ui.configbool('diff', 'git', None)), | |||
|
283 | showfunc=(opts.get('show_function') or | |||
|
284 | ui.configbool('diff', 'showfunc', None)), | |||
|
285 | ignorews=(opts.get('ignore_all_space') or | |||
|
286 | ui.configbool('diff', 'ignorews', None)), | |||
|
287 | ignorewsamount=(opts.get('ignore_space_change') or | |||
|
288 | ui.configbool('diff', 'ignorewsamount', None)), | |||
|
289 | ignoreblanklines=(opts.get('ignore_blank_lines') or | |||
|
290 | ui.configbool('diff', 'ignoreblanklines', None))) | |||
|
291 | ||||
|
292 | def updatedir(ui, repo, patches, wlock=None): | |||
|
293 | '''Update dirstate after patch application according to metadata''' | |||
|
294 | if not patches: | |||
|
295 | return | |||
|
296 | copies = [] | |||
|
297 | removes = [] | |||
|
298 | cfiles = patches.keys() | |||
|
299 | copts = {'after': False, 'force': False} | |||
|
300 | cwd = repo.getcwd() | |||
|
301 | if cwd: | |||
|
302 | cfiles = [util.pathto(cwd, f) for f in patches.keys()] | |||
|
303 | for f in patches: | |||
|
304 | ctype, gp = patches[f] | |||
|
305 | if ctype == 'RENAME': | |||
|
306 | copies.append((gp.oldpath, gp.path, gp.copymod)) | |||
|
307 | removes.append(gp.oldpath) | |||
|
308 | elif ctype == 'COPY': | |||
|
309 | copies.append((gp.oldpath, gp.path, gp.copymod)) | |||
|
310 | elif ctype == 'DELETE': | |||
|
311 | removes.append(gp.path) | |||
|
312 | for src, dst, after in copies: | |||
|
313 | if not after: | |||
|
314 | copyfile(src, dst, repo.root) | |||
|
315 | repo.copy(src, dst, wlock=wlock) | |||
|
316 | if removes: | |||
|
317 | repo.remove(removes, True, wlock=wlock) | |||
|
318 | for f in patches: | |||
|
319 | ctype, gp = patches[f] | |||
|
320 | if gp and gp.mode: | |||
|
321 | x = gp.mode & 0100 != 0 | |||
|
322 | dst = os.path.join(repo.root, gp.path) | |||
|
323 | util.set_exec(dst, x) | |||
|
324 | cmdutil.addremove(repo, cfiles, wlock=wlock) | |||
|
325 | files = patches.keys() | |||
|
326 | files.extend([r for r in removes if r not in files]) | |||
|
327 | files.sort() | |||
|
328 | ||||
|
329 | return files | |||
|
330 | ||||
|
331 | def diff(repo, node1=None, node2=None, files=None, match=util.always, | |||
|
332 | fp=None, changes=None, opts=None): | |||
|
333 | '''print diff of changes to files between two nodes, or node and | |||
|
334 | working directory. | |||
|
335 | ||||
|
336 | if node1 is None, use first dirstate parent instead. | |||
|
337 | if node2 is None, compare node1 with working directory.''' | |||
|
338 | ||||
|
339 | if opts is None: | |||
|
340 | opts = mdiff.defaultopts | |||
|
341 | if fp is None: | |||
|
342 | fp = repo.ui | |||
|
343 | ||||
|
344 | if not node1: | |||
|
345 | node1 = repo.dirstate.parents()[0] | |||
|
346 | ||||
|
347 | clcache = {} | |||
|
348 | def getchangelog(n): | |||
|
349 | if n not in clcache: | |||
|
350 | clcache[n] = repo.changelog.read(n) | |||
|
351 | return clcache[n] | |||
|
352 | mcache = {} | |||
|
353 | def getmanifest(n): | |||
|
354 | if n not in mcache: | |||
|
355 | mcache[n] = repo.manifest.read(n) | |||
|
356 | return mcache[n] | |||
|
357 | fcache = {} | |||
|
358 | def getfile(f): | |||
|
359 | if f not in fcache: | |||
|
360 | fcache[f] = repo.file(f) | |||
|
361 | return fcache[f] | |||
|
362 | ||||
|
363 | # reading the data for node1 early allows it to play nicely | |||
|
364 | # with repo.status and the revlog cache. | |||
|
365 | change = getchangelog(node1) | |||
|
366 | mmap = getmanifest(change[0]) | |||
|
367 | date1 = util.datestr(change[2]) | |||
|
368 | ||||
|
369 | if not changes: | |||
|
370 | changes = repo.status(node1, node2, files, match=match)[:5] | |||
|
371 | modified, added, removed, deleted, unknown = changes | |||
|
372 | if files: | |||
|
373 | def filterfiles(filters): | |||
|
374 | l = [x for x in filters if x in files] | |||
|
375 | ||||
|
376 | for t in files: | |||
|
377 | if not t.endswith("/"): | |||
|
378 | t += "/" | |||
|
379 | l += [x for x in filters if x.startswith(t)] | |||
|
380 | return l | |||
|
381 | ||||
|
382 | modified, added, removed = map(filterfiles, (modified, added, removed)) | |||
|
383 | ||||
|
384 | if not modified and not added and not removed: | |||
|
385 | return | |||
|
386 | ||||
|
387 | def renamedbetween(f, n1, n2): | |||
|
388 | r1, r2 = map(repo.changelog.rev, (n1, n2)) | |||
|
389 | src = None | |||
|
390 | while r2 > r1: | |||
|
391 | cl = getchangelog(n2)[0] | |||
|
392 | m = getmanifest(cl) | |||
|
393 | try: | |||
|
394 | src = getfile(f).renamed(m[f]) | |||
|
395 | except KeyError: | |||
|
396 | return None | |||
|
397 | if src: | |||
|
398 | f = src[0] | |||
|
399 | n2 = repo.changelog.parents(n2)[0] | |||
|
400 | r2 = repo.changelog.rev(n2) | |||
|
401 | return src | |||
|
402 | ||||
|
403 | if node2: | |||
|
404 | change = getchangelog(node2) | |||
|
405 | mmap2 = getmanifest(change[0]) | |||
|
406 | _date2 = util.datestr(change[2]) | |||
|
407 | def date2(f): | |||
|
408 | return _date2 | |||
|
409 | def read(f): | |||
|
410 | return getfile(f).read(mmap2[f]) | |||
|
411 | def renamed(f): | |||
|
412 | return renamedbetween(f, node1, node2) | |||
|
413 | else: | |||
|
414 | tz = util.makedate()[1] | |||
|
415 | _date2 = util.datestr() | |||
|
416 | def date2(f): | |||
|
417 | try: | |||
|
418 | return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) | |||
|
419 | except OSError, err: | |||
|
420 | if err.errno != errno.ENOENT: raise | |||
|
421 | return _date2 | |||
|
422 | def read(f): | |||
|
423 | return repo.wread(f) | |||
|
424 | def renamed(f): | |||
|
425 | src = repo.dirstate.copies.get(f) | |||
|
426 | parent = repo.dirstate.parents()[0] | |||
|
427 | if src: | |||
|
428 | f = src[0] | |||
|
429 | of = renamedbetween(f, node1, parent) | |||
|
430 | if of: | |||
|
431 | return of | |||
|
432 | elif src: | |||
|
433 | cl = getchangelog(parent)[0] | |||
|
434 | return (src, getmanifest(cl)[src]) | |||
|
435 | else: | |||
|
436 | return None | |||
|
437 | ||||
|
438 | if repo.ui.quiet: | |||
|
439 | r = None | |||
|
440 | else: | |||
|
441 | hexfunc = repo.ui.verbose and hex or short | |||
|
442 | r = [hexfunc(node) for node in [node1, node2] if node] | |||
|
443 | ||||
|
444 | if opts.git: | |||
|
445 | copied = {} | |||
|
446 | for f in added: | |||
|
447 | src = renamed(f) | |||
|
448 | if src: | |||
|
449 | copied[f] = src | |||
|
450 | srcs = [x[1][0] for x in copied.items()] | |||
|
451 | ||||
|
452 | all = modified + added + removed | |||
|
453 | all.sort() | |||
|
454 | for f in all: | |||
|
455 | to = None | |||
|
456 | tn = None | |||
|
457 | dodiff = True | |||
|
458 | if f in mmap: | |||
|
459 | to = getfile(f).read(mmap[f]) | |||
|
460 | if f not in removed: | |||
|
461 | tn = read(f) | |||
|
462 | if opts.git: | |||
|
463 | def gitmode(x): | |||
|
464 | return x and '100755' or '100644' | |||
|
465 | def addmodehdr(header, omode, nmode): | |||
|
466 | if omode != nmode: | |||
|
467 | header.append('old mode %s\n' % omode) | |||
|
468 | header.append('new mode %s\n' % nmode) | |||
|
469 | ||||
|
470 | a, b = f, f | |||
|
471 | header = [] | |||
|
472 | if f in added: | |||
|
473 | if node2: | |||
|
474 | mode = gitmode(mmap2.execf(f)) | |||
|
475 | else: | |||
|
476 | mode = gitmode(util.is_exec(repo.wjoin(f), None)) | |||
|
477 | if f in copied: | |||
|
478 | a, arev = copied[f] | |||
|
479 | omode = gitmode(mmap.execf(a)) | |||
|
480 | addmodehdr(header, omode, mode) | |||
|
481 | op = a in removed and 'rename' or 'copy' | |||
|
482 | header.append('%s from %s\n' % (op, a)) | |||
|
483 | header.append('%s to %s\n' % (op, f)) | |||
|
484 | to = getfile(a).read(arev) | |||
|
485 | else: | |||
|
486 | header.append('new file mode %s\n' % mode) | |||
|
487 | elif f in removed: | |||
|
488 | if f in srcs: | |||
|
489 | dodiff = False | |||
|
490 | else: | |||
|
491 | mode = gitmode(mmap.execf(f)) | |||
|
492 | header.append('deleted file mode %s\n' % mode) | |||
|
493 | else: | |||
|
494 | omode = gitmode(mmap.execf(f)) | |||
|
495 | nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) | |||
|
496 | addmodehdr(header, omode, nmode) | |||
|
497 | r = None | |||
|
498 | if dodiff: | |||
|
499 | header.insert(0, 'diff --git a/%s b/%s\n' % (a, b)) | |||
|
500 | fp.write(''.join(header)) | |||
|
501 | if dodiff: | |||
|
502 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)) | |||
|
503 | ||||
|
504 | def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False, | |||
|
505 | opts=None): | |||
|
506 | '''export changesets as hg patches.''' | |||
|
507 | ||||
|
508 | total = len(revs) | |||
|
509 | revwidth = max(map(len, revs)) | |||
|
510 | ||||
|
511 | def single(node, seqno, fp): | |||
|
512 | parents = [p for p in repo.changelog.parents(node) if p != nullid] | |||
|
513 | if switch_parent: | |||
|
514 | parents.reverse() | |||
|
515 | prev = (parents and parents[0]) or nullid | |||
|
516 | change = repo.changelog.read(node) | |||
|
517 | ||||
|
518 | if not fp: | |||
|
519 | fp = cmdutil.make_file(repo, template, node, total=total, | |||
|
520 | seqno=seqno, revwidth=revwidth) | |||
|
521 | if fp not in (sys.stdout, repo.ui): | |||
|
522 | repo.ui.note("%s\n" % fp.name) | |||
|
523 | ||||
|
524 | fp.write("# HG changeset patch\n") | |||
|
525 | fp.write("# User %s\n" % change[1]) | |||
|
526 | fp.write("# Date %d %d\n" % change[2]) | |||
|
527 | fp.write("# Node ID %s\n" % hex(node)) | |||
|
528 | fp.write("# Parent %s\n" % hex(prev)) | |||
|
529 | if len(parents) > 1: | |||
|
530 | fp.write("# Parent %s\n" % hex(parents[1])) | |||
|
531 | fp.write(change[4].rstrip()) | |||
|
532 | fp.write("\n\n") | |||
|
533 | ||||
|
534 | diff(repo, prev, node, fp=fp, opts=opts) | |||
|
535 | if fp not in (sys.stdout, repo.ui): | |||
|
536 | fp.close() | |||
|
537 | ||||
|
538 | for seqno, cset in enumerate(revs): | |||
|
539 | single(cset, seqno, fp) |
@@ -0,0 +1,34 b'' | |||||
|
1 | # strutil.py - string utilities for Mercurial | |||
|
2 | # | |||
|
3 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | def findall(haystack, needle, start=0, end=None): | |||
|
9 | if end is None: | |||
|
10 | end = len(haystack) | |||
|
11 | if end < 0: | |||
|
12 | end += len(haystack) | |||
|
13 | if start < 0: | |||
|
14 | start += len(haystack) | |||
|
15 | while start < end: | |||
|
16 | c = haystack.find(needle, start, end) | |||
|
17 | if c == -1: | |||
|
18 | break | |||
|
19 | yield c | |||
|
20 | start = c + 1 | |||
|
21 | ||||
|
22 | def rfindall(haystack, needle, start=0, end=None): | |||
|
23 | if end is None: | |||
|
24 | end = len(haystack) | |||
|
25 | if end < 0: | |||
|
26 | end += len(haystack) | |||
|
27 | if start < 0: | |||
|
28 | start += len(haystack) | |||
|
29 | while end >= 0: | |||
|
30 | c = haystack.rfind(needle, start, end) | |||
|
31 | if c == -1: | |||
|
32 | break | |||
|
33 | yield c | |||
|
34 | end = c - 1 |
@@ -0,0 +1,200 b'' | |||||
|
1 | # verify.py - repository integrity checking for Mercurial | |||
|
2 | # | |||
|
3 | # Copyright 2006 Matt Mackall <mpm@selenic.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms | |||
|
6 | # of the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | from node import * | |||
|
9 | from i18n import gettext as _ | |||
|
10 | import revlog, mdiff | |||
|
11 | ||||
|
12 | def verify(repo): | |||
|
13 | filelinkrevs = {} | |||
|
14 | filenodes = {} | |||
|
15 | changesets = revisions = files = 0 | |||
|
16 | errors = [0] | |||
|
17 | warnings = [0] | |||
|
18 | neededmanifests = {} | |||
|
19 | ||||
|
20 | def err(msg): | |||
|
21 | repo.ui.warn(msg + "\n") | |||
|
22 | errors[0] += 1 | |||
|
23 | ||||
|
24 | def warn(msg): | |||
|
25 | repo.ui.warn(msg + "\n") | |||
|
26 | warnings[0] += 1 | |||
|
27 | ||||
|
28 | def checksize(obj, name): | |||
|
29 | d = obj.checksize() | |||
|
30 | if d[0]: | |||
|
31 | err(_("%s data length off by %d bytes") % (name, d[0])) | |||
|
32 | if d[1]: | |||
|
33 | err(_("%s index contains %d extra bytes") % (name, d[1])) | |||
|
34 | ||||
|
35 | def checkversion(obj, name): | |||
|
36 | if obj.version != revlog.REVLOGV0: | |||
|
37 | if not revlogv1: | |||
|
38 | warn(_("warning: `%s' uses revlog format 1") % name) | |||
|
39 | elif revlogv1: | |||
|
40 | warn(_("warning: `%s' uses revlog format 0") % name) | |||
|
41 | ||||
|
42 | revlogv1 = repo.revlogversion != revlog.REVLOGV0 | |||
|
43 | if repo.ui.verbose or revlogv1 != repo.revlogv1: | |||
|
44 | repo.ui.status(_("repository uses revlog format %d\n") % | |||
|
45 | (revlogv1 and 1 or 0)) | |||
|
46 | ||||
|
47 | seen = {} | |||
|
48 | repo.ui.status(_("checking changesets\n")) | |||
|
49 | checksize(repo.changelog, "changelog") | |||
|
50 | ||||
|
51 | for i in range(repo.changelog.count()): | |||
|
52 | changesets += 1 | |||
|
53 | n = repo.changelog.node(i) | |||
|
54 | l = repo.changelog.linkrev(n) | |||
|
55 | if l != i: | |||
|
56 | err(_("incorrect link (%d) for changeset revision %d") %(l, i)) | |||
|
57 | if n in seen: | |||
|
58 | err(_("duplicate changeset at revision %d") % i) | |||
|
59 | seen[n] = 1 | |||
|
60 | ||||
|
61 | for p in repo.changelog.parents(n): | |||
|
62 | if p not in repo.changelog.nodemap: | |||
|
63 | err(_("changeset %s has unknown parent %s") % | |||
|
64 | (short(n), short(p))) | |||
|
65 | try: | |||
|
66 | changes = repo.changelog.read(n) | |||
|
67 | except KeyboardInterrupt: | |||
|
68 | repo.ui.warn(_("interrupted")) | |||
|
69 | raise | |||
|
70 | except Exception, inst: | |||
|
71 | err(_("unpacking changeset %s: %s") % (short(n), inst)) | |||
|
72 | continue | |||
|
73 | ||||
|
74 | neededmanifests[changes[0]] = n | |||
|
75 | ||||
|
76 | for f in changes[3]: | |||
|
77 | filelinkrevs.setdefault(f, []).append(i) | |||
|
78 | ||||
|
79 | seen = {} | |||
|
80 | repo.ui.status(_("checking manifests\n")) | |||
|
81 | checkversion(repo.manifest, "manifest") | |||
|
82 | checksize(repo.manifest, "manifest") | |||
|
83 | ||||
|
84 | for i in range(repo.manifest.count()): | |||
|
85 | n = repo.manifest.node(i) | |||
|
86 | l = repo.manifest.linkrev(n) | |||
|
87 | ||||
|
88 | if l < 0 or l >= repo.changelog.count(): | |||
|
89 | err(_("bad manifest link (%d) at revision %d") % (l, i)) | |||
|
90 | ||||
|
91 | if n in neededmanifests: | |||
|
92 | del neededmanifests[n] | |||
|
93 | ||||
|
94 | if n in seen: | |||
|
95 | err(_("duplicate manifest at revision %d") % i) | |||
|
96 | ||||
|
97 | seen[n] = 1 | |||
|
98 | ||||
|
99 | for p in repo.manifest.parents(n): | |||
|
100 | if p not in repo.manifest.nodemap: | |||
|
101 | err(_("manifest %s has unknown parent %s") % | |||
|
102 | (short(n), short(p))) | |||
|
103 | ||||
|
104 | try: | |||
|
105 | delta = mdiff.patchtext(repo.manifest.delta(n)) | |||
|
106 | except KeyboardInterrupt: | |||
|
107 | repo.ui.warn(_("interrupted")) | |||
|
108 | raise | |||
|
109 | except Exception, inst: | |||
|
110 | err(_("unpacking manifest %s: %s") % (short(n), inst)) | |||
|
111 | continue | |||
|
112 | ||||
|
113 | try: | |||
|
114 | ff = [ l.split('\0') for l in delta.splitlines() ] | |||
|
115 | for f, fn in ff: | |||
|
116 | filenodes.setdefault(f, {})[bin(fn[:40])] = 1 | |||
|
117 | except (ValueError, TypeError), inst: | |||
|
118 | err(_("broken delta in manifest %s: %s") % (short(n), inst)) | |||
|
119 | ||||
|
120 | repo.ui.status(_("crosschecking files in changesets and manifests\n")) | |||
|
121 | ||||
|
122 | for m, c in neededmanifests.items(): | |||
|
123 | err(_("Changeset %s refers to unknown manifest %s") % | |||
|
124 | (short(m), short(c))) | |||
|
125 | del neededmanifests | |||
|
126 | ||||
|
127 | for f in filenodes: | |||
|
128 | if f not in filelinkrevs: | |||
|
129 | err(_("file %s in manifest but not in changesets") % f) | |||
|
130 | ||||
|
131 | for f in filelinkrevs: | |||
|
132 | if f not in filenodes: | |||
|
133 | err(_("file %s in changeset but not in manifest") % f) | |||
|
134 | ||||
|
135 | repo.ui.status(_("checking files\n")) | |||
|
136 | ff = filenodes.keys() | |||
|
137 | ff.sort() | |||
|
138 | for f in ff: | |||
|
139 | if f == "/dev/null": | |||
|
140 | continue | |||
|
141 | files += 1 | |||
|
142 | if not f: | |||
|
143 | err(_("file without name in manifest %s") % short(n)) | |||
|
144 | continue | |||
|
145 | fl = repo.file(f) | |||
|
146 | checkversion(fl, f) | |||
|
147 | checksize(fl, f) | |||
|
148 | ||||
|
149 | nodes = {nullid: 1} | |||
|
150 | seen = {} | |||
|
151 | for i in range(fl.count()): | |||
|
152 | revisions += 1 | |||
|
153 | n = fl.node(i) | |||
|
154 | ||||
|
155 | if n in seen: | |||
|
156 | err(_("%s: duplicate revision %d") % (f, i)) | |||
|
157 | if n not in filenodes[f]: | |||
|
158 | err(_("%s: %d:%s not in manifests") % (f, i, short(n))) | |||
|
159 | else: | |||
|
160 | del filenodes[f][n] | |||
|
161 | ||||
|
162 | flr = fl.linkrev(n) | |||
|
163 | if flr not in filelinkrevs.get(f, []): | |||
|
164 | err(_("%s:%s points to unexpected changeset %d") | |||
|
165 | % (f, short(n), flr)) | |||
|
166 | else: | |||
|
167 | filelinkrevs[f].remove(flr) | |||
|
168 | ||||
|
169 | # verify contents | |||
|
170 | try: | |||
|
171 | t = fl.read(n) | |||
|
172 | except KeyboardInterrupt: | |||
|
173 | repo.ui.warn(_("interrupted")) | |||
|
174 | raise | |||
|
175 | except Exception, inst: | |||
|
176 | err(_("unpacking file %s %s: %s") % (f, short(n), inst)) | |||
|
177 | ||||
|
178 | # verify parents | |||
|
179 | (p1, p2) = fl.parents(n) | |||
|
180 | if p1 not in nodes: | |||
|
181 | err(_("file %s:%s unknown parent 1 %s") % | |||
|
182 | (f, short(n), short(p1))) | |||
|
183 | if p2 not in nodes: | |||
|
184 | err(_("file %s:%s unknown parent 2 %s") % | |||
|
185 | (f, short(n), short(p1))) | |||
|
186 | nodes[n] = 1 | |||
|
187 | ||||
|
188 | # cross-check | |||
|
189 | for node in filenodes[f]: | |||
|
190 | err(_("node %s in manifests not in %s") % (hex(node), f)) | |||
|
191 | ||||
|
192 | repo.ui.status(_("%d files, %d changesets, %d total revisions\n") % | |||
|
193 | (files, changesets, revisions)) | |||
|
194 | ||||
|
195 | if warnings[0]: | |||
|
196 | repo.ui.warn(_("%d warnings encountered!\n") % warnings[0]) | |||
|
197 | if errors[0]: | |||
|
198 | repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) | |||
|
199 | return 1 | |||
|
200 |
@@ -0,0 +1,38 b'' | |||||
|
1 | #header# | |||
|
2 | <title>#repo|escape#: shortlog</title> | |||
|
3 | <link rel="alternate" type="application/rss+xml" | |||
|
4 | href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#"> | |||
|
5 | </head> | |||
|
6 | <body> | |||
|
7 | ||||
|
8 | <div class="buttons"> | |||
|
9 | <a href="?cl=#rev#">changelog</a> | |||
|
10 | <a href="?cmd=tags">tags</a> | |||
|
11 | <a href="?mf=#manifest|short#;path=/">manifest</a> | |||
|
12 | #archives%archiveentry# | |||
|
13 | <a type="application/rss+xml" href="?style=rss">rss</a> | |||
|
14 | </div> | |||
|
15 | ||||
|
16 | <h2>shortlog for #repo|escape#</h2> | |||
|
17 | ||||
|
18 | <form action="#"> | |||
|
19 | <p> | |||
|
20 | <label for="search1">search:</label> | |||
|
21 | <input type="hidden" name="cmd" value="changelog"> | |||
|
22 | <input name="rev" id="search1" type="text" size="30"> | |||
|
23 | navigate: <small class="navigate">#changenav%navshortentry#</small> | |||
|
24 | </p> | |||
|
25 | </form> | |||
|
26 | ||||
|
27 | #entries%shortlogentry# | |||
|
28 | ||||
|
29 | <form action="#"> | |||
|
30 | <p> | |||
|
31 | <label for="search2">search:</label> | |||
|
32 | <input type="hidden" name="cmd" value="changelog"> | |||
|
33 | <input name="rev" id="search2" type="text" size="30"> | |||
|
34 | navigate: <small class="navigate">#changenav%navshortentry#</small> | |||
|
35 | </p> | |||
|
36 | </form> | |||
|
37 | ||||
|
38 | #footer# |
@@ -0,0 +1,7 b'' | |||||
|
1 | <table class="slogEntry parity#parity#"> | |||
|
2 | <tr> | |||
|
3 | <td class="age">#date|age#</td> | |||
|
4 | <td class="author">#author|obfuscate#</td> | |||
|
5 | <td class="node"><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></td> | |||
|
6 | </tr> | |||
|
7 | </table> |
@@ -0,0 +1,22 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | cat > $HGTMP/false <<EOF | |||
|
7 | #!/bin/sh | |||
|
8 | exit 1 | |||
|
9 | EOF | |||
|
10 | chmod +x $HGTMP/false | |||
|
11 | ||||
|
12 | hg init foo | |||
|
13 | cd foo | |||
|
14 | echo foo > foo | |||
|
15 | hg add foo | |||
|
16 | ||||
|
17 | # mq may keep a reference to the repository so __del__ will not be called | |||
|
18 | # and .hg/journal.dirstate will not be deleted: | |||
|
19 | HGEDITOR=$HGTMP/false hg ci | |||
|
20 | HGEDITOR=$HGTMP/false hg ci | |||
|
21 | ||||
|
22 | exit 0 |
@@ -0,0 +1,6 b'' | |||||
|
1 | abort: edit failed: false exited with status 1 | |||
|
2 | transaction abort! | |||
|
3 | rollback completed | |||
|
4 | abort: edit failed: false exited with status 1 | |||
|
5 | transaction abort! | |||
|
6 | rollback completed |
@@ -0,0 +1,23 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | echo % init | |||
|
4 | hg init | |||
|
5 | ||||
|
6 | echo % commit | |||
|
7 | echo 'a' > a | |||
|
8 | hg ci -A -m test -u nobody -d '1 0' | |||
|
9 | ||||
|
10 | echo % annotate -c | |||
|
11 | hg annotate -c a | |||
|
12 | ||||
|
13 | echo % annotate -d | |||
|
14 | hg annotate -d a | |||
|
15 | ||||
|
16 | echo % annotate -n | |||
|
17 | hg annotate -n a | |||
|
18 | ||||
|
19 | echo % annotate -u | |||
|
20 | hg annotate -u a | |||
|
21 | ||||
|
22 | echo % annotate -cdnu | |||
|
23 | hg annotate -cdnu a |
@@ -0,0 +1,13 b'' | |||||
|
1 | % init | |||
|
2 | % commit | |||
|
3 | adding a | |||
|
4 | % annotate -c | |||
|
5 | 8435f90966e4: a | |||
|
6 | % annotate -d | |||
|
7 | Thu Jan 01 00:00:01 1970 +0000: a | |||
|
8 | % annotate -n | |||
|
9 | 0: a | |||
|
10 | % annotate -u | |||
|
11 | nobody: a | |||
|
12 | % annotate -cdnu | |||
|
13 | nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a |
@@ -0,0 +1,37 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | set -e | |||
|
4 | ||||
|
5 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
6 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
7 | echo "hbisect=" >> $HGTMP/.hgrc | |||
|
8 | ||||
|
9 | echo % init | |||
|
10 | hg init | |||
|
11 | ||||
|
12 | echo % committing changes | |||
|
13 | count=0 | |||
|
14 | echo > a | |||
|
15 | while test $count -lt 32 ; do | |||
|
16 | echo 'a' >> a | |||
|
17 | test $count -eq 0 && hg add | |||
|
18 | hg ci -m "msg $count" -d "$count 0" | |||
|
19 | echo % committed changeset $count | |||
|
20 | count=`expr $count + 1` | |||
|
21 | done | |||
|
22 | ||||
|
23 | echo % log | |||
|
24 | hg log | |||
|
25 | ||||
|
26 | echo % hg up -C | |||
|
27 | hg up -C | |||
|
28 | ||||
|
29 | echo % bisect test | |||
|
30 | hg bisect init | |||
|
31 | hg bisect bad | |||
|
32 | hg bisect good 1 | |||
|
33 | hg bisect good | |||
|
34 | hg bisect good | |||
|
35 | hg bisect good | |||
|
36 | hg bisect bad | |||
|
37 | hg bisect good |
@@ -0,0 +1,216 b'' | |||||
|
1 | % init | |||
|
2 | % committing changes | |||
|
3 | adding a | |||
|
4 | % committed changeset 0 | |||
|
5 | % committed changeset 1 | |||
|
6 | % committed changeset 2 | |||
|
7 | % committed changeset 3 | |||
|
8 | % committed changeset 4 | |||
|
9 | % committed changeset 5 | |||
|
10 | % committed changeset 6 | |||
|
11 | % committed changeset 7 | |||
|
12 | % committed changeset 8 | |||
|
13 | % committed changeset 9 | |||
|
14 | % committed changeset 10 | |||
|
15 | % committed changeset 11 | |||
|
16 | % committed changeset 12 | |||
|
17 | % committed changeset 13 | |||
|
18 | % committed changeset 14 | |||
|
19 | % committed changeset 15 | |||
|
20 | % committed changeset 16 | |||
|
21 | % committed changeset 17 | |||
|
22 | % committed changeset 18 | |||
|
23 | % committed changeset 19 | |||
|
24 | % committed changeset 20 | |||
|
25 | % committed changeset 21 | |||
|
26 | % committed changeset 22 | |||
|
27 | % committed changeset 23 | |||
|
28 | % committed changeset 24 | |||
|
29 | % committed changeset 25 | |||
|
30 | % committed changeset 26 | |||
|
31 | % committed changeset 27 | |||
|
32 | % committed changeset 28 | |||
|
33 | % committed changeset 29 | |||
|
34 | % committed changeset 30 | |||
|
35 | % committed changeset 31 | |||
|
36 | % log | |||
|
37 | changeset: 31:58c80a7c8a40 | |||
|
38 | tag: tip | |||
|
39 | user: test | |||
|
40 | date: Thu Jan 01 00:00:31 1970 +0000 | |||
|
41 | summary: msg 31 | |||
|
42 | ||||
|
43 | changeset: 30:ed2d2f24b11c | |||
|
44 | user: test | |||
|
45 | date: Thu Jan 01 00:00:30 1970 +0000 | |||
|
46 | summary: msg 30 | |||
|
47 | ||||
|
48 | changeset: 29:b5bd63375ab9 | |||
|
49 | user: test | |||
|
50 | date: Thu Jan 01 00:00:29 1970 +0000 | |||
|
51 | summary: msg 29 | |||
|
52 | ||||
|
53 | changeset: 28:8e0c2264c8af | |||
|
54 | user: test | |||
|
55 | date: Thu Jan 01 00:00:28 1970 +0000 | |||
|
56 | summary: msg 28 | |||
|
57 | ||||
|
58 | changeset: 27:288867a866e9 | |||
|
59 | user: test | |||
|
60 | date: Thu Jan 01 00:00:27 1970 +0000 | |||
|
61 | summary: msg 27 | |||
|
62 | ||||
|
63 | changeset: 26:3efc6fd51aeb | |||
|
64 | user: test | |||
|
65 | date: Thu Jan 01 00:00:26 1970 +0000 | |||
|
66 | summary: msg 26 | |||
|
67 | ||||
|
68 | changeset: 25:02a84173a97a | |||
|
69 | user: test | |||
|
70 | date: Thu Jan 01 00:00:25 1970 +0000 | |||
|
71 | summary: msg 25 | |||
|
72 | ||||
|
73 | changeset: 24:10e0acd3809e | |||
|
74 | user: test | |||
|
75 | date: Thu Jan 01 00:00:24 1970 +0000 | |||
|
76 | summary: msg 24 | |||
|
77 | ||||
|
78 | changeset: 23:5ec79163bff4 | |||
|
79 | user: test | |||
|
80 | date: Thu Jan 01 00:00:23 1970 +0000 | |||
|
81 | summary: msg 23 | |||
|
82 | ||||
|
83 | changeset: 22:06c7993750ce | |||
|
84 | user: test | |||
|
85 | date: Thu Jan 01 00:00:22 1970 +0000 | |||
|
86 | summary: msg 22 | |||
|
87 | ||||
|
88 | changeset: 21:e5db6aa3fe2a | |||
|
89 | user: test | |||
|
90 | date: Thu Jan 01 00:00:21 1970 +0000 | |||
|
91 | summary: msg 21 | |||
|
92 | ||||
|
93 | changeset: 20:7128fb4fdbc9 | |||
|
94 | user: test | |||
|
95 | date: Thu Jan 01 00:00:20 1970 +0000 | |||
|
96 | summary: msg 20 | |||
|
97 | ||||
|
98 | changeset: 19:52798545b482 | |||
|
99 | user: test | |||
|
100 | date: Thu Jan 01 00:00:19 1970 +0000 | |||
|
101 | summary: msg 19 | |||
|
102 | ||||
|
103 | changeset: 18:86977a90077e | |||
|
104 | user: test | |||
|
105 | date: Thu Jan 01 00:00:18 1970 +0000 | |||
|
106 | summary: msg 18 | |||
|
107 | ||||
|
108 | changeset: 17:03515f4a9080 | |||
|
109 | user: test | |||
|
110 | date: Thu Jan 01 00:00:17 1970 +0000 | |||
|
111 | summary: msg 17 | |||
|
112 | ||||
|
113 | changeset: 16:a2e6ea4973e9 | |||
|
114 | user: test | |||
|
115 | date: Thu Jan 01 00:00:16 1970 +0000 | |||
|
116 | summary: msg 16 | |||
|
117 | ||||
|
118 | changeset: 15:e7fa0811edb0 | |||
|
119 | user: test | |||
|
120 | date: Thu Jan 01 00:00:15 1970 +0000 | |||
|
121 | summary: msg 15 | |||
|
122 | ||||
|
123 | changeset: 14:ce8f0998e922 | |||
|
124 | user: test | |||
|
125 | date: Thu Jan 01 00:00:14 1970 +0000 | |||
|
126 | summary: msg 14 | |||
|
127 | ||||
|
128 | changeset: 13:9d7d07bc967c | |||
|
129 | user: test | |||
|
130 | date: Thu Jan 01 00:00:13 1970 +0000 | |||
|
131 | summary: msg 13 | |||
|
132 | ||||
|
133 | changeset: 12:1941b52820a5 | |||
|
134 | user: test | |||
|
135 | date: Thu Jan 01 00:00:12 1970 +0000 | |||
|
136 | summary: msg 12 | |||
|
137 | ||||
|
138 | changeset: 11:7b4cd9578619 | |||
|
139 | user: test | |||
|
140 | date: Thu Jan 01 00:00:11 1970 +0000 | |||
|
141 | summary: msg 11 | |||
|
142 | ||||
|
143 | changeset: 10:7c5eff49a6b6 | |||
|
144 | user: test | |||
|
145 | date: Thu Jan 01 00:00:10 1970 +0000 | |||
|
146 | summary: msg 10 | |||
|
147 | ||||
|
148 | changeset: 9:eb44510ef29a | |||
|
149 | user: test | |||
|
150 | date: Thu Jan 01 00:00:09 1970 +0000 | |||
|
151 | summary: msg 9 | |||
|
152 | ||||
|
153 | changeset: 8:453eb4dba229 | |||
|
154 | user: test | |||
|
155 | date: Thu Jan 01 00:00:08 1970 +0000 | |||
|
156 | summary: msg 8 | |||
|
157 | ||||
|
158 | changeset: 7:03750880c6b5 | |||
|
159 | user: test | |||
|
160 | date: Thu Jan 01 00:00:07 1970 +0000 | |||
|
161 | summary: msg 7 | |||
|
162 | ||||
|
163 | changeset: 6:a3d5c6fdf0d3 | |||
|
164 | user: test | |||
|
165 | date: Thu Jan 01 00:00:06 1970 +0000 | |||
|
166 | summary: msg 6 | |||
|
167 | ||||
|
168 | changeset: 5:7874a09ea728 | |||
|
169 | user: test | |||
|
170 | date: Thu Jan 01 00:00:05 1970 +0000 | |||
|
171 | summary: msg 5 | |||
|
172 | ||||
|
173 | changeset: 4:9b2ba8336a65 | |||
|
174 | user: test | |||
|
175 | date: Thu Jan 01 00:00:04 1970 +0000 | |||
|
176 | summary: msg 4 | |||
|
177 | ||||
|
178 | changeset: 3:b53bea5e2fcb | |||
|
179 | user: test | |||
|
180 | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
181 | summary: msg 3 | |||
|
182 | ||||
|
183 | changeset: 2:db07c04beaca | |||
|
184 | user: test | |||
|
185 | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
186 | summary: msg 2 | |||
|
187 | ||||
|
188 | changeset: 1:5cd978ea5149 | |||
|
189 | user: test | |||
|
190 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
191 | summary: msg 1 | |||
|
192 | ||||
|
193 | changeset: 0:b99c7b9c8e11 | |||
|
194 | user: test | |||
|
195 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
196 | summary: msg 0 | |||
|
197 | ||||
|
198 | % hg up -C | |||
|
199 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
200 | % bisect test | |||
|
201 | Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests) | |||
|
202 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
203 | Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests) | |||
|
204 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
205 | Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests) | |||
|
206 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
207 | Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests) | |||
|
208 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
209 | Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests) | |||
|
210 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
211 | The first bad revision is: | |||
|
212 | changeset: 29:b5bd63375ab9 | |||
|
213 | user: test | |||
|
214 | date: Thu Jan 01 00:00:29 1970 +0000 | |||
|
215 | summary: msg 29 | |||
|
216 |
@@ -0,0 +1,27 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init | |||
|
4 | ||||
|
5 | mkdir alpha | |||
|
6 | touch alpha/one | |||
|
7 | mkdir beta | |||
|
8 | touch beta/two | |||
|
9 | ||||
|
10 | hg add alpha/one beta/two | |||
|
11 | hg ci -m "start" -d "1000000 0" | |||
|
12 | ||||
|
13 | echo 1 > alpha/one | |||
|
14 | echo 2 > beta/two | |||
|
15 | ||||
|
16 | echo EVERYTHING | |||
|
17 | hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
18 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
19 | ||||
|
20 | echo BETA ONLY | |||
|
21 | hg diff beta | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
22 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
23 | ||||
|
24 | echo INSIDE BETA | |||
|
25 | cd beta | |||
|
26 | hg diff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
27 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
@@ -0,0 +1,23 b'' | |||||
|
1 | EVERYTHING | |||
|
2 | diff -r ec612a6291f1 alpha/one | |||
|
3 | --- a/alpha/one | |||
|
4 | +++ b/alpha/one | |||
|
5 | @@ -0,0 +1,1 @@ | |||
|
6 | +1 | |||
|
7 | diff -r ec612a6291f1 beta/two | |||
|
8 | --- a/beta/two | |||
|
9 | +++ b/beta/two | |||
|
10 | @@ -0,0 +1,1 @@ | |||
|
11 | +2 | |||
|
12 | BETA ONLY | |||
|
13 | diff -r ec612a6291f1 beta/two | |||
|
14 | --- a/beta/two | |||
|
15 | +++ b/beta/two | |||
|
16 | @@ -0,0 +1,1 @@ | |||
|
17 | +2 | |||
|
18 | INSIDE BETA | |||
|
19 | diff -r ec612a6291f1 beta/two | |||
|
20 | --- a/beta/two | |||
|
21 | +++ b/beta/two | |||
|
22 | @@ -0,0 +1,1 @@ | |||
|
23 | +2 |
@@ -0,0 +1,30 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "extdiff=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | hg init a | |||
|
8 | cd a | |||
|
9 | echo a > a | |||
|
10 | hg add | |||
|
11 | diff -N /dev/null /dev/null 2> /dev/null | |||
|
12 | if [ $? -ne 0 ]; then | |||
|
13 | opt="-p gdiff" | |||
|
14 | fi | |||
|
15 | hg extdiff -o -Nr $opt | |||
|
16 | ||||
|
17 | echo "[extdiff]" >> $HGTMP/.hgrc | |||
|
18 | echo "cmd.falabala=echo" >> $HGTMP/.hgrc | |||
|
19 | echo "opts.falabala=diffing" >> $HGTMP/.hgrc | |||
|
20 | ||||
|
21 | hg falabala | |||
|
22 | ||||
|
23 | hg help falabala | |||
|
24 | ||||
|
25 | hg ci -d '0 0' -mtest1 | |||
|
26 | ||||
|
27 | echo b >> a | |||
|
28 | hg ci -d '1 0' -mtest2 | |||
|
29 | ||||
|
30 | hg falabala -r 0:1 || echo "diff-like tools yield a non-zero exit code" |
@@ -0,0 +1,32 b'' | |||||
|
1 | adding a | |||
|
2 | making snapshot of 0 files from rev 000000000000 | |||
|
3 | making snapshot of 1 files from working dir | |||
|
4 | diff -Nr a.000000000000/a a/a | |||
|
5 | 0a1 | |||
|
6 | > a | |||
|
7 | making snapshot of 0 files from rev 000000000000 | |||
|
8 | making snapshot of 1 files from working dir | |||
|
9 | diffing a.000000000000 a | |||
|
10 | hg falabala [OPT]... [FILE]... | |||
|
11 | ||||
|
12 | use 'echo' to diff repository (or selected files) | |||
|
13 | ||||
|
14 | Show differences between revisions for the specified | |||
|
15 | files, using the 'echo' program. | |||
|
16 | ||||
|
17 | When two revision arguments are given, then changes are | |||
|
18 | shown between those revisions. If only one revision is | |||
|
19 | specified then that revision is compared to the working | |||
|
20 | directory, and, when no revisions are specified, the | |||
|
21 | working directory files are compared to its parent. | |||
|
22 | ||||
|
23 | options: | |||
|
24 | ||||
|
25 | -o --option pass option to comparison program | |||
|
26 | -r --rev revision | |||
|
27 | -I --include include names matching the given patterns | |||
|
28 | -X --exclude exclude names matching the given patterns | |||
|
29 | making snapshot of 1 files from rev e27a2475d60a | |||
|
30 | making snapshot of 1 files from rev 5e49ec8d3f05 | |||
|
31 | diffing a.e27a2475d60a a.5e49ec8d3f05 | |||
|
32 | diff-like tools yield a non-zero exit code |
@@ -0,0 +1,25 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "fetch=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | hg init a | |||
|
8 | echo a > a/a | |||
|
9 | hg --cwd a commit -d '1 0' -Ama | |||
|
10 | ||||
|
11 | hg clone a b | |||
|
12 | hg clone a c | |||
|
13 | ||||
|
14 | echo b > a/b | |||
|
15 | hg --cwd a commit -d '2 0' -Amb | |||
|
16 | hg --cwd a parents -q | |||
|
17 | ||||
|
18 | echo % should pull one change | |||
|
19 | hg --cwd b fetch ../a | |||
|
20 | hg --cwd b parents -q | |||
|
21 | ||||
|
22 | echo c > c/c | |||
|
23 | hg --cwd c commit -d '3 0' -Amc | |||
|
24 | hg --cwd c fetch -d '4 0' -m 'automated merge' ../a | |||
|
25 | ls c |
@@ -0,0 +1,27 b'' | |||||
|
1 | adding a | |||
|
2 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
3 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
4 | adding b | |||
|
5 | 1:97d72e5f12c7 | |||
|
6 | % should pull one change | |||
|
7 | pulling from ../a | |||
|
8 | searching for changes | |||
|
9 | adding changesets | |||
|
10 | adding manifests | |||
|
11 | adding file changes | |||
|
12 | added 1 changesets with 1 changes to 1 files | |||
|
13 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
14 | 1:97d72e5f12c7 | |||
|
15 | adding c | |||
|
16 | pulling from ../a | |||
|
17 | searching for changes | |||
|
18 | adding changesets | |||
|
19 | adding manifests | |||
|
20 | adding file changes | |||
|
21 | added 1 changesets with 1 changes to 1 files (+1 heads) | |||
|
22 | merging with new head 2:97d72e5f12c7 | |||
|
23 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
24 | new changeset 3:cd3a41621cf0 merges remote changes with local | |||
|
25 | a | |||
|
26 | b | |||
|
27 | c |
@@ -0,0 +1,52 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init a | |||
|
4 | cd a | |||
|
5 | ||||
|
6 | echo start > start | |||
|
7 | hg ci -Amstart -d '0 0' | |||
|
8 | echo new > new | |||
|
9 | hg ci -Amnew -d '0 0' | |||
|
10 | echo '% new file' | |||
|
11 | hg diff --git -r 0 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
12 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
13 | ||||
|
14 | hg cp new copy | |||
|
15 | hg ci -mcopy -d '0 0' | |||
|
16 | echo '% copy' | |||
|
17 | hg diff --git -r 1:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
18 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
19 | ||||
|
20 | hg mv copy rename | |||
|
21 | hg ci -mrename -d '0 0' | |||
|
22 | echo '% rename' | |||
|
23 | hg diff --git -r 2:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
24 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
25 | ||||
|
26 | hg rm rename | |||
|
27 | hg ci -mdelete -d '0 0' | |||
|
28 | echo '% delete' | |||
|
29 | hg diff --git -r 3:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
30 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
31 | ||||
|
32 | cat > src <<EOF | |||
|
33 | 1 | |||
|
34 | 2 | |||
|
35 | 3 | |||
|
36 | 4 | |||
|
37 | 5 | |||
|
38 | EOF | |||
|
39 | hg ci -Amsrc -d '0 0' | |||
|
40 | chmod +x src | |||
|
41 | hg ci -munexec -d '0 0' | |||
|
42 | echo '% chmod 644' | |||
|
43 | hg diff --git -r 5:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
44 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
45 | ||||
|
46 | hg mv src dst | |||
|
47 | chmod -x dst | |||
|
48 | echo a >> dst | |||
|
49 | hg ci -mrenamemod -d '0 0' | |||
|
50 | echo '% rename+mod+chmod' | |||
|
51 | hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
52 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
@@ -0,0 +1,42 b'' | |||||
|
1 | adding start | |||
|
2 | adding new | |||
|
3 | % new file | |||
|
4 | diff --git a/new b/new | |||
|
5 | new file mode 100644 | |||
|
6 | --- /dev/null | |||
|
7 | +++ b/new | |||
|
8 | @@ -0,0 +1,1 @@ | |||
|
9 | +new | |||
|
10 | % copy | |||
|
11 | diff --git a/new b/copy | |||
|
12 | copy from new | |||
|
13 | copy to copy | |||
|
14 | % rename | |||
|
15 | diff --git a/copy b/rename | |||
|
16 | rename from copy | |||
|
17 | rename to rename | |||
|
18 | % delete | |||
|
19 | diff --git a/rename b/rename | |||
|
20 | deleted file mode 100644 | |||
|
21 | --- a/rename | |||
|
22 | +++ /dev/null | |||
|
23 | @@ -1,1 +0,0 @@ | |||
|
24 | -new | |||
|
25 | adding src | |||
|
26 | % chmod 644 | |||
|
27 | diff --git a/src b/src | |||
|
28 | old mode 100644 | |||
|
29 | new mode 100755 | |||
|
30 | % rename+mod+chmod | |||
|
31 | diff --git a/src b/dst | |||
|
32 | old mode 100755 | |||
|
33 | new mode 100644 | |||
|
34 | rename from src | |||
|
35 | rename to dst | |||
|
36 | --- a/dst | |||
|
37 | +++ b/dst | |||
|
38 | @@ -3,3 +3,4 @@ 3 | |||
|
39 | 3 | |||
|
40 | 4 | |||
|
41 | 5 | |||
|
42 | +a |
@@ -0,0 +1,122 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init a | |||
|
4 | cd a | |||
|
5 | ||||
|
6 | echo % new file | |||
|
7 | hg import -mnew - <<EOF | |||
|
8 | diff --git a/new b/new | |||
|
9 | new file mode 100644 | |||
|
10 | index 0000000..7898192 | |||
|
11 | --- /dev/null | |||
|
12 | +++ b/new | |||
|
13 | @@ -0,0 +1 @@ | |||
|
14 | +a | |||
|
15 | EOF | |||
|
16 | ||||
|
17 | echo % chmod +x | |||
|
18 | hg import -msetx - <<EOF | |||
|
19 | diff --git a/new b/new | |||
|
20 | old mode 100644 | |||
|
21 | new mode 100755 | |||
|
22 | EOF | |||
|
23 | ||||
|
24 | test -x new || echo failed | |||
|
25 | ||||
|
26 | echo % copy | |||
|
27 | hg import -mcopy - <<EOF | |||
|
28 | diff --git a/new b/copy | |||
|
29 | old mode 100755 | |||
|
30 | new mode 100644 | |||
|
31 | similarity index 100% | |||
|
32 | copy from new | |||
|
33 | copy to copy | |||
|
34 | diff --git a/new b/copyx | |||
|
35 | similarity index 100% | |||
|
36 | copy from new | |||
|
37 | copy to copyx | |||
|
38 | EOF | |||
|
39 | ||||
|
40 | test -f copy -a ! -x copy || echo failed | |||
|
41 | test -x copyx || echo failed | |||
|
42 | cat copy | |||
|
43 | hg cat copy | |||
|
44 | ||||
|
45 | echo % rename | |||
|
46 | hg import -mrename - <<EOF | |||
|
47 | diff --git a/copy b/rename | |||
|
48 | similarity index 100% | |||
|
49 | rename from copy | |||
|
50 | rename to rename | |||
|
51 | EOF | |||
|
52 | ||||
|
53 | hg locate | |||
|
54 | ||||
|
55 | echo % delete | |||
|
56 | hg import -mdelete - <<EOF | |||
|
57 | diff --git a/copyx b/copyx | |||
|
58 | deleted file mode 100755 | |||
|
59 | index 7898192..0000000 | |||
|
60 | --- a/copyx | |||
|
61 | +++ /dev/null | |||
|
62 | @@ -1 +0,0 @@ | |||
|
63 | -a | |||
|
64 | EOF | |||
|
65 | ||||
|
66 | hg locate | |||
|
67 | test -f copyx && echo failed || true | |||
|
68 | ||||
|
69 | echo % regular diff | |||
|
70 | hg import -mregular - <<EOF | |||
|
71 | diff --git a/rename b/rename | |||
|
72 | index 7898192..72e1fe3 100644 | |||
|
73 | --- a/rename | |||
|
74 | +++ b/rename | |||
|
75 | @@ -1 +1,5 @@ | |||
|
76 | a | |||
|
77 | +a | |||
|
78 | +a | |||
|
79 | +a | |||
|
80 | +a | |||
|
81 | EOF | |||
|
82 | ||||
|
83 | echo % copy and modify | |||
|
84 | hg import -mcopymod - <<EOF | |||
|
85 | diff --git a/rename b/copy2 | |||
|
86 | similarity index 80% | |||
|
87 | copy from rename | |||
|
88 | copy to copy2 | |||
|
89 | index 72e1fe3..b53c148 100644 | |||
|
90 | --- a/rename | |||
|
91 | +++ b/copy2 | |||
|
92 | @@ -1,5 +1,5 @@ | |||
|
93 | a | |||
|
94 | a | |||
|
95 | -a | |||
|
96 | +b | |||
|
97 | a | |||
|
98 | a | |||
|
99 | EOF | |||
|
100 | ||||
|
101 | hg cat copy2 | |||
|
102 | ||||
|
103 | echo % rename and modify | |||
|
104 | hg import -mrenamemod - <<EOF | |||
|
105 | diff --git a/copy2 b/rename2 | |||
|
106 | similarity index 80% | |||
|
107 | rename from copy2 | |||
|
108 | rename to rename2 | |||
|
109 | index b53c148..8f81e29 100644 | |||
|
110 | --- a/copy2 | |||
|
111 | +++ b/rename2 | |||
|
112 | @@ -1,5 +1,5 @@ | |||
|
113 | a | |||
|
114 | a | |||
|
115 | b | |||
|
116 | -a | |||
|
117 | +c | |||
|
118 | a | |||
|
119 | EOF | |||
|
120 | ||||
|
121 | hg locate copy2 | |||
|
122 | hg cat rename2 |
@@ -0,0 +1,34 b'' | |||||
|
1 | % new file | |||
|
2 | applying patch from stdin | |||
|
3 | % chmod +x | |||
|
4 | applying patch from stdin | |||
|
5 | % copy | |||
|
6 | applying patch from stdin | |||
|
7 | a | |||
|
8 | a | |||
|
9 | % rename | |||
|
10 | applying patch from stdin | |||
|
11 | copyx | |||
|
12 | new | |||
|
13 | rename | |||
|
14 | % delete | |||
|
15 | applying patch from stdin | |||
|
16 | new | |||
|
17 | rename | |||
|
18 | % regular diff | |||
|
19 | applying patch from stdin | |||
|
20 | % copy and modify | |||
|
21 | applying patch from stdin | |||
|
22 | a | |||
|
23 | a | |||
|
24 | b | |||
|
25 | a | |||
|
26 | a | |||
|
27 | % rename and modify | |||
|
28 | applying patch from stdin | |||
|
29 | copy2: No such file or directory | |||
|
30 | a | |||
|
31 | a | |||
|
32 | b | |||
|
33 | c | |||
|
34 | a |
@@ -0,0 +1,49 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | # http://www.selenic.com/mercurial/bts/issue322 | |||
|
3 | ||||
|
4 | echo % file replaced with directory | |||
|
5 | ||||
|
6 | hg init a | |||
|
7 | cd a | |||
|
8 | echo a > a | |||
|
9 | hg commit -Ama | |||
|
10 | rm a | |||
|
11 | mkdir a | |||
|
12 | echo a > a/a | |||
|
13 | ||||
|
14 | echo % should fail - would corrupt dirstate | |||
|
15 | hg add a/a | |||
|
16 | ||||
|
17 | cd .. | |||
|
18 | ||||
|
19 | echo % directory replaced with file | |||
|
20 | ||||
|
21 | hg init c | |||
|
22 | cd c | |||
|
23 | mkdir a | |||
|
24 | echo a > a/a | |||
|
25 | hg commit -Ama | |||
|
26 | ||||
|
27 | rm -rf a | |||
|
28 | echo a > a | |||
|
29 | ||||
|
30 | echo % should fail - would corrupt dirstate | |||
|
31 | hg add a | |||
|
32 | ||||
|
33 | cd .. | |||
|
34 | ||||
|
35 | echo % directory replaced with file | |||
|
36 | ||||
|
37 | hg init d | |||
|
38 | cd d | |||
|
39 | mkdir b | |||
|
40 | mkdir b/c | |||
|
41 | echo a > b/c/d | |||
|
42 | hg commit -Ama | |||
|
43 | rm -rf b | |||
|
44 | echo a > b | |||
|
45 | ||||
|
46 | echo % should fail - would corrupt dirstate | |||
|
47 | hg add b | |||
|
48 | ||||
|
49 | exit 0 |
@@ -0,0 +1,12 b'' | |||||
|
1 | % file replaced with directory | |||
|
2 | adding a | |||
|
3 | % should fail - would corrupt dirstate | |||
|
4 | abort: file named 'a' already in dirstate | |||
|
5 | % directory replaced with file | |||
|
6 | adding a/a | |||
|
7 | % should fail - would corrupt dirstate | |||
|
8 | abort: directory named 'a' already in dirstate | |||
|
9 | % directory replaced with file | |||
|
10 | adding b/c/d | |||
|
11 | % should fail - would corrupt dirstate | |||
|
12 | abort: directory named 'b' already in dirstate |
@@ -0,0 +1,68 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init a | |||
|
4 | ||||
|
5 | cd a | |||
|
6 | echo a > a | |||
|
7 | hg ci -Ama -d '1 0' | |||
|
8 | ||||
|
9 | hg cp a b | |||
|
10 | hg ci -mb -d '2 0' | |||
|
11 | ||||
|
12 | mkdir dir | |||
|
13 | hg mv b dir | |||
|
14 | hg ci -mc -d '3 0' | |||
|
15 | ||||
|
16 | hg mv a b | |||
|
17 | hg ci -md -d '4 0' | |||
|
18 | ||||
|
19 | hg mv dir/b e | |||
|
20 | hg ci -me -d '5 0' | |||
|
21 | ||||
|
22 | hg log a | |||
|
23 | echo % -f, directory | |||
|
24 | hg log -f dir | |||
|
25 | echo % -f, but no args | |||
|
26 | hg log -f | |||
|
27 | echo % one rename | |||
|
28 | hg log -vf a | |||
|
29 | echo % many renames | |||
|
30 | hg log -vf e | |||
|
31 | ||||
|
32 | # log --follow tests | |||
|
33 | hg init ../follow | |||
|
34 | cd ../follow | |||
|
35 | echo base > base | |||
|
36 | hg ci -Ambase -d '1 0' | |||
|
37 | ||||
|
38 | echo r1 >> base | |||
|
39 | hg ci -Amr1 -d '1 0' | |||
|
40 | echo r2 >> base | |||
|
41 | hg ci -Amr2 -d '1 0' | |||
|
42 | ||||
|
43 | hg up -C 1 | |||
|
44 | echo b1 > b1 | |||
|
45 | hg ci -Amb1 -d '1 0' | |||
|
46 | ||||
|
47 | echo % log -f | |||
|
48 | hg log -f | |||
|
49 | ||||
|
50 | hg up -C 0 | |||
|
51 | echo b2 > b2 | |||
|
52 | hg ci -Amb2 -d '1 0' | |||
|
53 | ||||
|
54 | echo % log -f -r 1:tip | |||
|
55 | hg log -f -r 1:tip | |||
|
56 | ||||
|
57 | hg up -C 3 | |||
|
58 | hg merge tip | |||
|
59 | hg ci -mm12 -d '1 0' | |||
|
60 | ||||
|
61 | echo postm >> b1 | |||
|
62 | hg ci -Amb1.1 -d'1 0' | |||
|
63 | ||||
|
64 | echo % log --follow-first | |||
|
65 | hg log --follow-first | |||
|
66 | ||||
|
67 | echo % log -P 2 | |||
|
68 | hg log -P 2 |
@@ -0,0 +1,177 b'' | |||||
|
1 | adding a | |||
|
2 | changeset: 0:8580ff50825a | |||
|
3 | user: test | |||
|
4 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
5 | summary: a | |||
|
6 | ||||
|
7 | % -f, directory | |||
|
8 | abort: can only follow copies/renames for explicit file names | |||
|
9 | % -f, but no args | |||
|
10 | changeset: 4:8c1c8408f737 | |||
|
11 | tag: tip | |||
|
12 | user: test | |||
|
13 | date: Thu Jan 01 00:00:05 1970 +0000 | |||
|
14 | summary: e | |||
|
15 | ||||
|
16 | changeset: 3:c4ba038c90ce | |||
|
17 | user: test | |||
|
18 | date: Thu Jan 01 00:00:04 1970 +0000 | |||
|
19 | summary: d | |||
|
20 | ||||
|
21 | changeset: 2:21fba396af4c | |||
|
22 | user: test | |||
|
23 | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
24 | summary: c | |||
|
25 | ||||
|
26 | changeset: 1:c0296dabce9b | |||
|
27 | user: test | |||
|
28 | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
29 | summary: b | |||
|
30 | ||||
|
31 | changeset: 0:8580ff50825a | |||
|
32 | user: test | |||
|
33 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
34 | summary: a | |||
|
35 | ||||
|
36 | % one rename | |||
|
37 | changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab | |||
|
38 | user: test | |||
|
39 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
40 | files: a | |||
|
41 | description: | |||
|
42 | a | |||
|
43 | ||||
|
44 | ||||
|
45 | % many renames | |||
|
46 | changeset: 4:8c1c8408f7371319750ea2d4fa7969828effbcf4 | |||
|
47 | tag: tip | |||
|
48 | user: test | |||
|
49 | date: Thu Jan 01 00:00:05 1970 +0000 | |||
|
50 | files: dir/b e | |||
|
51 | description: | |||
|
52 | e | |||
|
53 | ||||
|
54 | ||||
|
55 | changeset: 2:21fba396af4c801f9717de6c415b6cc9620437e8 | |||
|
56 | user: test | |||
|
57 | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
58 | files: b dir/b | |||
|
59 | description: | |||
|
60 | c | |||
|
61 | ||||
|
62 | ||||
|
63 | changeset: 1:c0296dabce9bf0cd3fdd608de26693c91cd6bbf4 | |||
|
64 | user: test | |||
|
65 | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
66 | files: b | |||
|
67 | description: | |||
|
68 | b | |||
|
69 | ||||
|
70 | ||||
|
71 | changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab | |||
|
72 | user: test | |||
|
73 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
74 | files: a | |||
|
75 | description: | |||
|
76 | a | |||
|
77 | ||||
|
78 | ||||
|
79 | adding base | |||
|
80 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
81 | adding b1 | |||
|
82 | % log -f | |||
|
83 | changeset: 3:e62f78d544b4 | |||
|
84 | tag: tip | |||
|
85 | parent: 1:3d5bf5654eda | |||
|
86 | user: test | |||
|
87 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
88 | summary: b1 | |||
|
89 | ||||
|
90 | changeset: 1:3d5bf5654eda | |||
|
91 | user: test | |||
|
92 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
93 | summary: r1 | |||
|
94 | ||||
|
95 | changeset: 0:67e992f2c4f3 | |||
|
96 | user: test | |||
|
97 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
98 | summary: base | |||
|
99 | ||||
|
100 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
101 | adding b2 | |||
|
102 | % log -f -r 1:tip | |||
|
103 | changeset: 1:3d5bf5654eda | |||
|
104 | user: test | |||
|
105 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
106 | summary: r1 | |||
|
107 | ||||
|
108 | changeset: 2:60c670bf5b30 | |||
|
109 | user: test | |||
|
110 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
111 | summary: r2 | |||
|
112 | ||||
|
113 | changeset: 3:e62f78d544b4 | |||
|
114 | parent: 1:3d5bf5654eda | |||
|
115 | user: test | |||
|
116 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
117 | summary: b1 | |||
|
118 | ||||
|
119 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
120 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
121 | (branch merge, don't forget to commit) | |||
|
122 | % log --follow-first | |||
|
123 | changeset: 6:2404bbcab562 | |||
|
124 | tag: tip | |||
|
125 | user: test | |||
|
126 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
127 | summary: b1.1 | |||
|
128 | ||||
|
129 | changeset: 5:302e9dd6890d | |||
|
130 | parent: 3:e62f78d544b4 | |||
|
131 | parent: 4:ddb82e70d1a1 | |||
|
132 | user: test | |||
|
133 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
134 | summary: m12 | |||
|
135 | ||||
|
136 | changeset: 3:e62f78d544b4 | |||
|
137 | parent: 1:3d5bf5654eda | |||
|
138 | user: test | |||
|
139 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
140 | summary: b1 | |||
|
141 | ||||
|
142 | changeset: 1:3d5bf5654eda | |||
|
143 | user: test | |||
|
144 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
145 | summary: r1 | |||
|
146 | ||||
|
147 | changeset: 0:67e992f2c4f3 | |||
|
148 | user: test | |||
|
149 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
150 | summary: base | |||
|
151 | ||||
|
152 | % log -P 2 | |||
|
153 | changeset: 6:2404bbcab562 | |||
|
154 | tag: tip | |||
|
155 | user: test | |||
|
156 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
157 | summary: b1.1 | |||
|
158 | ||||
|
159 | changeset: 5:302e9dd6890d | |||
|
160 | parent: 3:e62f78d544b4 | |||
|
161 | parent: 4:ddb82e70d1a1 | |||
|
162 | user: test | |||
|
163 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
164 | summary: m12 | |||
|
165 | ||||
|
166 | changeset: 4:ddb82e70d1a1 | |||
|
167 | parent: 0:67e992f2c4f3 | |||
|
168 | user: test | |||
|
169 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
170 | summary: b2 | |||
|
171 | ||||
|
172 | changeset: 3:e62f78d544b4 | |||
|
173 | parent: 1:3d5bf5654eda | |||
|
174 | user: test | |||
|
175 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
176 | summary: b1 | |||
|
177 |
@@ -0,0 +1,40 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init | |||
|
4 | echo a > a | |||
|
5 | hg commit -A -ma | |||
|
6 | ||||
|
7 | echo a >> a | |||
|
8 | hg commit -mb | |||
|
9 | ||||
|
10 | echo a >> a | |||
|
11 | hg commit -mc | |||
|
12 | ||||
|
13 | hg up 1 | |||
|
14 | echo a >> a | |||
|
15 | hg commit -md | |||
|
16 | ||||
|
17 | hg up 1 | |||
|
18 | echo a >> a | |||
|
19 | hg commit -me | |||
|
20 | ||||
|
21 | hg up 1 | |||
|
22 | echo % should fail because not at a head | |||
|
23 | hg merge | |||
|
24 | ||||
|
25 | hg up | |||
|
26 | echo % should fail because \> 2 heads | |||
|
27 | hg merge | |||
|
28 | ||||
|
29 | echo % should succeed | |||
|
30 | hg merge 2 | |||
|
31 | hg commit -mm1 | |||
|
32 | ||||
|
33 | echo % should succeed - 2 heads | |||
|
34 | hg merge | |||
|
35 | hg commit -mm2 | |||
|
36 | ||||
|
37 | echo % should fail because 1 head | |||
|
38 | hg merge | |||
|
39 | ||||
|
40 | true |
@@ -0,0 +1,17 b'' | |||||
|
1 | adding a | |||
|
2 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
3 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
4 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
5 | % should fail because not at a head | |||
|
6 | abort: repo has 3 heads - please merge with an explicit rev | |||
|
7 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
8 | % should fail because > 2 heads | |||
|
9 | abort: repo has 3 heads - please merge with an explicit rev | |||
|
10 | % should succeed | |||
|
11 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
12 | (branch merge, don't forget to commit) | |||
|
13 | % should succeed - 2 heads | |||
|
14 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
15 | (branch merge, don't forget to commit) | |||
|
16 | % should fail because 1 head | |||
|
17 | abort: there is nothing to merge - use "hg update" instead |
@@ -0,0 +1,155 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | echo % help | |||
|
8 | hg help mq | |||
|
9 | ||||
|
10 | hg init a | |||
|
11 | cd a | |||
|
12 | echo a > a | |||
|
13 | hg ci -Ama | |||
|
14 | ||||
|
15 | hg clone . ../k | |||
|
16 | ||||
|
17 | mkdir b | |||
|
18 | echo z > b/z | |||
|
19 | hg ci -Ama | |||
|
20 | ||||
|
21 | echo % qinit | |||
|
22 | ||||
|
23 | hg qinit | |||
|
24 | ||||
|
25 | cd .. | |||
|
26 | hg init b | |||
|
27 | ||||
|
28 | echo % -R qinit | |||
|
29 | ||||
|
30 | hg -R b qinit | |||
|
31 | ||||
|
32 | hg init c | |||
|
33 | ||||
|
34 | echo % qinit -c | |||
|
35 | ||||
|
36 | hg --cwd c qinit -c | |||
|
37 | hg -R c/.hg/patches st | |||
|
38 | ||||
|
39 | echo % qnew implies add | |||
|
40 | ||||
|
41 | hg -R c qnew test.patch | |||
|
42 | hg -R c/.hg/patches st | |||
|
43 | ||||
|
44 | cd a | |||
|
45 | ||||
|
46 | echo % qnew -m | |||
|
47 | ||||
|
48 | hg qnew -m 'foo bar' test.patch | |||
|
49 | cat .hg/patches/test.patch | |||
|
50 | ||||
|
51 | echo % qrefresh | |||
|
52 | ||||
|
53 | echo a >> a | |||
|
54 | hg qrefresh | |||
|
55 | sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \ | |||
|
56 | -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
57 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch | |||
|
58 | ||||
|
59 | echo % qpop | |||
|
60 | ||||
|
61 | hg qpop | |||
|
62 | ||||
|
63 | echo % qpush | |||
|
64 | ||||
|
65 | hg qpush | |||
|
66 | ||||
|
67 | cd .. | |||
|
68 | ||||
|
69 | echo % pop/push outside repo | |||
|
70 | ||||
|
71 | hg -R a qpop | |||
|
72 | hg -R a qpush | |||
|
73 | ||||
|
74 | cd a | |||
|
75 | hg qnew test2.patch | |||
|
76 | ||||
|
77 | echo % qrefresh in subdir | |||
|
78 | ||||
|
79 | cd b | |||
|
80 | echo a > a | |||
|
81 | hg add a | |||
|
82 | hg qrefresh | |||
|
83 | ||||
|
84 | echo % pop/push -a in subdir | |||
|
85 | ||||
|
86 | hg qpop -a | |||
|
87 | hg --traceback qpush -a | |||
|
88 | ||||
|
89 | echo % qseries | |||
|
90 | hg qseries | |||
|
91 | ||||
|
92 | echo % qapplied | |||
|
93 | hg qapplied | |||
|
94 | ||||
|
95 | echo % qtop | |||
|
96 | hg qtop | |||
|
97 | ||||
|
98 | echo % qprev | |||
|
99 | hg qprev | |||
|
100 | ||||
|
101 | echo % qnext | |||
|
102 | hg qnext | |||
|
103 | ||||
|
104 | echo % pop, qnext, qprev, qapplied | |||
|
105 | hg qpop | |||
|
106 | hg qnext | |||
|
107 | hg qprev | |||
|
108 | hg qapplied | |||
|
109 | ||||
|
110 | echo % commit should fail | |||
|
111 | hg commit | |||
|
112 | ||||
|
113 | echo % push should fail | |||
|
114 | hg push ../../k | |||
|
115 | ||||
|
116 | echo % qunapplied | |||
|
117 | hg qunapplied | |||
|
118 | ||||
|
119 | echo % push should succeed | |||
|
120 | hg qpop -a | |||
|
121 | hg push ../../k | |||
|
122 | ||||
|
123 | echo % strip | |||
|
124 | cd ../../b | |||
|
125 | echo x>x | |||
|
126 | hg ci -Ama | |||
|
127 | hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' | |||
|
128 | hg unbundle .hg/strip-backup/* | |||
|
129 | ||||
|
130 | cat >>$HGTMP/.hgrc <<EOF | |||
|
131 | [diff] | |||
|
132 | git = True | |||
|
133 | EOF | |||
|
134 | cd .. | |||
|
135 | hg init git | |||
|
136 | cd git | |||
|
137 | hg qinit | |||
|
138 | ||||
|
139 | hg qnew -m'new file' new | |||
|
140 | echo foo > new | |||
|
141 | chmod +x new | |||
|
142 | hg add new | |||
|
143 | hg qrefresh | |||
|
144 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
145 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new | |||
|
146 | ||||
|
147 | hg qnew -m'copy file' copy | |||
|
148 | hg cp new copy | |||
|
149 | hg qrefresh | |||
|
150 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
151 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy | |||
|
152 | ||||
|
153 | hg qpop | |||
|
154 | hg qpush | |||
|
155 | hg qdiff |
@@ -0,0 +1,101 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | hg init | |||
|
8 | hg qinit | |||
|
9 | ||||
|
10 | echo x > x | |||
|
11 | hg ci -Ama | |||
|
12 | ||||
|
13 | hg qnew a.patch | |||
|
14 | echo a > a | |||
|
15 | hg add a | |||
|
16 | hg qrefresh | |||
|
17 | ||||
|
18 | hg qnew b.patch | |||
|
19 | echo b > b | |||
|
20 | hg add b | |||
|
21 | hg qrefresh | |||
|
22 | ||||
|
23 | hg qnew c.patch | |||
|
24 | echo c > c | |||
|
25 | hg add c | |||
|
26 | hg qrefresh | |||
|
27 | ||||
|
28 | hg qpop -a | |||
|
29 | ||||
|
30 | echo % should fail | |||
|
31 | hg qguard +fail | |||
|
32 | ||||
|
33 | hg qpush | |||
|
34 | echo % should guard a.patch | |||
|
35 | hg qguard +a | |||
|
36 | echo % should print +a | |||
|
37 | hg qguard | |||
|
38 | hg qpop | |||
|
39 | ||||
|
40 | hg qguard a.patch | |||
|
41 | echo % should push b.patch | |||
|
42 | hg qpush | |||
|
43 | ||||
|
44 | hg qpop | |||
|
45 | hg qselect a | |||
|
46 | echo % should push a.patch | |||
|
47 | hg qpush | |||
|
48 | ||||
|
49 | hg qguard c.patch -a | |||
|
50 | echo % should print -a | |||
|
51 | hg qguard c.patch | |||
|
52 | ||||
|
53 | echo % should skip c.patch | |||
|
54 | hg qpush -a | |||
|
55 | ||||
|
56 | hg qguard -n c.patch | |||
|
57 | echo % should push c.patch | |||
|
58 | hg qpush -a | |||
|
59 | ||||
|
60 | hg qpop -a | |||
|
61 | hg qselect -n | |||
|
62 | echo % should push all | |||
|
63 | hg qpush -a | |||
|
64 | ||||
|
65 | hg qpop -a | |||
|
66 | hg qguard a.patch +1 | |||
|
67 | hg qguard b.patch +2 | |||
|
68 | hg qselect 1 | |||
|
69 | echo % should push a.patch, not b.patch | |||
|
70 | hg qpush | |||
|
71 | hg qpush | |||
|
72 | hg qpop -a | |||
|
73 | ||||
|
74 | hg qselect 2 | |||
|
75 | echo % should push b.patch | |||
|
76 | hg qpush | |||
|
77 | hg qpop -a | |||
|
78 | ||||
|
79 | hg qselect 1 2 | |||
|
80 | echo % should push a.patch, b.patch | |||
|
81 | hg qpush | |||
|
82 | hg qpush | |||
|
83 | hg qpop -a | |||
|
84 | ||||
|
85 | hg qguard a.patch +1 +2 -3 | |||
|
86 | hg qselect 1 2 3 | |||
|
87 | echo % list patches and guards | |||
|
88 | hg qguard -l | |||
|
89 | echo % list series | |||
|
90 | hg qseries -v | |||
|
91 | echo % list guards | |||
|
92 | hg qselect | |||
|
93 | echo % should push b.patch | |||
|
94 | hg qpush | |||
|
95 | ||||
|
96 | hg qpush -a | |||
|
97 | hg qselect -n --reapply | |||
|
98 | echo % guards in series file: +1 +2 -3 | |||
|
99 | hg qselect -s | |||
|
100 | echo % should show c.patch | |||
|
101 | hg qapplied |
@@ -0,0 +1,84 b'' | |||||
|
1 | adding x | |||
|
2 | Patch queue now empty | |||
|
3 | % should fail | |||
|
4 | abort: no patches applied | |||
|
5 | applying a.patch | |||
|
6 | Now at: a.patch | |||
|
7 | % should guard a.patch | |||
|
8 | % should print +a | |||
|
9 | a.patch: +a | |||
|
10 | Patch queue now empty | |||
|
11 | a.patch: +a | |||
|
12 | % should push b.patch | |||
|
13 | applying b.patch | |||
|
14 | Now at: b.patch | |||
|
15 | Patch queue now empty | |||
|
16 | number of unguarded, unapplied patches has changed from 2 to 3 | |||
|
17 | % should push a.patch | |||
|
18 | applying a.patch | |||
|
19 | Now at: a.patch | |||
|
20 | % should print -a | |||
|
21 | c.patch: -a | |||
|
22 | % should skip c.patch | |||
|
23 | applying b.patch | |||
|
24 | skipping c.patch - guarded by '- a' | |||
|
25 | Now at: b.patch | |||
|
26 | % should push c.patch | |||
|
27 | applying c.patch | |||
|
28 | Now at: c.patch | |||
|
29 | Patch queue now empty | |||
|
30 | guards deactivated | |||
|
31 | number of unguarded, unapplied patches has changed from 3 to 2 | |||
|
32 | % should push all | |||
|
33 | applying b.patch | |||
|
34 | applying c.patch | |||
|
35 | Now at: c.patch | |||
|
36 | Patch queue now empty | |||
|
37 | number of unguarded, unapplied patches has changed from 1 to 2 | |||
|
38 | % should push a.patch, not b.patch | |||
|
39 | applying a.patch | |||
|
40 | Now at: a.patch | |||
|
41 | applying c.patch | |||
|
42 | Now at: c.patch | |||
|
43 | Patch queue now empty | |||
|
44 | % should push b.patch | |||
|
45 | applying b.patch | |||
|
46 | Now at: b.patch | |||
|
47 | Patch queue now empty | |||
|
48 | number of unguarded, unapplied patches has changed from 2 to 3 | |||
|
49 | % should push a.patch, b.patch | |||
|
50 | applying a.patch | |||
|
51 | Now at: a.patch | |||
|
52 | applying b.patch | |||
|
53 | Now at: b.patch | |||
|
54 | Patch queue now empty | |||
|
55 | number of unguarded, unapplied patches has changed from 3 to 2 | |||
|
56 | % list patches and guards | |||
|
57 | a.patch: +1 +2 -3 | |||
|
58 | b.patch: +2 | |||
|
59 | c.patch: unguarded | |||
|
60 | % list series | |||
|
61 | 0 G a.patch | |||
|
62 | 1 U b.patch | |||
|
63 | 2 U c.patch | |||
|
64 | % list guards | |||
|
65 | 1 | |||
|
66 | 2 | |||
|
67 | 3 | |||
|
68 | % should push b.patch | |||
|
69 | applying b.patch | |||
|
70 | Now at: b.patch | |||
|
71 | applying c.patch | |||
|
72 | Now at: c.patch | |||
|
73 | guards deactivated | |||
|
74 | popping guarded patches | |||
|
75 | Patch queue now empty | |||
|
76 | reapplying unguarded patches | |||
|
77 | applying c.patch | |||
|
78 | Now at: c.patch | |||
|
79 | % guards in series file: +1 +2 -3 | |||
|
80 | +1 | |||
|
81 | +2 | |||
|
82 | -3 | |||
|
83 | % should show c.patch | |||
|
84 | c.patch |
@@ -0,0 +1,28 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | echo % init | |||
|
8 | hg init a | |||
|
9 | cd a | |||
|
10 | ||||
|
11 | echo % commit | |||
|
12 | echo 'base' > base | |||
|
13 | hg ci -Ambase -d '1 0' | |||
|
14 | ||||
|
15 | echo % qnew mqbase | |||
|
16 | hg qnew -mmqbase mqbase | |||
|
17 | ||||
|
18 | echo % qrefresh | |||
|
19 | echo 'patched' > base | |||
|
20 | hg qrefresh | |||
|
21 | ||||
|
22 | echo % qdiff | |||
|
23 | hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
24 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
|
25 | ||||
|
26 | echo % qdiff dirname | |||
|
27 | hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
28 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
@@ -0,0 +1,19 b'' | |||||
|
1 | % init | |||
|
2 | % commit | |||
|
3 | adding base | |||
|
4 | % qnew mqbase | |||
|
5 | % qrefresh | |||
|
6 | % qdiff | |||
|
7 | diff -r 67e992f2c4f3 base | |||
|
8 | --- a/base | |||
|
9 | +++ b/base | |||
|
10 | @@ -1,1 +1,1 @@ base | |||
|
11 | -base | |||
|
12 | +patched | |||
|
13 | % qdiff dirname | |||
|
14 | diff -r 67e992f2c4f3 base | |||
|
15 | --- a/base | |||
|
16 | +++ b/base | |||
|
17 | @@ -1,1 +1,1 @@ base | |||
|
18 | -base | |||
|
19 | +patched |
@@ -0,0 +1,15 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | hg init a | |||
|
8 | cd a | |||
|
9 | hg qnew first.patch | |||
|
10 | hg qnew first.patch | |||
|
11 | ||||
|
12 | touch ../first.patch | |||
|
13 | hg qimport ../first.patch | |||
|
14 | ||||
|
15 | exit 0 |
@@ -0,0 +1,2 b'' | |||||
|
1 | abort: patch "first.patch" already exists | |||
|
2 | abort: patch "first.patch" already exists |
@@ -0,0 +1,51 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | # Environement setup for MQ | |||
|
4 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
5 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
6 | echo "mq=" >> $HGTMP/.hgrc | |||
|
7 | ||||
|
8 | #Repo init | |||
|
9 | hg init | |||
|
10 | hg qinit | |||
|
11 | ||||
|
12 | hg qnew -m "First commit message" first-patch | |||
|
13 | echo aaaa > file | |||
|
14 | hg add file | |||
|
15 | hg qrefresh | |||
|
16 | echo ======================= | |||
|
17 | echo "Should display 'First commit message'" | |||
|
18 | hg log -l1 -v | sed -n '/description/,$p' | |||
|
19 | echo | |||
|
20 | ||||
|
21 | # Testing changing message with -m | |||
|
22 | echo bbbb > file | |||
|
23 | hg qrefresh -m "Second commit message" | |||
|
24 | echo ======================= | |||
|
25 | echo "Should display 'Second commit message'" | |||
|
26 | hg log -l1 -v | sed -n '/description/,$p' | |||
|
27 | echo | |||
|
28 | ||||
|
29 | ||||
|
30 | # Testing changing message with -l | |||
|
31 | echo "Third commit message" > logfile | |||
|
32 | echo " This is the 3rd log message" >> logfile | |||
|
33 | echo bbbb > file | |||
|
34 | hg qrefresh -l logfile | |||
|
35 | echo ======================= | |||
|
36 | printf "Should display 'Third commit message\\\n This is the 3rd log message'\n" | |||
|
37 | hg log -l1 -v | sed -n '/description/,$p' | |||
|
38 | echo | |||
|
39 | ||||
|
40 | # Testing changing message with -l- | |||
|
41 | hg qnew -m "First commit message" second-patch | |||
|
42 | echo aaaa > file2 | |||
|
43 | hg add file2 | |||
|
44 | echo bbbb > file2 | |||
|
45 | (echo "Fifth commit message" | |||
|
46 | echo " This is the 5th log message" >> logfile) |\ | |||
|
47 | hg qrefresh -l- | |||
|
48 | echo ======================= | |||
|
49 | printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n" | |||
|
50 | hg log -l1 -v | sed -n '/description/,$p' | |||
|
51 | echo |
@@ -0,0 +1,29 b'' | |||||
|
1 | ======================= | |||
|
2 | Should display 'First commit message' | |||
|
3 | description: | |||
|
4 | First commit message | |||
|
5 | ||||
|
6 | ||||
|
7 | ||||
|
8 | ======================= | |||
|
9 | Should display 'Second commit message' | |||
|
10 | description: | |||
|
11 | Second commit message | |||
|
12 | ||||
|
13 | ||||
|
14 | ||||
|
15 | ======================= | |||
|
16 | Should display 'Third commit message\n This is the 3rd log message' | |||
|
17 | description: | |||
|
18 | Third commit message | |||
|
19 | This is the 3rd log message | |||
|
20 | ||||
|
21 | ||||
|
22 | ||||
|
23 | ======================= | |||
|
24 | Should display 'Fifth commit message\n This is the 5th log message' | |||
|
25 | description: | |||
|
26 | Fifth commit message | |||
|
27 | ||||
|
28 | ||||
|
29 |
@@ -0,0 +1,16 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | HGRCPATH=$HGTMP/.hgrc; export HGRCPATH | |||
|
4 | echo "[extensions]" >> $HGTMP/.hgrc | |||
|
5 | echo "mq=" >> $HGTMP/.hgrc | |||
|
6 | ||||
|
7 | hg init a | |||
|
8 | cd a | |||
|
9 | ||||
|
10 | echo 'base' > base | |||
|
11 | hg ci -Ambase -d '1 0' | |||
|
12 | ||||
|
13 | hg qnew -mmqbase mqbase | |||
|
14 | ||||
|
15 | hg qsave | |||
|
16 | hg qrestore 2 |
@@ -0,0 +1,148 b'' | |||||
|
1 | % help | |||
|
2 | mq extension - patch management and development | |||
|
3 | ||||
|
4 | This extension lets you work with a stack of patches in a Mercurial | |||
|
5 | repository. It manages two stacks of patches - all known patches, and | |||
|
6 | applied patches (subset of known patches). | |||
|
7 | ||||
|
8 | Known patches are represented as patch files in the .hg/patches | |||
|
9 | directory. Applied patches are both patch files and changesets. | |||
|
10 | ||||
|
11 | Common tasks (use "hg help command" for more details): | |||
|
12 | ||||
|
13 | prepare repository to work with patches qinit | |||
|
14 | create new patch qnew | |||
|
15 | import existing patch qimport | |||
|
16 | ||||
|
17 | print patch series qseries | |||
|
18 | print applied patches qapplied | |||
|
19 | print name of top applied patch qtop | |||
|
20 | ||||
|
21 | add known patch to applied stack qpush | |||
|
22 | remove patch from applied stack qpop | |||
|
23 | refresh contents of top applied patch qrefresh | |||
|
24 | ||||
|
25 | list of commands (use "hg help -v mq" to show aliases and global options): | |||
|
26 | ||||
|
27 | qapplied print the patches already applied | |||
|
28 | qclone clone main and patch repository at same time | |||
|
29 | qcommit commit changes in the queue repository | |||
|
30 | qdelete remove patches from queue | |||
|
31 | qdiff diff of the current patch | |||
|
32 | qfold fold the named patches into the current patch | |||
|
33 | qguard set or print guards for a patch | |||
|
34 | qheader Print the header of the topmost or specified patch | |||
|
35 | qimport import a patch | |||
|
36 | qinit init a new queue repository | |||
|
37 | qnew create a new patch | |||
|
38 | qnext print the name of the next patch | |||
|
39 | qpop pop the current patch off the stack | |||
|
40 | qprev print the name of the previous patch | |||
|
41 | qpush push the next patch onto the stack | |||
|
42 | qrefresh update the current patch | |||
|
43 | qrename rename a patch | |||
|
44 | qrestore restore the queue state saved by a rev | |||
|
45 | qsave save current queue state | |||
|
46 | qselect set or print guarded patches to push | |||
|
47 | qseries print the entire series file | |||
|
48 | qtop print the name of the current patch | |||
|
49 | qunapplied print the patches not yet applied | |||
|
50 | strip strip a revision and all later revs on the same branch | |||
|
51 | adding a | |||
|
52 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
53 | adding b/z | |||
|
54 | % qinit | |||
|
55 | % -R qinit | |||
|
56 | % qinit -c | |||
|
57 | A .hgignore | |||
|
58 | A series | |||
|
59 | % qnew implies add | |||
|
60 | A .hgignore | |||
|
61 | A series | |||
|
62 | A test.patch | |||
|
63 | % qnew -m | |||
|
64 | foo bar | |||
|
65 | % qrefresh | |||
|
66 | foo bar | |||
|
67 | ||||
|
68 | diff -r xa | |||
|
69 | --- a/a | |||
|
70 | +++ b/a | |||
|
71 | @@ -1,1 +1,2 @@ a | |||
|
72 | a | |||
|
73 | +a | |||
|
74 | % qpop | |||
|
75 | Patch queue now empty | |||
|
76 | % qpush | |||
|
77 | applying test.patch | |||
|
78 | Now at: test.patch | |||
|
79 | % pop/push outside repo | |||
|
80 | Patch queue now empty | |||
|
81 | applying test.patch | |||
|
82 | Now at: test.patch | |||
|
83 | % qrefresh in subdir | |||
|
84 | % pop/push -a in subdir | |||
|
85 | Patch queue now empty | |||
|
86 | applying test.patch | |||
|
87 | applying test2.patch | |||
|
88 | Now at: test2.patch | |||
|
89 | % qseries | |||
|
90 | test.patch | |||
|
91 | test2.patch | |||
|
92 | % qapplied | |||
|
93 | test.patch | |||
|
94 | test2.patch | |||
|
95 | % qtop | |||
|
96 | test2.patch | |||
|
97 | % qprev | |||
|
98 | test.patch | |||
|
99 | % qnext | |||
|
100 | All patches applied | |||
|
101 | % pop, qnext, qprev, qapplied | |||
|
102 | Now at: test.patch | |||
|
103 | test2.patch | |||
|
104 | Only one patch applied | |||
|
105 | test.patch | |||
|
106 | % commit should fail | |||
|
107 | abort: cannot commit over an applied mq patch | |||
|
108 | % push should fail | |||
|
109 | pushing to ../../k | |||
|
110 | abort: source has mq patches applied | |||
|
111 | % qunapplied | |||
|
112 | test2.patch | |||
|
113 | % push should succeed | |||
|
114 | Patch queue now empty | |||
|
115 | pushing to ../../k | |||
|
116 | searching for changes | |||
|
117 | adding changesets | |||
|
118 | adding manifests | |||
|
119 | adding file changes | |||
|
120 | added 1 changesets with 1 changes to 1 files | |||
|
121 | % strip | |||
|
122 | adding x | |||
|
123 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
124 | saving bundle to | |||
|
125 | adding changesets | |||
|
126 | adding manifests | |||
|
127 | adding file changes | |||
|
128 | added 1 changesets with 1 changes to 1 files | |||
|
129 | (run 'hg update' to get a working copy) | |||
|
130 | new file | |||
|
131 | ||||
|
132 | diff --git a/new b/new | |||
|
133 | new file mode 100755 | |||
|
134 | --- /dev/null | |||
|
135 | +++ b/new | |||
|
136 | @@ -0,0 +1,1 @@ | |||
|
137 | +foo | |||
|
138 | copy file | |||
|
139 | ||||
|
140 | diff --git a/new b/copy | |||
|
141 | copy from new | |||
|
142 | copy to copy | |||
|
143 | Now at: new | |||
|
144 | applying copy | |||
|
145 | Now at: copy | |||
|
146 | diff --git a/new b/copy | |||
|
147 | copy from new | |||
|
148 | copy to copy |
@@ -1,1 +1,2 b'' | |||||
1 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A= |
|
1 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A= | |
|
2 | 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk= |
@@ -11,3 +11,4 b' 979c049974485125e1f9357f6bbe9c1b548a64c3' | |||||
11 | 3a56574f329a368d645853e0f9e09472aee62349 0.8 |
|
11 | 3a56574f329a368d645853e0f9e09472aee62349 0.8 | |
12 | 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1 |
|
12 | 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1 | |
13 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9 |
|
13 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9 | |
|
14 | 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1 |
@@ -4,6 +4,7 b' Goffredo Baroncelli <kreijack at libero.' | |||||
4 | Muli Ben-Yehuda <mulix at mulix.org> |
|
4 | Muli Ben-Yehuda <mulix at mulix.org> | |
5 | Mikael Berthe <mikael at lilotux.net> |
|
5 | Mikael Berthe <mikael at lilotux.net> | |
6 | Benoit Boissinot <bboissin at gmail.com> |
|
6 | Benoit Boissinot <bboissin at gmail.com> | |
|
7 | Brendan Cully <brendan at kublai.com> | |||
7 | Vincent Danjean <vdanjean.ml at free.fr> |
|
8 | Vincent Danjean <vdanjean.ml at free.fr> | |
8 | Jake Edge <jake at edge2.net> |
|
9 | Jake Edge <jake at edge2.net> | |
9 | Michael Fetterman <michael.fetterman at intel.com> |
|
10 | Michael Fetterman <michael.fetterman at intel.com> |
@@ -2,7 +2,7 b' include hg' | |||||
2 | recursive-include mercurial *.py |
|
2 | recursive-include mercurial *.py | |
3 | include hgweb.cgi hgwebdir.cgi |
|
3 | include hgweb.cgi hgwebdir.cgi | |
4 | include hgeditor rewrite-log |
|
4 | include hgeditor rewrite-log | |
5 |
include tests/README tests/ |
|
5 | include tests/README tests/*.py tests/test-*[a-z0-9] tests/*.out | |
6 | prune tests/*.err |
|
6 | prune tests/*.err | |
7 | include *.txt |
|
7 | include *.txt | |
8 | include templates/map templates/map-*[a-z0-9] |
|
8 | include templates/map templates/map-*[a-z0-9] | |
@@ -10,8 +10,10 b' include templates/*.tmpl' | |||||
10 | include templates/static/* |
|
10 | include templates/static/* | |
11 | include doc/README doc/Makefile doc/gendoc.py doc/*.txt doc/*.html doc/*.[0-9] |
|
11 | include doc/README doc/Makefile doc/gendoc.py doc/*.txt doc/*.html doc/*.[0-9] | |
12 | recursive-include contrib * |
|
12 | recursive-include contrib * | |
|
13 | recursive-include hgext * | |||
13 | include README |
|
14 | include README | |
14 | include CONTRIBUTORS |
|
15 | include CONTRIBUTORS | |
15 | include COPYING |
|
16 | include COPYING | |
16 | include Makefile |
|
17 | include Makefile | |
17 | include MANIFEST.in |
|
18 | include MANIFEST.in | |
|
19 | prune *.elc *.orig *.rej *~ *.o *.so *.pyc *.swp *.prof |
@@ -288,7 +288,7 b' complete -o bashdefault -o default -F _h' | |||||
288 |
|
288 | |||
289 | _hg_cmd_qdelete() |
|
289 | _hg_cmd_qdelete() | |
290 | { |
|
290 | { | |
291 |
_hg_ext_mq_patchlist q |
|
291 | _hg_ext_mq_patchlist qunapplied | |
292 | } |
|
292 | } | |
293 |
|
293 | |||
294 | _hg_cmd_qsave() |
|
294 | _hg_cmd_qsave() | |
@@ -313,6 +313,11 b' complete -o bashdefault -o default -F _h' | |||||
313 | COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) |
|
313 | COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) | |
314 | } |
|
314 | } | |
315 |
|
315 | |||
|
316 | _hg_cmd_export() | |||
|
317 | { | |||
|
318 | _hg_ext_mq_patchlist qapplied | |||
|
319 | } | |||
|
320 | ||||
316 |
|
321 | |||
317 | # hbisect |
|
322 | # hbisect | |
318 | _hg_cmd_bisect() |
|
323 | _hg_cmd_bisect() |
@@ -28,7 +28,8 b' class convert_git:' | |||||
28 | self.path = path |
|
28 | self.path = path | |
29 |
|
29 | |||
30 | def getheads(self): |
|
30 | def getheads(self): | |
31 | return [file(self.path + "/HEAD").read()[:-1]] |
|
31 | fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path) | |
|
32 | return [fh.read()[:-1]] | |||
32 |
|
33 | |||
33 | def catfile(self, rev, type): |
|
34 | def catfile(self, rev, type): | |
34 | if rev == "0" * 40: raise IOError() |
|
35 | if rev == "0" * 40: raise IOError() |
@@ -92,7 +92,7 b' def darcs_tip(darcs_repo):' | |||||
92 |
|
92 | |||
93 | def darcs_pull(hg_repo, darcs_repo, chash): |
|
93 | def darcs_pull(hg_repo, darcs_repo, chash): | |
94 | old_tip = darcs_tip(darcs_repo) |
|
94 | old_tip = darcs_tip(darcs_repo) | |
95 |
res = cmd("darcs pull |
|
95 | res = cmd("darcs pull \"%s\" --all --match=\"hash %s\"" % (darcs_repo, chash), hg_repo) | |
96 | print res |
|
96 | print res | |
97 | new_tip = darcs_tip(darcs_repo) |
|
97 | new_tip = darcs_tip(darcs_repo) | |
98 | if not new_tip != old_tip + 1: |
|
98 | if not new_tip != old_tip + 1: | |
@@ -110,7 +110,8 b' def hg_commit( hg_repo, text, author, da' | |||||
110 | old_tip = hg_tip(hg_repo) |
|
110 | old_tip = hg_tip(hg_repo) | |
111 | cmd("hg add -X _darcs", hg_repo) |
|
111 | cmd("hg add -X _darcs", hg_repo) | |
112 | cmd("hg remove -X _darcs --after", hg_repo) |
|
112 | cmd("hg remove -X _darcs --after", hg_repo) | |
113 |
res = cmd("hg commit -l %s -u |
|
113 | res = cmd("hg commit -l %s -u \"%s\" -d \"%s 0\"" % (tmpfile, author, date), hg_repo) | |
|
114 | os.close(fd) | |||
114 | os.unlink(tmpfile) |
|
115 | os.unlink(tmpfile) | |
115 | new_tip = hg_tip(hg_repo) |
|
116 | new_tip = hg_tip(hg_repo) | |
116 | if not new_tip == old_tip + 1: |
|
117 | if not new_tip == old_tip + 1: | |
@@ -156,7 +157,7 b' if __name__ == "__main__":' | |||||
156 | print "Given HG repository must not exist when no SKIP is specified." |
|
157 | print "Given HG repository must not exist when no SKIP is specified." | |
157 | sys.exit(-1) |
|
158 | sys.exit(-1) | |
158 | if skip == None: |
|
159 | if skip == None: | |
159 |
cmd("hg init |
|
160 | cmd("hg init \"%s\"" % (hg_repo)) | |
160 | cmd("darcs initialize", hg_repo) |
|
161 | cmd("darcs initialize", hg_repo) | |
161 | # Get the changes from the Darcs repository |
|
162 | # Get the changes from the Darcs repository | |
162 | change_number = 0 |
|
163 | change_number = 0 |
@@ -5,13 +5,73 b'' | |||||
5 | <meta http-equiv="Content-Style-Type" content="text/css"> |
|
5 | <meta http-equiv="Content-Style-Type" content="text/css"> | |
6 | <title></title> |
|
6 | <title></title> | |
7 | <style type="text/css"> |
|
7 | <style type="text/css"> | |
8 |
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 1 |
|
8 | p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica} | |
9 | p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px} |
|
9 | p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px} | |
10 | </style> |
|
10 | </style> | |
11 | </head> |
|
11 | </head> | |
12 | <body> |
|
12 | <body> | |
13 | <p class="p1">This is a prepackaged release of <a href="http://www.selenic.com/mercurial">Mercurial</a> for Mac OS X.</p> |
|
13 | <p class="p1">This is a prepackaged release of <a href="http://www.selenic.com/mercurial">Mercurial</a> for Mac OS X.</p> | |
14 | <p class="p2"><br></p> |
|
14 | <p class="p2"><br></p> | |
15 | <p class="p1">It is based on Mercurial 0.9.</p> |
|
15 | <p class="p1">It is based on Mercurial 0.9.1</p> | |
|
16 | <br> | |||
|
17 | <pre> | |||
|
18 | Release Notes | |||
|
19 | ------------- | |||
|
20 | ||||
|
21 | 2006-07-24 v0.9.1 | |||
|
22 | ||||
|
23 | Major changes between Mercurial 0.9 and 0.9.1: | |||
|
24 | ||||
|
25 | New features: | |||
|
26 | - You can now configure your 'hgweb' server to let remote users | |||
|
27 | 'push' changes over http. | |||
|
28 | - You can now 'import' a patch in a mail message by saving the mail | |||
|
29 | message, and importing it. This works for patches sent either | |||
|
30 | inline or as attachments. | |||
|
31 | - The 'diff' command now accepts '-rA:B' syntax as a synonym for | |||
|
32 | '-r A -r B', and adds '-b' and '-B' options. | |||
|
33 | ||||
|
34 | New contributions and extensions: | |||
|
35 | - The 'acl' extension lets you lock down parts of a repository | |||
|
36 | against incoming changes | |||
|
37 | - The 'extdiff' extension lets you run your favourite graphical | |||
|
38 | change viewer | |||
|
39 | - Comprehensive integration with the 'vim' editor | |||
|
40 | - A restricted shell for 'ssh'-hosted repositories | |||
|
41 | - An importer for 'darcs' repositories | |||
|
42 | ||||
|
43 | New hooks added: | |||
|
44 | - 'preupdate' is run before an update or merge in the working | |||
|
45 | directory. | |||
|
46 | - 'update' is run after an update or merge in the working | |||
|
47 | directory. | |||
|
48 | ||||
|
49 | Behaviour changes: | |||
|
50 | - NOTE: Mercurial as installed by the Windows binary | |||
|
51 | installer no longer performs automatic line-ending conversion for | |||
|
52 | Unix/Linux compatibility. To re-enable this feature, edit your | |||
|
53 | 'mercurial.ini' file after you upgrade. | |||
|
54 | - The Windows binary installer now automatically adds 'hg' to your | |||
|
55 | '%PATH%'. | |||
|
56 | - The 'backout' command now runs an editor by default, to let you | |||
|
57 | modify the commit message for a backed-out changeset. | |||
|
58 | - An earlier problem with parsing of tags has been fixed. | |||
|
59 | This makes tag parsing slower but more reliable. | |||
|
60 | ||||
|
61 | Memory usage and performance improvements: | |||
|
62 | - The 'remove' command has been rewritten to be hundreds of times | |||
|
63 | faster in large repositories. | |||
|
64 | - It is now possible to 'clone' a repository very quickly over a | |||
|
65 | LAN, if the server is configured to allow it. See the new 'server' | |||
|
66 | section in the 'hgrc' documentation. | |||
|
67 | ||||
|
68 | Other changes of note: | |||
|
69 | - Mercurial will now print help for an extension if you type 'hg | |||
|
70 | help EXT_NAME'. | |||
|
71 | - The usual array of bug fixes and documentation improvements. | |||
|
72 | - The integrated web server is now more WSGI-compliant. | |||
|
73 | - Work has begun to solidify Mercurial's API for use by third-party | |||
|
74 | packages. | |||
|
75 | </pre> | |||
16 | </body> |
|
76 | </body> | |
17 | </html> |
|
77 | </html> |
@@ -380,7 +380,9 b" Handle frickin' frackin' gratuitous even" | |||||
380 | (save-excursion |
|
380 | (save-excursion | |
381 | (while hg-prev-buffer |
|
381 | (while hg-prev-buffer | |
382 | (set-buffer hg-prev-buffer)) |
|
382 | (set-buffer hg-prev-buffer)) | |
383 | (let ((path (or default (buffer-file-name) default-directory))) |
|
383 | (let ((path (or default | |
|
384 | (buffer-file-name) | |||
|
385 | (expand-file-name default-directory)))) | |||
384 | (if (or (not path) current-prefix-arg) |
|
386 | (if (or (not path) current-prefix-arg) | |
385 | (expand-file-name |
|
387 | (expand-file-name | |
386 | (eval (list* 'read-file-name |
|
388 | (eval (list* 'read-file-name | |
@@ -716,7 +718,11 b' code by typing `M-x find-library mercuri' | |||||
716 | (goto-char pos) |
|
718 | (goto-char pos) | |
717 | (end-of-line 1) |
|
719 | (end-of-line 1) | |
718 | (delete-region pos (point))) |
|
720 | (delete-region pos (point))) | |
719 |
( |
|
721 | (let ((hg-root-dir (hg-root))) | |
|
722 | (if (not hg-root-dir) | |||
|
723 | (error "error: %s: directory is not part of a Mercurial repository." | |||
|
724 | default-directory) | |||
|
725 | (cd hg-root-dir))))) | |||
720 |
|
726 | |||
721 | (defun hg-add (path) |
|
727 | (defun hg-add (path) | |
722 | "Add PATH to the Mercurial repository on the next commit. |
|
728 | "Add PATH to the Mercurial repository on the next commit. | |
@@ -972,7 +978,8 b' With a prefix argument, prompt for the p' | |||||
972 | (cd (hg-root path))) |
|
978 | (cd (hg-root path))) | |
973 | (when update |
|
979 | (when update | |
974 | (with-current-buffer buf |
|
980 | (with-current-buffer buf | |
975 |
|
|
981 | (when (local-variable-p 'backup-inhibited) | |
|
982 | (kill-local-variable 'backup-inhibited)) | |||
976 | (hg-mode-line))))) |
|
983 | (hg-mode-line))))) | |
977 |
|
984 | |||
978 | (defun hg-incoming (&optional repo) |
|
985 | (defun hg-incoming (&optional repo) |
This diff has been collapsed as it changes many lines, (686 lines changed) Show them Hide them | |||||
@@ -3,7 +3,7 b'' | |||||
3 | " Vim plugin to assist in working with HG-controlled files. |
|
3 | " Vim plugin to assist in working with HG-controlled files. | |
4 | " |
|
4 | " | |
5 | " Last Change: 2006/02/22 |
|
5 | " Last Change: 2006/02/22 | |
6 |
" Version: 1.7 |
|
6 | " Version: 1.77 | |
7 | " Maintainer: Mathieu Clabaut <mathieu.clabaut@gmail.com> |
|
7 | " Maintainer: Mathieu Clabaut <mathieu.clabaut@gmail.com> | |
8 | " License: This file is placed in the public domain. |
|
8 | " License: This file is placed in the public domain. | |
9 | " Credits: |
|
9 | " Credits: | |
@@ -13,7 +13,7 b'' | |||||
13 |
|
13 | |||
14 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
|
14 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | |
15 | " |
|
15 | " | |
16 |
" Section: Documentation |
|
16 | " Section: Documentation | |
17 | "---------------------------- |
|
17 | "---------------------------- | |
18 | " |
|
18 | " | |
19 | " Documentation should be available by ":help hgcommand" command, once the |
|
19 | " Documentation should be available by ":help hgcommand" command, once the | |
@@ -21,7 +21,7 b'' | |||||
21 | " |
|
21 | " | |
22 | " You still can read the documentation at the end of this file. Locate it by |
|
22 | " You still can read the documentation at the end of this file. Locate it by | |
23 | " searching the "hgcommand-contents" string (and set ft=help to have |
|
23 | " searching the "hgcommand-contents" string (and set ft=help to have | |
24 |
" appropriate syntaxic coloration). |
|
24 | " appropriate syntaxic coloration). | |
25 |
|
25 | |||
26 | " Section: Plugin header {{{1 |
|
26 | " Section: Plugin header {{{1 | |
27 |
|
27 | |||
@@ -34,11 +34,33 b' if exists("loaded_hgcommand")' | |||||
34 | endif |
|
34 | endif | |
35 | let loaded_hgcommand = 1 |
|
35 | let loaded_hgcommand = 1 | |
36 |
|
36 | |||
|
37 | " store 'compatible' settings | |||
|
38 | let s:save_cpo = &cpo | |||
|
39 | set cpo&vim | |||
|
40 | ||||
|
41 | " run checks | |||
|
42 | let s:script_name = expand("<sfile>:t:r") | |||
|
43 | ||||
|
44 | function! s:HGCleanupOnFailure(err) | |||
|
45 | echohl WarningMsg | |||
|
46 | echomsg s:script_name . ":" a:err "Plugin not loaded" | |||
|
47 | echohl None | |||
|
48 | let loaded_hgcommand = "no" | |||
|
49 | unlet s:save_cpo s:script_name | |||
|
50 | endfunction | |||
|
51 | ||||
37 | if v:version < 602 |
|
52 | if v:version < 602 | |
38 | echohl WarningMsg|echomsg "HGCommand 1.69 or later requires VIM 6.2 or later"|echohl None |
|
53 | call <SID>HGCleanupOnFailure("VIM 6.2 or later required.") | |
39 | finish |
|
54 | finish | |
40 | endif |
|
55 | endif | |
41 |
|
56 | |||
|
57 | if !exists("*system") | |||
|
58 | call <SID>HGCleanupOnFailure("builtin system() function required.") | |||
|
59 | finish | |||
|
60 | endif | |||
|
61 | ||||
|
62 | let s:script_version = "v0.2" | |||
|
63 | ||||
42 | " Section: Event group setup {{{1 |
|
64 | " Section: Event group setup {{{1 | |
43 |
|
65 | |||
44 | augroup HGCommand |
|
66 | augroup HGCommand | |
@@ -63,7 +85,7 b' unlet! s:vimDiffScratchList' | |||||
63 | function! s:HGResolveLink(fileName) |
|
85 | function! s:HGResolveLink(fileName) | |
64 | let resolved = resolve(a:fileName) |
|
86 | let resolved = resolve(a:fileName) | |
65 | if resolved != a:fileName |
|
87 | if resolved != a:fileName | |
66 |
let resolved = |
|
88 | let resolved = <SID>HGResolveLink(resolved) | |
67 | endif |
|
89 | endif | |
68 | return resolved |
|
90 | return resolved | |
69 | endfunction |
|
91 | endfunction | |
@@ -74,7 +96,7 b' endfunction' | |||||
74 |
|
96 | |||
75 | function! s:HGChangeToCurrentFileDir(fileName) |
|
97 | function! s:HGChangeToCurrentFileDir(fileName) | |
76 | let oldCwd=getcwd() |
|
98 | let oldCwd=getcwd() | |
77 |
let fileName= |
|
99 | let fileName=<SID>HGResolveLink(a:fileName) | |
78 | let newCwd=fnamemodify(fileName, ':h') |
|
100 | let newCwd=fnamemodify(fileName, ':h') | |
79 | if strlen(newCwd) > 0 |
|
101 | if strlen(newCwd) > 0 | |
80 | execute 'cd' escape(newCwd, ' ') |
|
102 | execute 'cd' escape(newCwd, ' ') | |
@@ -82,7 +104,7 b' function! s:HGChangeToCurrentFileDir(fil' | |||||
82 | return oldCwd |
|
104 | return oldCwd | |
83 | endfunction |
|
105 | endfunction | |
84 |
|
106 | |||
85 |
" Function: |
|
107 | " Function: <SID>HGGetOption(name, default) {{{2 | |
86 | " Grab a user-specified option to override the default provided. Options are |
|
108 | " Grab a user-specified option to override the default provided. Options are | |
87 | " searched in the window, buffer, then global spaces. |
|
109 | " searched in the window, buffer, then global spaces. | |
88 |
|
110 | |||
@@ -110,9 +132,9 b' function! s:HGEditFile(name, origBuffNR)' | |||||
110 | "Name parameter will be pasted into expression. |
|
132 | "Name parameter will be pasted into expression. | |
111 | let name = escape(a:name, ' *?\') |
|
133 | let name = escape(a:name, ' *?\') | |
112 |
|
134 | |||
113 |
let editCommand = |
|
135 | let editCommand = <SID>HGGetOption('HGCommandEdit', 'edit') | |
114 | if editCommand != 'edit' |
|
136 | if editCommand != 'edit' | |
115 |
if |
|
137 | if <SID>HGGetOption('HGCommandSplit', 'horizontal') == 'horizontal' | |
116 | if name == "" |
|
138 | if name == "" | |
117 | let editCommand = 'rightbelow new' |
|
139 | let editCommand = 'rightbelow new' | |
118 | else |
|
140 | else | |
@@ -154,8 +176,8 b' function! s:HGCreateCommandBuffer(cmd, c' | |||||
154 |
|
176 | |||
155 | let resultBufferName='' |
|
177 | let resultBufferName='' | |
156 |
|
178 | |||
157 |
if |
|
179 | if <SID>HGGetOption("HGCommandNameResultBuffers", 0) | |
158 |
let nameMarker = |
|
180 | let nameMarker = <SID>HGGetOption("HGCommandNameMarker", '_') | |
159 | if strlen(a:statusText) > 0 |
|
181 | if strlen(a:statusText) > 0 | |
160 | let bufName=a:cmdName . ' -- ' . a:statusText |
|
182 | let bufName=a:cmdName . ' -- ' . a:statusText | |
161 | else |
|
183 | else | |
@@ -170,7 +192,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||||
170 | endwhile |
|
192 | endwhile | |
171 | endif |
|
193 | endif | |
172 |
|
194 | |||
173 |
let hgCommand = |
|
195 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " " . a:cmd | |
174 | "echomsg "DBG :".hgCommand |
|
196 | "echomsg "DBG :".hgCommand | |
175 | let hgOut = system(hgCommand) |
|
197 | let hgOut = system(hgCommand) | |
176 | " HACK: diff command does not return proper error codes |
|
198 | " HACK: diff command does not return proper error codes | |
@@ -192,7 +214,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||||
192 | return -1 |
|
214 | return -1 | |
193 | endif |
|
215 | endif | |
194 |
|
216 | |||
195 |
if |
|
217 | if <SID>HGEditFile(resultBufferName, a:origBuffNR) == -1 | |
196 | return -1 |
|
218 | return -1 | |
197 | endif |
|
219 | endif | |
198 |
|
220 | |||
@@ -200,7 +222,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||||
200 | set noswapfile |
|
222 | set noswapfile | |
201 | set filetype= |
|
223 | set filetype= | |
202 |
|
224 | |||
203 |
if |
|
225 | if <SID>HGGetOption("HGCommandDeleteOnHide", 0) | |
204 | set bufhidden=delete |
|
226 | set bufhidden=delete | |
205 | endif |
|
227 | endif | |
206 |
|
228 | |||
@@ -213,8 +235,8 b' function! s:HGCreateCommandBuffer(cmd, c' | |||||
213 | " This could be fixed by explicitly detecting whether the last line is |
|
235 | " This could be fixed by explicitly detecting whether the last line is | |
214 | " within a fold, but I prefer to simply unfold the result buffer altogether. |
|
236 | " within a fold, but I prefer to simply unfold the result buffer altogether. | |
215 |
|
237 | |||
216 |
if has( |
|
238 | if has("folding") | |
217 | normal zR |
|
239 | setlocal nofoldenable | |
218 | endif |
|
240 | endif | |
219 |
|
241 | |||
220 | $d |
|
242 | $d | |
@@ -243,7 +265,7 b' function! s:HGBufferCheck(hgBuffer)' | |||||
243 | return origBuffer |
|
265 | return origBuffer | |
244 | else |
|
266 | else | |
245 | " Original buffer no longer exists. |
|
267 | " Original buffer no longer exists. | |
246 |
return -1 |
|
268 | return -1 | |
247 | endif |
|
269 | endif | |
248 | else |
|
270 | else | |
249 | " No original buffer |
|
271 | " No original buffer | |
@@ -256,7 +278,7 b' endfunction' | |||||
256 | " for the current buffer. |
|
278 | " for the current buffer. | |
257 |
|
279 | |||
258 | function! s:HGCurrentBufferCheck() |
|
280 | function! s:HGCurrentBufferCheck() | |
259 |
return |
|
281 | return <SID>HGBufferCheck(bufnr("%")) | |
260 | endfunction |
|
282 | endfunction | |
261 |
|
283 | |||
262 | " Function: s:HGToggleDeleteOnHide() {{{2 |
|
284 | " Function: s:HGToggleDeleteOnHide() {{{2 | |
@@ -275,8 +297,8 b' endfunction' | |||||
275 | " Returns: name of the new command buffer containing the command results |
|
297 | " Returns: name of the new command buffer containing the command results | |
276 |
|
298 | |||
277 | function! s:HGDoCommand(cmd, cmdName, statusText) |
|
299 | function! s:HGDoCommand(cmd, cmdName, statusText) | |
278 |
let hgBufferCheck= |
|
300 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
279 |
if hgBufferCheck == -1 |
|
301 | if hgBufferCheck == -1 | |
280 | echo "Original buffer no longer exists, aborting." |
|
302 | echo "Original buffer no longer exists, aborting." | |
281 | return -1 |
|
303 | return -1 | |
282 | endif |
|
304 | endif | |
@@ -285,8 +307,8 b' function! s:HGDoCommand(cmd, cmdName, st' | |||||
285 | if isdirectory(fileName) |
|
307 | if isdirectory(fileName) | |
286 | let fileName=fileName . "/" . getline(".") |
|
308 | let fileName=fileName . "/" . getline(".") | |
287 | endif |
|
309 | endif | |
288 |
let realFileName = fnamemodify( |
|
310 | let realFileName = fnamemodify(<SID>HGResolveLink(fileName), ':t') | |
289 |
let oldCwd= |
|
311 | let oldCwd=<SID>HGChangeToCurrentFileDir(fileName) | |
290 | try |
|
312 | try | |
291 | " TODO |
|
313 | " TODO | |
292 | "if !filereadable('HG/Root') |
|
314 | "if !filereadable('HG/Root') | |
@@ -294,7 +316,7 b' function! s:HGDoCommand(cmd, cmdName, st' | |||||
294 | "endif |
|
316 | "endif | |
295 | let fullCmd = a:cmd . ' "' . realFileName . '"' |
|
317 | let fullCmd = a:cmd . ' "' . realFileName . '"' | |
296 | "echomsg "DEBUG".fullCmd |
|
318 | "echomsg "DEBUG".fullCmd | |
297 |
let resultBuffer= |
|
319 | let resultBuffer=<SID>HGCreateCommandBuffer(fullCmd, a:cmdName, a:statusText, hgBufferCheck) | |
298 | return resultBuffer |
|
320 | return resultBuffer | |
299 | catch |
|
321 | catch | |
300 | echoerr v:exception |
|
322 | echoerr v:exception | |
@@ -314,17 +336,17 b' endfunction' | |||||
314 | " Returns: string to be exec'd that sets the multiple return values. |
|
336 | " Returns: string to be exec'd that sets the multiple return values. | |
315 |
|
337 | |||
316 | function! s:HGGetStatusVars(revisionVar, branchVar, repositoryVar) |
|
338 | function! s:HGGetStatusVars(revisionVar, branchVar, repositoryVar) | |
317 |
let hgBufferCheck= |
|
339 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
318 | "echomsg "DBG : in HGGetStatusVars" |
|
340 | "echomsg "DBG : in HGGetStatusVars" | |
319 |
if hgBufferCheck == -1 |
|
341 | if hgBufferCheck == -1 | |
320 | return "" |
|
342 | return "" | |
321 | endif |
|
343 | endif | |
322 | let fileName=bufname(hgBufferCheck) |
|
344 | let fileName=bufname(hgBufferCheck) | |
323 |
let fileNameWithoutLink= |
|
345 | let fileNameWithoutLink=<SID>HGResolveLink(fileName) | |
324 | let realFileName = fnamemodify(fileNameWithoutLink, ':t') |
|
346 | let realFileName = fnamemodify(fileNameWithoutLink, ':t') | |
325 |
let oldCwd= |
|
347 | let oldCwd=<SID>HGChangeToCurrentFileDir(realFileName) | |
326 | try |
|
348 | try | |
327 |
let hgCommand = |
|
349 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " root " | |
328 | let roottext=system(hgCommand) |
|
350 | let roottext=system(hgCommand) | |
329 | " Suppress ending null char ! Does it work in window ? |
|
351 | " Suppress ending null char ! Does it work in window ? | |
330 | let roottext=substitute(roottext,'^.*/\([^/\n\r]*\)\n\_.*$','\1','') |
|
352 | let roottext=substitute(roottext,'^.*/\([^/\n\r]*\)\n\_.*$','\1','') | |
@@ -335,31 +357,31 b' function! s:HGGetStatusVars(revisionVar,' | |||||
335 | if a:repositoryVar != "" |
|
357 | if a:repositoryVar != "" | |
336 | let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . roottext . "'" |
|
358 | let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . roottext . "'" | |
337 | endif |
|
359 | endif | |
338 |
let hgCommand = |
|
360 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " status -mardui " . realFileName | |
339 | let statustext=system(hgCommand) |
|
361 | let statustext=system(hgCommand) | |
340 | if(v:shell_error) |
|
362 | if(v:shell_error) | |
341 | return "" |
|
363 | return "" | |
342 | endif |
|
364 | endif | |
343 |
if match(statustext, '^[?I]') >= 0 |
|
365 | if match(statustext, '^[?I]') >= 0 | |
344 | let revision="NEW" |
|
366 | let revision="NEW" | |
345 |
elseif match(statustext, '^[R]') >= 0 |
|
367 | elseif match(statustext, '^[R]') >= 0 | |
346 | let revision="REMOVED" |
|
368 | let revision="REMOVED" | |
347 |
elseif match(statustext, '^[D]') >= 0 |
|
369 | elseif match(statustext, '^[D]') >= 0 | |
348 | let revision="DELETED" |
|
370 | let revision="DELETED" | |
349 |
elseif match(statustext, '^[A]') >= 0 |
|
371 | elseif match(statustext, '^[A]') >= 0 | |
350 | let revision="ADDED" |
|
372 | let revision="ADDED" | |
351 | else |
|
373 | else | |
352 | " The file is tracked, we can try to get is revision number |
|
374 | " The file is tracked, we can try to get is revision number | |
353 |
let hgCommand = |
|
375 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " parents -b " | |
354 | let statustext=system(hgCommand) |
|
376 | let statustext=system(hgCommand) | |
355 | if(v:shell_error) |
|
377 | if(v:shell_error) | |
356 |
|
|
378 | return "" | |
357 | endif |
|
379 | endif | |
358 | let revision=substitute(statustext, '^changeset:\s*\(\d\+\):.*\_$\_.*$', '\1', "") |
|
380 | let revision=substitute(statustext, '^changeset:\s*\(\d\+\):.*\_$\_.*$', '\1', "") | |
359 |
|
381 | |||
360 | if a:branchVar != "" && match(statustext, '^\_.*\_^branch:') >= 0 |
|
382 | if a:branchVar != "" && match(statustext, '^\_.*\_^branch:') >= 0 | |
361 |
|
|
383 | let branch=substitute(statustext, '^\_.*\_^branch:\s*\(\S\+\)\n\_.*$', '\1', "") | |
362 |
|
|
384 | let returnExpression=returnExpression . " | let " . a:branchVar . "='" . branch . "'" | |
363 | endif |
|
385 | endif | |
364 | endif |
|
386 | endif | |
365 | if (exists('revision')) |
|
387 | if (exists('revision')) | |
@@ -381,7 +403,7 b' function! s:HGSetupBuffer(...)' | |||||
381 | return |
|
403 | return | |
382 | endif |
|
404 | endif | |
383 |
|
405 | |||
384 |
if ! |
|
406 | if !<SID>HGGetOption("HGCommandEnableBufferSetup", 0) | |
385 | \ || @% == "" |
|
407 | \ || @% == "" | |
386 | \ || s:HGCommandEditFileRunning > 0 |
|
408 | \ || s:HGCommandEditFileRunning > 0 | |
387 | \ || exists("b:HGOrigBuffNR") |
|
409 | \ || exists("b:HGOrigBuffNR") | |
@@ -399,7 +421,7 b' function! s:HGSetupBuffer(...)' | |||||
399 | let branch="" |
|
421 | let branch="" | |
400 | let repository="" |
|
422 | let repository="" | |
401 |
|
423 | |||
402 |
exec |
|
424 | exec <SID>HGGetStatusVars('revision', 'branch', 'repository') | |
403 | "echomsg "DBG ".revision."#".branch."#".repository |
|
425 | "echomsg "DBG ".revision."#".branch."#".repository | |
404 | if revision != "" |
|
426 | if revision != "" | |
405 | let b:HGRevision=revision |
|
427 | let b:HGRevision=revision | |
@@ -427,7 +449,7 b' endfunction' | |||||
427 | function! s:HGMarkOrigBufferForSetup(hgBuffer) |
|
449 | function! s:HGMarkOrigBufferForSetup(hgBuffer) | |
428 | checktime |
|
450 | checktime | |
429 | if a:hgBuffer != -1 |
|
451 | if a:hgBuffer != -1 | |
430 |
let origBuffer = |
|
452 | let origBuffer = <SID>HGBufferCheck(a:hgBuffer) | |
431 | "This should never not work, but I'm paranoid |
|
453 | "This should never not work, but I'm paranoid | |
432 | if origBuffer != a:hgBuffer |
|
454 | if origBuffer != a:hgBuffer | |
433 | call setbufvar(origBuffer, "HGBufferSetup", 0) |
|
455 | call setbufvar(origBuffer, "HGBufferSetup", 0) | |
@@ -436,7 +458,7 b' function! s:HGMarkOrigBufferForSetup(hgB' | |||||
436 | "We are presumably in the original buffer |
|
458 | "We are presumably in the original buffer | |
437 | let b:HGBufferSetup = 0 |
|
459 | let b:HGBufferSetup = 0 | |
438 | "We do the setup now as now event will be triggered allowing it later. |
|
460 | "We do the setup now as now event will be triggered allowing it later. | |
439 |
call |
|
461 | call <SID>HGSetupBuffer() | |
440 | endif |
|
462 | endif | |
441 | return a:hgBuffer |
|
463 | return a:hgBuffer | |
442 | endfunction |
|
464 | endfunction | |
@@ -478,111 +500,93 b' endfunction' | |||||
478 | " 1 if new document installed, 0 otherwise. |
|
500 | " 1 if new document installed, 0 otherwise. | |
479 | " Note: Cleaned and generalized by guo-peng Wen |
|
501 | " Note: Cleaned and generalized by guo-peng Wen | |
480 | "''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' |
|
502 | "''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
481 |
|
503 | " Helper function to make mkdir as portable as possible | ||
482 | function! s:HGInstallDocumentation(full_name, revision) |
|
504 | function! s:HGFlexiMkdir(dir) | |
483 | " Name of the document path based on the system we use: |
|
505 | if exists("*mkdir") " we can use Vim's own mkdir() | |
484 | if (has("unix")) |
|
506 | call mkdir(a:dir) | |
485 | " On UNIX like system, using forward slash: |
|
507 | elseif !exists("+shellslash") | |
486 | let l:slash_char = '/' |
|
508 | call system("mkdir -p '".a:dir."'") | |
487 | let l:mkdir_cmd = ':silent !mkdir -p ' |
|
509 | else " M$ | |
488 | else |
|
510 | let l:ssl = &shellslash | |
489 | " On M$ system, use backslash. Also mkdir syntax is different. |
|
511 | try | |
490 | " This should only work on W2K and up. |
|
512 | set shellslash | |
491 | let l:slash_char = '\' |
|
513 | " no single quotes? | |
492 | let l:mkdir_cmd = ':silent !mkdir ' |
|
514 | call system('mkdir "'.a:dir.'"') | |
493 | endif |
|
515 | finally | |
494 |
|
516 | let &shellslash = l:ssl | ||
495 | let l:doc_path = l:slash_char . 'doc' |
|
517 | endtry | |
496 | let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc' |
|
518 | endif | |
|
519 | endfunction | |||
497 |
|
520 | |||
498 | " Figure out document path based on full name of this script: |
|
521 | function! s:HGInstallDocumentation(full_name) | |
499 | let l:vim_plugin_path = fnamemodify(a:full_name, ':h') |
|
522 | " Figure out document path based on full name of this script: | |
500 |
|
|
523 | let l:vim_doc_path = fnamemodify(a:full_name, ":h:h") . "/doc" | |
501 |
|
|
524 | if filewritable(l:vim_doc_path) != 2 | |
502 | echomsg "Doc path: " . l:vim_doc_path |
|
525 | echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path | |
503 | execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' |
|
526 | silent! call <SID>HGFlexiMkdir(l:vim_doc_path) | |
504 |
|
|
527 | if filewritable(l:vim_doc_path) != 2 | |
505 | " Try a default configuration in user home: |
|
528 | " Try first item in 'runtimepath': | |
506 |
|
|
529 | let l:vim_doc_path = | |
507 | if (!(filewritable(l:vim_doc_path) == 2)) |
|
530 | \ substitute(&runtimepath, '^\([^,]*\).*', '\1/doc', 'e') | |
508 | execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' |
|
531 | if filewritable(l:vim_doc_path) != 2 | |
509 | if (!(filewritable(l:vim_doc_path) == 2)) |
|
532 | echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path | |
510 | " Put a warning: |
|
533 | silent! call <SID>HGFlexiMkdir(l:vim_doc_path) | |
511 | echomsg "Unable to open documentation directory" |
|
534 | if filewritable(l:vim_doc_path) != 2 | |
512 | echomsg " type :help add-local-help for more informations." |
|
535 | " Put a warning: | |
513 | return 0 |
|
536 | echomsg "Unable to open documentation directory" | |
514 | endif |
|
537 | echomsg " type `:help add-local-help' for more information." | |
515 |
|
|
538 | return 0 | |
516 | endif |
|
539 | endif | |
|
540 | endif | |||
517 | endif |
|
541 | endif | |
518 |
|
542 | endif | ||
519 | " Exit if we have problem to access the document directory: |
|
|||
520 | if (!isdirectory(l:vim_plugin_path) |
|
|||
521 | \ || !isdirectory(l:vim_doc_path) |
|
|||
522 | \ || filewritable(l:vim_doc_path) != 2) |
|
|||
523 | return 0 |
|
|||
524 | endif |
|
|||
525 |
|
||||
526 | " Full name of script and documentation file: |
|
|||
527 | let l:script_name = fnamemodify(a:full_name, ':t') |
|
|||
528 | let l:doc_name = fnamemodify(a:full_name, ':t:r') . '.txt' |
|
|||
529 | let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name |
|
|||
530 | let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name |
|
|||
531 |
|
543 | |||
532 | " Bail out if document file is still up to date: |
|
544 | " Full name of documentation file: | |
533 | if (filereadable(l:doc_file) && |
|
545 | let l:doc_file = | |
534 | \ getftime(l:plugin_file) < getftime(l:doc_file)) |
|
546 | \ l:vim_doc_path . "/" . s:script_name . ".txt" | |
535 | return 0 |
|
547 | " Bail out if document file is still up to date: | |
536 | endif |
|
548 | if filereadable(l:doc_file) && | |
|
549 | \ getftime(a:full_name) < getftime(l:doc_file) | |||
|
550 | return 0 | |||
|
551 | endif | |||
537 |
|
552 | |||
538 | " Prepare window position restoring command: |
|
553 | " temporary global settings | |
539 | if (strlen(@%)) |
|
554 | let l:lz = &lazyredraw | |
540 | let l:go_back = 'b ' . bufnr("%") |
|
555 | let l:hls = &hlsearch | |
541 | else |
|
556 | set lazyredraw nohlsearch | |
542 | let l:go_back = 'enew!' |
|
557 | " Create a new buffer & read in the plugin file (me): | |
543 | endif |
|
558 | 1 new | |
544 |
|
559 | setlocal noswapfile modifiable nomodeline | ||
545 | " Create a new buffer & read in the plugin file (me): |
|
560 | if has("folding") | |
546 |
setl no |
|
561 | setlocal nofoldenable | |
547 | exe 'enew!' |
|
562 | endif | |
548 | exe 'r ' . l:plugin_file |
|
563 | silent execute "read" escape(a:full_name, " ") | |
549 |
|
564 | let l:doc_buf = bufnr("%") | ||
550 | setl modeline |
|
|||
551 | let l:buf = bufnr("%") |
|
|||
552 | setl noswapfile modifiable |
|
|||
553 |
|
||||
554 | norm zR |
|
|||
555 | norm gg |
|
|||
556 |
|
565 | |||
557 | " Delete from first line to a line starts with |
|
566 | 1 | |
558 | " === START_DOC |
|
567 | " Delete from first line to a line starts with | |
559 | 1,/^=\{3,}\s\+START_DOC\C/ d |
|
568 | " === START_DOC | |
560 |
|
569 | silent 1,/^=\{3,}\s\+START_DOC\C/ d | ||
561 |
|
|
570 | " Delete from a line starts with | |
562 |
|
|
571 | " === END_DOC | |
563 |
|
|
572 | " to the end of the documents: | |
564 |
|
|
573 | silent /^=\{3,}\s\+END_DOC\C/,$ d | |
565 |
|
||||
566 | " Remove fold marks: |
|
|||
567 | %s/{\{3}[1-9]/ / |
|
|||
568 |
|
574 | |||
569 |
|
|
575 | " Add modeline for help doc: the modeline string is mangled intentionally | |
570 |
|
|
576 | " to avoid it be recognized by VIM: | |
571 |
|
|
577 | call append(line("$"), "") | |
572 |
|
|
578 | call append(line("$"), " v" . "im:tw=78:ts=8:ft=help:norl:") | |
573 |
|
||||
574 | " Replace revision: |
|
|||
575 | exe "normal :1s/#version#/ v" . a:revision . "/\<CR>" |
|
|||
576 |
|
579 | |||
577 | " Save the help document: |
|
580 | " Replace revision: | |
578 | exe 'w! ' . l:doc_file |
|
581 | silent execute "normal :1s/#version#/" . s:script_version . "/\<CR>" | |
579 | exe l:go_back |
|
582 | " Save the help document and wipe out buffer: | |
580 | exe 'bw ' . l:buf |
|
583 | silent execute "wq!" escape(l:doc_file, " ") "| bw" l:doc_buf | |
|
584 | " Build help tags: | |||
|
585 | silent execute "helptags" l:vim_doc_path | |||
581 |
|
586 | |||
582 | " Build help tags: |
|
587 | let &hlsearch = l:hls | |
583 | exe 'helptags ' . l:vim_doc_path |
|
588 | let &lazyredraw = l:lz | |
584 |
|
589 | return 1 | ||
585 | return 1 |
|
|||
586 | endfunction |
|
590 | endfunction | |
587 |
|
591 | |||
588 | " Section: Public functions {{{1 |
|
592 | " Section: Public functions {{{1 | |
@@ -593,7 +597,7 b' endfunction' | |||||
593 |
|
597 | |||
594 | function! HGGetRevision() |
|
598 | function! HGGetRevision() | |
595 | let revision="" |
|
599 | let revision="" | |
596 |
exec |
|
600 | exec <SID>HGGetStatusVars('revision', '', '') | |
597 | return revision |
|
601 | return revision | |
598 | endfunction |
|
602 | endfunction | |
599 |
|
603 | |||
@@ -612,16 +616,16 b' function! HGEnableBufferSetup()' | |||||
612 | let g:HGCommandEnableBufferSetup=1 |
|
616 | let g:HGCommandEnableBufferSetup=1 | |
613 | augroup HGCommandPlugin |
|
617 | augroup HGCommandPlugin | |
614 | au! |
|
618 | au! | |
615 |
au BufEnter * call |
|
619 | au BufEnter * call <SID>HGSetupBuffer() | |
616 |
au BufWritePost * call |
|
620 | au BufWritePost * call <SID>HGSetupBuffer() | |
617 | " Force resetting up buffer on external file change (HG update) |
|
621 | " Force resetting up buffer on external file change (HG update) | |
618 |
au FileChangedShell * call |
|
622 | au FileChangedShell * call <SID>HGSetupBuffer(1) | |
619 | augroup END |
|
623 | augroup END | |
620 |
|
624 | |||
621 | " Only auto-load if the plugin is fully loaded. This gives other plugins a |
|
625 | " Only auto-load if the plugin is fully loaded. This gives other plugins a | |
622 | " chance to run. |
|
626 | " chance to run. | |
623 | if g:loaded_hgcommand == 2 |
|
627 | if g:loaded_hgcommand == 2 | |
624 |
call |
|
628 | call <SID>HGSetupBuffer() | |
625 | endif |
|
629 | endif | |
626 | endfunction |
|
630 | endfunction | |
627 |
|
631 | |||
@@ -662,7 +666,7 b' endfunction' | |||||
662 |
|
666 | |||
663 | " Function: s:HGAdd() {{{2 |
|
667 | " Function: s:HGAdd() {{{2 | |
664 | function! s:HGAdd() |
|
668 | function! s:HGAdd() | |
665 |
return |
|
669 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('add', 'hgadd', '')) | |
666 | endfunction |
|
670 | endfunction | |
667 |
|
671 | |||
668 | " Function: s:HGAnnotate(...) {{{2 |
|
672 | " Function: s:HGAnnotate(...) {{{2 | |
@@ -672,7 +676,7 b' function! s:HGAnnotate(...)' | |||||
672 | " This is a HGAnnotate buffer. Perform annotation of the version |
|
676 | " This is a HGAnnotate buffer. Perform annotation of the version | |
673 | " indicated by the current line. |
|
677 | " indicated by the current line. | |
674 | let revision = substitute(getline("."),'\(^[0-9]*\):.*','\1','') |
|
678 | let revision = substitute(getline("."),'\(^[0-9]*\):.*','\1','') | |
675 |
if |
|
679 | if <SID>HGGetOption('HGCommandAnnotateParent', 0) != 0 && revision > 0 | |
676 | let revision = revision - 1 |
|
680 | let revision = revision - 1 | |
677 | endif |
|
681 | endif | |
678 | else |
|
682 | else | |
@@ -691,7 +695,7 b' function! s:HGAnnotate(...)' | |||||
691 | return -1 |
|
695 | return -1 | |
692 | endif |
|
696 | endif | |
693 |
|
697 | |||
694 |
let resultBuffer= |
|
698 | let resultBuffer=<SID>HGDoCommand('annotate -ndu -r ' . revision, 'hgannotate', revision) | |
695 | "echomsg "DBG: ".resultBuffer |
|
699 | "echomsg "DBG: ".resultBuffer | |
696 | if resultBuffer != -1 |
|
700 | if resultBuffer != -1 | |
697 | set filetype=HGAnnotate |
|
701 | set filetype=HGAnnotate | |
@@ -706,10 +710,10 b' function! s:HGCommit(...)' | |||||
706 | " is used; if bang is supplied, an empty message is used; otherwise, the |
|
710 | " is used; if bang is supplied, an empty message is used; otherwise, the | |
707 | " user is provided a buffer from which to edit the commit message. |
|
711 | " user is provided a buffer from which to edit the commit message. | |
708 | if a:2 != "" || a:1 == "!" |
|
712 | if a:2 != "" || a:1 == "!" | |
709 |
return |
|
713 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('commit -m "' . a:2 . '"', 'hgcommit', '')) | |
710 | endif |
|
714 | endif | |
711 |
|
715 | |||
712 |
let hgBufferCheck= |
|
716 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
713 | if hgBufferCheck == -1 |
|
717 | if hgBufferCheck == -1 | |
714 | echo "Original buffer no longer exists, aborting." |
|
718 | echo "Original buffer no longer exists, aborting." | |
715 | return -1 |
|
719 | return -1 | |
@@ -725,7 +729,7 b' function! s:HGCommit(...)' | |||||
725 | let messageFileName = tempname() |
|
729 | let messageFileName = tempname() | |
726 |
|
730 | |||
727 | let fileName=bufname(hgBufferCheck) |
|
731 | let fileName=bufname(hgBufferCheck) | |
728 |
let realFilePath= |
|
732 | let realFilePath=<SID>HGResolveLink(fileName) | |
729 | let newCwd=fnamemodify(realFilePath, ':h') |
|
733 | let newCwd=fnamemodify(realFilePath, ':h') | |
730 | if strlen(newCwd) == 0 |
|
734 | if strlen(newCwd) == 0 | |
731 | " Account for autochdir being in effect, which will make this blank, but |
|
735 | " Account for autochdir being in effect, which will make this blank, but | |
@@ -735,7 +739,7 b' function! s:HGCommit(...)' | |||||
735 |
|
739 | |||
736 | let realFileName=fnamemodify(realFilePath, ':t') |
|
740 | let realFileName=fnamemodify(realFilePath, ':t') | |
737 |
|
741 | |||
738 |
if |
|
742 | if <SID>HGEditFile(messageFileName, hgBufferCheck) == -1 | |
739 | return |
|
743 | return | |
740 | endif |
|
744 | endif | |
741 |
|
745 | |||
@@ -766,9 +770,9 b' function! s:HGCommit(...)' | |||||
766 | silent put =\"HG: Enter Log. Lines beginning with `HG:' are removed automatically\" |
|
770 | silent put =\"HG: Enter Log. Lines beginning with `HG:' are removed automatically\" | |
767 | silent put ='HG: Type <leader>cc (or your own <Plug>HGCommit mapping)' |
|
771 | silent put ='HG: Type <leader>cc (or your own <Plug>HGCommit mapping)' | |
768 |
|
772 | |||
769 |
if |
|
773 | if <SID>HGGetOption('HGCommandCommitOnWrite', 1) == 1 | |
770 | execute 'au HGCommit BufWritePre' autoPattern 'g/^HG:/d' |
|
774 | execute 'au HGCommit BufWritePre' autoPattern 'g/^HG:/d' | |
771 |
execute 'au HGCommit BufWritePost' autoPattern 'call |
|
775 | execute 'au HGCommit BufWritePost' autoPattern 'call <SID>HGFinishCommit("' . messageFileName . '", "' . newCwd . '", "' . realFileName . '", ' . hgBufferCheck . ') | au! * ' autoPattern | |
772 | silent put ='HG: or write this buffer' |
|
776 | silent put ='HG: or write this buffer' | |
773 | endif |
|
777 | endif | |
774 |
|
778 | |||
@@ -797,7 +801,7 b' function! s:HGDiff(...)' | |||||
797 | let caption = '' |
|
801 | let caption = '' | |
798 | endif |
|
802 | endif | |
799 |
|
803 | |||
800 |
let hgdiffopt= |
|
804 | let hgdiffopt=<SID>HGGetOption('HGCommandDiffOpt', 'w') | |
801 |
|
805 | |||
802 | if hgdiffopt == "" |
|
806 | if hgdiffopt == "" | |
803 | let diffoptionstring="" |
|
807 | let diffoptionstring="" | |
@@ -805,8 +809,8 b' function! s:HGDiff(...)' | |||||
805 | let diffoptionstring=" -" . hgdiffopt . " " |
|
809 | let diffoptionstring=" -" . hgdiffopt . " " | |
806 | endif |
|
810 | endif | |
807 |
|
811 | |||
808 |
let resultBuffer = |
|
812 | let resultBuffer = <SID>HGDoCommand('diff ' . diffoptionstring . revOptions , 'hgdiff', caption) | |
809 |
if resultBuffer != -1 |
|
813 | if resultBuffer != -1 | |
810 | set filetype=diff |
|
814 | set filetype=diff | |
811 | endif |
|
815 | endif | |
812 | return resultBuffer |
|
816 | return resultBuffer | |
@@ -815,7 +819,7 b' endfunction' | |||||
815 |
|
819 | |||
816 | " Function: s:HGGotoOriginal(["!]) {{{2 |
|
820 | " Function: s:HGGotoOriginal(["!]) {{{2 | |
817 | function! s:HGGotoOriginal(...) |
|
821 | function! s:HGGotoOriginal(...) | |
818 |
let origBuffNR = |
|
822 | let origBuffNR = <SID>HGCurrentBufferCheck() | |
819 | if origBuffNR > 0 |
|
823 | if origBuffNR > 0 | |
820 | let origWinNR = bufwinnr(origBuffNR) |
|
824 | let origWinNR = bufwinnr(origBuffNR) | |
821 | if origWinNR == -1 |
|
825 | if origWinNR == -1 | |
@@ -845,11 +849,11 b' function! s:HGFinishCommit(messageFile, ' | |||||
845 | if strlen(a:targetDir) > 0 |
|
849 | if strlen(a:targetDir) > 0 | |
846 | execute 'cd' escape(a:targetDir, ' ') |
|
850 | execute 'cd' escape(a:targetDir, ' ') | |
847 | endif |
|
851 | endif | |
848 |
let resultBuffer= |
|
852 | let resultBuffer=<SID>HGCreateCommandBuffer('commit -l "' . a:messageFile . '" "'. a:targetFile . '"', 'hgcommit', '', a:origBuffNR) | |
849 | execute 'cd' escape(oldCwd, ' ') |
|
853 | execute 'cd' escape(oldCwd, ' ') | |
850 | execute 'bw' escape(a:messageFile, ' *?\') |
|
854 | execute 'bw' escape(a:messageFile, ' *?\') | |
851 | silent execute 'call delete("' . a:messageFile . '")' |
|
855 | silent execute 'call delete("' . a:messageFile . '")' | |
852 |
return |
|
856 | return <SID>HGMarkOrigBufferForSetup(resultBuffer) | |
853 | else |
|
857 | else | |
854 | echoerr "Can't read message file; no commit is possible." |
|
858 | echoerr "Can't read message file; no commit is possible." | |
855 | return -1 |
|
859 | return -1 | |
@@ -866,7 +870,7 b' function! s:HGLog(...)' | |||||
866 | let caption = a:1 |
|
870 | let caption = a:1 | |
867 | endif |
|
871 | endif | |
868 |
|
872 | |||
869 |
let resultBuffer= |
|
873 | let resultBuffer=<SID>HGDoCommand('log' . versionOption, 'hglog', caption) | |
870 | if resultBuffer != "" |
|
874 | if resultBuffer != "" | |
871 | set filetype=rcslog |
|
875 | set filetype=rcslog | |
872 | endif |
|
876 | endif | |
@@ -875,14 +879,14 b' endfunction' | |||||
875 |
|
879 | |||
876 | " Function: s:HGRevert() {{{2 |
|
880 | " Function: s:HGRevert() {{{2 | |
877 | function! s:HGRevert() |
|
881 | function! s:HGRevert() | |
878 |
return |
|
882 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('revert', 'hgrevert', '')) | |
879 | endfunction |
|
883 | endfunction | |
880 |
|
884 | |||
881 | " Function: s:HGReview(...) {{{2 |
|
885 | " Function: s:HGReview(...) {{{2 | |
882 | function! s:HGReview(...) |
|
886 | function! s:HGReview(...) | |
883 | if a:0 == 0 |
|
887 | if a:0 == 0 | |
884 | let versiontag="" |
|
888 | let versiontag="" | |
885 |
if |
|
889 | if <SID>HGGetOption('HGCommandInteractive', 0) | |
886 | let versiontag=input('Revision: ') |
|
890 | let versiontag=input('Revision: ') | |
887 | endif |
|
891 | endif | |
888 | if versiontag == "" |
|
892 | if versiontag == "" | |
@@ -896,7 +900,7 b' function! s:HGReview(...)' | |||||
896 | let versionOption=" -r " . versiontag . " " |
|
900 | let versionOption=" -r " . versiontag . " " | |
897 | endif |
|
901 | endif | |
898 |
|
902 | |||
899 |
let resultBuffer = |
|
903 | let resultBuffer = <SID>HGDoCommand('cat' . versionOption, 'hgreview', versiontag) | |
900 | if resultBuffer > 0 |
|
904 | if resultBuffer > 0 | |
901 | let &filetype=getbufvar(b:HGOrigBuffNR, '&filetype') |
|
905 | let &filetype=getbufvar(b:HGOrigBuffNR, '&filetype') | |
902 | endif |
|
906 | endif | |
@@ -906,18 +910,18 b' endfunction' | |||||
906 |
|
910 | |||
907 | " Function: s:HGStatus() {{{2 |
|
911 | " Function: s:HGStatus() {{{2 | |
908 | function! s:HGStatus() |
|
912 | function! s:HGStatus() | |
909 |
return |
|
913 | return <SID>HGDoCommand('status', 'hgstatus', '') | |
910 | endfunction |
|
914 | endfunction | |
911 |
|
915 | |||
912 |
|
916 | |||
913 | " Function: s:HGUpdate() {{{2 |
|
917 | " Function: s:HGUpdate() {{{2 | |
914 | function! s:HGUpdate() |
|
918 | function! s:HGUpdate() | |
915 |
return |
|
919 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('update', 'update', '')) | |
916 | endfunction |
|
920 | endfunction | |
917 |
|
921 | |||
918 | " Function: s:HGVimDiff(...) {{{2 |
|
922 | " Function: s:HGVimDiff(...) {{{2 | |
919 | function! s:HGVimDiff(...) |
|
923 | function! s:HGVimDiff(...) | |
920 |
let originalBuffer = |
|
924 | let originalBuffer = <SID>HGCurrentBufferCheck() | |
921 | let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 |
|
925 | let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 | |
922 | try |
|
926 | try | |
923 | " If there's already a VimDiff'ed window, restore it. |
|
927 | " If there's already a VimDiff'ed window, restore it. | |
@@ -925,16 +929,16 b' function! s:HGVimDiff(...)' | |||||
925 |
|
929 | |||
926 | if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer |
|
930 | if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer | |
927 | " Clear the existing vimdiff setup by removing the result buffers. |
|
931 | " Clear the existing vimdiff setup by removing the result buffers. | |
928 |
call |
|
932 | call <SID>HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') | |
929 | endif |
|
933 | endif | |
930 |
|
934 | |||
931 | " Split and diff |
|
935 | " Split and diff | |
932 | if(a:0 == 2) |
|
936 | if(a:0 == 2) | |
933 | " Reset the vimdiff system, as 2 explicit versions were provided. |
|
937 | " Reset the vimdiff system, as 2 explicit versions were provided. | |
934 | if exists('s:vimDiffSourceBuffer') |
|
938 | if exists('s:vimDiffSourceBuffer') | |
935 |
call |
|
939 | call <SID>HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') | |
936 | endif |
|
940 | endif | |
937 |
let resultBuffer = |
|
941 | let resultBuffer = <SID>HGReview(a:1) | |
938 | if resultBuffer < 0 |
|
942 | if resultBuffer < 0 | |
939 | echomsg "Can't open HG revision " . a:1 |
|
943 | echomsg "Can't open HG revision " . a:1 | |
940 | return resultBuffer |
|
944 | return resultBuffer | |
@@ -945,10 +949,10 b' function! s:HGVimDiff(...)' | |||||
945 | let s:vimDiffScratchList = '{'. resultBuffer . '}' |
|
949 | let s:vimDiffScratchList = '{'. resultBuffer . '}' | |
946 | " If no split method is defined, cheat, and set it to vertical. |
|
950 | " If no split method is defined, cheat, and set it to vertical. | |
947 | try |
|
951 | try | |
948 |
call |
|
952 | call <SID>HGOverrideOption('HGCommandSplit', <SID>HGGetOption('HGCommandDiffSplit', <SID>HGGetOption('HGCommandSplit', 'vertical'))) | |
949 |
let resultBuffer= |
|
953 | let resultBuffer=<SID>HGReview(a:2) | |
950 | finally |
|
954 | finally | |
951 |
call |
|
955 | call <SID>HGOverrideOption('HGCommandSplit') | |
952 | endtry |
|
956 | endtry | |
953 | if resultBuffer < 0 |
|
957 | if resultBuffer < 0 | |
954 | echomsg "Can't open HG revision " . a:1 |
|
958 | echomsg "Can't open HG revision " . a:1 | |
@@ -962,16 +966,16 b' function! s:HGVimDiff(...)' | |||||
962 | " Add new buffer |
|
966 | " Add new buffer | |
963 | try |
|
967 | try | |
964 | " Force splitting behavior, otherwise why use vimdiff? |
|
968 | " Force splitting behavior, otherwise why use vimdiff? | |
965 |
call |
|
969 | call <SID>HGOverrideOption("HGCommandEdit", "split") | |
966 |
call |
|
970 | call <SID>HGOverrideOption("HGCommandSplit", <SID>HGGetOption('HGCommandDiffSplit', <SID>HGGetOption('HGCommandSplit', 'vertical'))) | |
967 | if(a:0 == 0) |
|
971 | if(a:0 == 0) | |
968 |
let resultBuffer= |
|
972 | let resultBuffer=<SID>HGReview() | |
969 | else |
|
973 | else | |
970 |
let resultBuffer= |
|
974 | let resultBuffer=<SID>HGReview(a:1) | |
971 | endif |
|
975 | endif | |
972 | finally |
|
976 | finally | |
973 |
call |
|
977 | call <SID>HGOverrideOption("HGCommandEdit") | |
974 |
call |
|
978 | call <SID>HGOverrideOption("HGCommandSplit") | |
975 | endtry |
|
979 | endtry | |
976 | if resultBuffer < 0 |
|
980 | if resultBuffer < 0 | |
977 | echomsg "Can't open current HG revision" |
|
981 | echomsg "Can't open current HG revision" | |
@@ -990,14 +994,14 b' function! s:HGVimDiff(...)' | |||||
990 | wincmd W |
|
994 | wincmd W | |
991 | execute 'buffer' originalBuffer |
|
995 | execute 'buffer' originalBuffer | |
992 | " Store info for later original buffer restore |
|
996 | " Store info for later original buffer restore | |
993 |
let s:vimDiffRestoreCmd = |
|
997 | let s:vimDiffRestoreCmd = | |
994 | \ "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")" |
|
998 | \ "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")" | |
995 | \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")" |
|
999 | \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")" | |
996 | \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")" |
|
1000 | \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")" | |
997 | \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')" |
|
1001 | \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')" | |
998 | \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")" |
|
1002 | \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")" | |
999 | \ . "|call setbufvar(".originalBuffer.", \"&wrap\", ".getbufvar(originalBuffer, '&wrap').")" |
|
1003 | \ . "|call setbufvar(".originalBuffer.", \"&wrap\", ".getbufvar(originalBuffer, '&wrap').")" | |
1000 | \ . "|if &foldmethod=='manual'|execute 'normal zE'|endif" |
|
1004 | \ . "|if &foldmethod=='manual'|execute 'normal! zE'|endif" | |
1001 | diffthis |
|
1005 | diffthis | |
1002 | wincmd w |
|
1006 | wincmd w | |
1003 | else |
|
1007 | else | |
@@ -1027,17 +1031,17 b' endfunction' | |||||
1027 |
|
1031 | |||
1028 | " Section: Command definitions {{{1 |
|
1032 | " Section: Command definitions {{{1 | |
1029 | " Section: Primary commands {{{2 |
|
1033 | " Section: Primary commands {{{2 | |
1030 |
com! HGAdd call |
|
1034 | com! HGAdd call <SID>HGAdd() | |
1031 |
com! -nargs=? HGAnnotate call |
|
1035 | com! -nargs=? HGAnnotate call <SID>HGAnnotate(<f-args>) | |
1032 |
com! -bang -nargs=? HGCommit call |
|
1036 | com! -bang -nargs=? HGCommit call <SID>HGCommit(<q-bang>, <q-args>) | |
1033 |
com! -nargs=* HGDiff call |
|
1037 | com! -nargs=* HGDiff call <SID>HGDiff(<f-args>) | |
1034 |
com! -bang HGGotoOriginal call |
|
1038 | com! -bang HGGotoOriginal call <SID>HGGotoOriginal(<q-bang>) | |
1035 |
com! -nargs=? HGLog call |
|
1039 | com! -nargs=? HGLog call <SID>HGLog(<f-args>) | |
1036 |
com! HGRevert call |
|
1040 | com! HGRevert call <SID>HGRevert() | |
1037 |
com! -nargs=? HGReview call |
|
1041 | com! -nargs=? HGReview call <SID>HGReview(<f-args>) | |
1038 |
com! HGStatus call |
|
1042 | com! HGStatus call <SID>HGStatus() | |
1039 |
com! HGUpdate call |
|
1043 | com! HGUpdate call <SID>HGUpdate() | |
1040 |
com! -nargs=* HGVimDiff call |
|
1044 | com! -nargs=* HGVimDiff call <SID>HGVimDiff(<f-args>) | |
1041 |
|
1045 | |||
1042 | " Section: HG buffer management commands {{{2 |
|
1046 | " Section: HG buffer management commands {{{2 | |
1043 | com! HGDisableBufferSetup call HGDisableBufferSetup() |
|
1047 | com! HGDisableBufferSetup call HGDisableBufferSetup() | |
@@ -1173,7 +1177,7 b' endfunction' | |||||
1173 |
|
1177 | |||
1174 | augroup HGVimDiffRestore |
|
1178 | augroup HGVimDiffRestore | |
1175 | au! |
|
1179 | au! | |
1176 |
au BufUnload * call |
|
1180 | au BufUnload * call <SID>HGVimDiffRestore(expand("<abuf>")) | |
1177 | augroup END |
|
1181 | augroup END | |
1178 |
|
1182 | |||
1179 | " Section: Optional activation of buffer management {{{1 |
|
1183 | " Section: Optional activation of buffer management {{{1 | |
@@ -1183,20 +1187,24 b" if s:HGGetOption('HGCommandEnableBufferS" | |||||
1183 | endif |
|
1187 | endif | |
1184 |
|
1188 | |||
1185 | " Section: Doc installation {{{1 |
|
1189 | " Section: Doc installation {{{1 | |
1186 | " |
|
|||
1187 | let s:revision="0.1" |
|
|||
1188 | silent! let s:install_status = |
|
|||
1189 | \ s:HGInstallDocumentation(expand('<sfile>:p'), s:revision) |
|
|||
1190 | if (s:install_status == 1) |
|
|||
1191 | echom expand("<sfile>:t:r") . ' v' . s:revision . |
|
|||
1192 | \ ': Help-documentation installed.' |
|
|||
1193 | endif |
|
|||
1194 |
|
1190 | |||
|
1191 | if <SID>HGInstallDocumentation(expand("<sfile>:p")) | |||
|
1192 | echomsg s:script_name s:script_version . ": updated documentation" | |||
|
1193 | endif | |||
1195 |
|
1194 | |||
1196 | " Section: Plugin completion {{{1 |
|
1195 | " Section: Plugin completion {{{1 | |
1197 |
|
1196 | |||
|
1197 | " delete one-time vars and functions | |||
|
1198 | delfunction <SID>HGInstallDocumentation | |||
|
1199 | delfunction <SID>HGFlexiMkdir | |||
|
1200 | delfunction <SID>HGCleanupOnFailure | |||
|
1201 | unlet s:script_version s:script_name | |||
|
1202 | ||||
1198 | let loaded_hgcommand=2 |
|
1203 | let loaded_hgcommand=2 | |
1199 | silent do HGCommand User HGPluginFinish |
|
1204 | silent do HGCommand User HGPluginFinish | |
|
1205 | ||||
|
1206 | let &cpo = s:save_cpo | |||
|
1207 | unlet s:save_cpo | |||
1200 | " vim:se expandtab sts=2 sw=2: |
|
1208 | " vim:se expandtab sts=2 sw=2: | |
1201 | finish |
|
1209 | finish | |
1202 |
|
1210 | |||
@@ -1228,16 +1236,16 b' 1. Contents\t\t\t\t\t\t *hgcommand-contents*' | |||||
1228 | ============================================================================== |
|
1236 | ============================================================================== | |
1229 | 2. HGCommand Installation *hgcommand-install* |
|
1237 | 2. HGCommand Installation *hgcommand-install* | |
1230 |
|
1238 | |||
1231 |
In order to install the plugin, place the hgcommand.vim file into a plugin' |
|
1239 | In order to install the plugin, place the hgcommand.vim file into a plugin' | |
1232 |
directory in your runtime path (please see |add-global-plugin| and |
|
1240 | directory in your runtime path (please see |add-global-plugin| and | |
1233 | |'runtimepath'|. |
|
1241 | |'runtimepath'|. | |
1234 |
|
1242 | |||
1235 |
HGCommand may be customized by setting variables, creating maps, and |
|
1243 | HGCommand may be customized by setting variables, creating maps, and | |
1236 | specifying event handlers. Please see |hgcommand-customize| for more |
|
1244 | specifying event handlers. Please see |hgcommand-customize| for more | |
1237 | details. |
|
1245 | details. | |
1238 |
|
1246 | |||
1239 | *hgcommand-auto-help* |
|
1247 | *hgcommand-auto-help* | |
1240 |
The help file is automagically generated when the |hgcommand| script is |
|
1248 | The help file is automagically generated when the |hgcommand| script is | |
1241 | loaded for the first time. |
|
1249 | loaded for the first time. | |
1242 |
|
1250 | |||
1243 | ============================================================================== |
|
1251 | ============================================================================== | |
@@ -1245,32 +1253,32 b' 2. HGCommand Installation\t\t\t\t *hgcomma' | |||||
1245 | 3. HGCommand Intro *hgcommand* |
|
1253 | 3. HGCommand Intro *hgcommand* | |
1246 | *hgcommand-intro* |
|
1254 | *hgcommand-intro* | |
1247 |
|
1255 | |||
1248 |
The HGCommand plugin provides global ex commands for manipulating |
|
1256 | The HGCommand plugin provides global ex commands for manipulating | |
1249 |
HG-controlled source files. In general, each command operates on the |
|
1257 | HG-controlled source files. In general, each command operates on the | |
1250 |
current buffer and accomplishes a separate hg function, such as update, |
|
1258 | current buffer and accomplishes a separate hg function, such as update, | |
1251 | commit, log, and others (please see |hgcommand-commands| for a list of all |
|
1259 | commit, log, and others (please see |hgcommand-commands| for a list of all | |
1252 |
available commands). The results of each operation are displayed in a |
|
1260 | available commands). The results of each operation are displayed in a | |
1253 |
scratch buffer. Several buffer variables are defined for those scratch |
|
1261 | scratch buffer. Several buffer variables are defined for those scratch | |
1254 | buffers (please see |hgcommand-buffer-variables|). |
|
1262 | buffers (please see |hgcommand-buffer-variables|). | |
1255 |
|
1263 | |||
1256 |
The notion of "current file" means either the current buffer, or, in the |
|
1264 | The notion of "current file" means either the current buffer, or, in the | |
1257 | case of a directory buffer, the file on the current line within the buffer. |
|
1265 | case of a directory buffer, the file on the current line within the buffer. | |
1258 |
|
1266 | |||
1259 |
For convenience, any HGCommand invoked on a HGCommand scratch buffer acts |
|
1267 | For convenience, any HGCommand invoked on a HGCommand scratch buffer acts | |
1260 |
as though it was invoked on the original file and splits the screen so that |
|
1268 | as though it was invoked on the original file and splits the screen so that | |
1261 | the output appears in a new window. |
|
1269 | the output appears in a new window. | |
1262 |
|
1270 | |||
1263 |
Many of the commands accept revisions as arguments. By default, most |
|
1271 | Many of the commands accept revisions as arguments. By default, most | |
1264 |
operate on the most recent revision on the current branch if no revision is |
|
1272 | operate on the most recent revision on the current branch if no revision is | |
1265 | specified (though see |HGCommandInteractive| to prompt instead). |
|
1273 | specified (though see |HGCommandInteractive| to prompt instead). | |
1266 |
|
1274 | |||
1267 |
Each HGCommand is mapped to a key sequence starting with the <Leader> |
|
1275 | Each HGCommand is mapped to a key sequence starting with the <Leader> | |
1268 |
keystroke. The default mappings may be overridden by supplying different |
|
1276 | keystroke. The default mappings may be overridden by supplying different | |
1269 |
mappings before the plugin is loaded, such as in the vimrc, in the standard |
|
1277 | mappings before the plugin is loaded, such as in the vimrc, in the standard | |
1270 |
fashion for plugin mappings. For examples, please see |
|
1278 | fashion for plugin mappings. For examples, please see | |
1271 | |hgcommand-mappings-override|. |
|
1279 | |hgcommand-mappings-override|. | |
1272 |
|
1280 | |||
1273 |
The HGCommand plugin may be configured in several ways. For more details, |
|
1281 | The HGCommand plugin may be configured in several ways. For more details, | |
1274 | please see |hgcommand-customize|. |
|
1282 | please see |hgcommand-customize|. | |
1275 |
|
1283 | |||
1276 | ============================================================================== |
|
1284 | ============================================================================== | |
@@ -1294,85 +1302,85 b' 4.1 HGCommand commands\t\t\t\t\t *hgcommand-' | |||||
1294 |
|
1302 | |||
1295 | :HGAdd *:HGAdd* |
|
1303 | :HGAdd *:HGAdd* | |
1296 |
|
1304 | |||
1297 |
This command performs "hg add" on the current file. Please note, this does |
|
1305 | This command performs "hg add" on the current file. Please note, this does | |
1298 | not commit the newly-added file. |
|
1306 | not commit the newly-added file. | |
1299 |
|
1307 | |||
1300 | :HGAnnotate *:HGAnnotate* |
|
1308 | :HGAnnotate *:HGAnnotate* | |
1301 |
|
1309 | |||
1302 |
This command performs "hg annotate" on the current file. If an argument is |
|
1310 | This command performs "hg annotate" on the current file. If an argument is | |
1303 |
given, the argument is used as a revision number to display. If not given |
|
1311 | given, the argument is used as a revision number to display. If not given | |
1304 |
an argument, it uses the most recent version of the file on the current |
|
1312 | an argument, it uses the most recent version of the file on the current | |
1305 |
branch. Additionally, if the current buffer is a HGAnnotate buffer |
|
1313 | branch. Additionally, if the current buffer is a HGAnnotate buffer | |
1306 | already, the version number on the current line is used. |
|
1314 | already, the version number on the current line is used. | |
1307 |
|
1315 | |||
1308 |
If the |HGCommandAnnotateParent| variable is set to a non-zero value, the |
|
1316 | If the |HGCommandAnnotateParent| variable is set to a non-zero value, the | |
1309 |
version previous to the one on the current line is used instead. This |
|
1317 | version previous to the one on the current line is used instead. This | |
1310 | allows one to navigate back to examine the previous version of a line. |
|
1318 | allows one to navigate back to examine the previous version of a line. | |
1311 |
|
1319 | |||
1312 |
The filetype of the HGCommand scratch buffer is set to 'HGAnnotate', to |
|
1320 | The filetype of the HGCommand scratch buffer is set to 'HGAnnotate', to | |
1313 | take advantage of the bundled syntax file. |
|
1321 | take advantage of the bundled syntax file. | |
1314 |
|
1322 | |||
1315 |
|
1323 | |||
1316 | :HGCommit[!] *:HGCommit* |
|
1324 | :HGCommit[!] *:HGCommit* | |
1317 |
|
1325 | |||
1318 |
If called with arguments, this performs "hg commit" using the arguments as |
|
1326 | If called with arguments, this performs "hg commit" using the arguments as | |
1319 | the log message. |
|
1327 | the log message. | |
1320 |
|
1328 | |||
1321 | If '!' is used with no arguments, an empty log message is committed. |
|
1329 | If '!' is used with no arguments, an empty log message is committed. | |
1322 |
|
1330 | |||
1323 |
If called with no arguments, this is a two-step command. The first step |
|
1331 | If called with no arguments, this is a two-step command. The first step | |
1324 |
opens a buffer to accept a log message. When that buffer is written, it is |
|
1332 | opens a buffer to accept a log message. When that buffer is written, it is | |
1325 |
automatically closed and the file is committed using the information from |
|
1333 | automatically closed and the file is committed using the information from | |
1326 |
that log message. The commit can be abandoned if the log message buffer is |
|
1334 | that log message. The commit can be abandoned if the log message buffer is | |
1327 | deleted or wiped before being written. |
|
1335 | deleted or wiped before being written. | |
1328 |
|
1336 | |||
1329 |
Alternatively, the mapping that is used to invoke :HGCommit (by default |
|
1337 | Alternatively, the mapping that is used to invoke :HGCommit (by default | |
1330 |
<Leader>hgc) can be used in the log message buffer to immediately commit. |
|
1338 | <Leader>hgc) can be used in the log message buffer to immediately commit. | |
1331 |
This is useful if the |HGCommandCommitOnWrite| variable is set to 0 to |
|
1339 | This is useful if the |HGCommandCommitOnWrite| variable is set to 0 to | |
1332 | disable the normal commit-on-write behavior. |
|
1340 | disable the normal commit-on-write behavior. | |
1333 |
|
1341 | |||
1334 | :HGDiff *:HGDiff* |
|
1342 | :HGDiff *:HGDiff* | |
1335 |
|
1343 | |||
1336 |
With no arguments, this performs "hg diff" on the current file against the |
|
1344 | With no arguments, this performs "hg diff" on the current file against the | |
1337 | current repository version. |
|
1345 | current repository version. | |
1338 |
|
1346 | |||
1339 |
With one argument, "hg diff" is performed on the current file against the |
|
1347 | With one argument, "hg diff" is performed on the current file against the | |
1340 | specified revision. |
|
1348 | specified revision. | |
1341 |
|
1349 | |||
1342 |
With two arguments, hg diff is performed between the specified revisions of |
|
1350 | With two arguments, hg diff is performed between the specified revisions of | |
1343 | the current file. |
|
1351 | the current file. | |
1344 |
|
1352 | |||
1345 |
This command uses the 'HGCommandDiffOpt' variable to specify diff options. |
|
1353 | This command uses the 'HGCommandDiffOpt' variable to specify diff options. | |
1346 |
If that variable does not exist, then 'wbBc' is assumed. If you wish to |
|
1354 | If that variable does not exist, then 'wbBc' is assumed. If you wish to | |
1347 | have no options, then set it to the empty string. |
|
1355 | have no options, then set it to the empty string. | |
1348 |
|
1356 | |||
1349 |
|
1357 | |||
1350 | :HGGotoOriginal *:HGGotoOriginal* |
|
1358 | :HGGotoOriginal *:HGGotoOriginal* | |
1351 |
|
1359 | |||
1352 |
This command returns the current window to the source buffer, if the |
|
1360 | This command returns the current window to the source buffer, if the | |
1353 | current buffer is a HG command output buffer. |
|
1361 | current buffer is a HG command output buffer. | |
1354 |
|
1362 | |||
1355 | :HGGotoOriginal! |
|
1363 | :HGGotoOriginal! | |
1356 |
|
1364 | |||
1357 |
Like ":HGGotoOriginal" but also executes :bufwipeout on all HG command |
|
1365 | Like ":HGGotoOriginal" but also executes :bufwipeout on all HG command | |
1358 | output buffers for the source buffer. |
|
1366 | output buffers for the source buffer. | |
1359 |
|
1367 | |||
1360 | :HGLog *:HGLog* |
|
1368 | :HGLog *:HGLog* | |
1361 |
|
1369 | |||
1362 | Performs "hg log" on the current file. |
|
1370 | Performs "hg log" on the current file. | |
1363 |
|
1371 | |||
1364 |
If an argument is given, it is passed as an argument to the "-r" option of |
|
1372 | If an argument is given, it is passed as an argument to the "-r" option of | |
1365 | "hg log". |
|
1373 | "hg log". | |
1366 |
|
1374 | |||
1367 | :HGRevert *:HGRevert* |
|
1375 | :HGRevert *:HGRevert* | |
1368 |
|
1376 | |||
1369 |
Replaces the current file with the most recent version from the repository |
|
1377 | Replaces the current file with the most recent version from the repository | |
1370 | in order to wipe out any undesired changes. |
|
1378 | in order to wipe out any undesired changes. | |
1371 |
|
1379 | |||
1372 | :HGReview *:HGReview* |
|
1380 | :HGReview *:HGReview* | |
1373 |
|
1381 | |||
1374 |
Retrieves a particular version of the current file. If no argument is |
|
1382 | Retrieves a particular version of the current file. If no argument is | |
1375 |
given, the most recent version of the file on the current branch is |
|
1383 | given, the most recent version of the file on the current branch is | |
1376 | retrieved. Otherwise, the specified version is retrieved. |
|
1384 | retrieved. Otherwise, the specified version is retrieved. | |
1377 |
|
1385 | |||
1378 | :HGStatus *:HGStatus* |
|
1386 | :HGStatus *:HGStatus* | |
@@ -1381,37 +1389,37 b' 4.1 HGCommand commands\t\t\t\t\t *hgcommand-' | |||||
1381 |
|
1389 | |||
1382 | :HGUpdate *:HGUpdate* |
|
1390 | :HGUpdate *:HGUpdate* | |
1383 |
|
1391 | |||
1384 |
Performs "hg update" on the current file. This intentionally does not |
|
1392 | Performs "hg update" on the current file. This intentionally does not | |
1385 |
automatically reload the current buffer, though vim should prompt the user |
|
1393 | automatically reload the current buffer, though vim should prompt the user | |
1386 | to do so if the underlying file is altered by this command. |
|
1394 | to do so if the underlying file is altered by this command. | |
1387 |
|
1395 | |||
1388 | :HGVimDiff *:HGVimDiff* |
|
1396 | :HGVimDiff *:HGVimDiff* | |
1389 |
|
1397 | |||
1390 |
With no arguments, this prompts the user for a revision and then uses |
|
1398 | With no arguments, this prompts the user for a revision and then uses | |
1391 |
vimdiff to display the differences between the current file and the |
|
1399 | vimdiff to display the differences between the current file and the | |
1392 |
specified revision. If no revision is specified, the most recent version |
|
1400 | specified revision. If no revision is specified, the most recent version | |
1393 | of the file on the current branch is used. |
|
1401 | of the file on the current branch is used. | |
1394 |
|
1402 | |||
1395 |
With one argument, that argument is used as the revision as above. With |
|
1403 | With one argument, that argument is used as the revision as above. With | |
1396 |
two arguments, the differences between the two revisions is displayed using |
|
1404 | two arguments, the differences between the two revisions is displayed using | |
1397 | vimdiff. |
|
1405 | vimdiff. | |
1398 |
|
1406 | |||
1399 |
With either zero or one argument, the original buffer is used to perform |
|
1407 | With either zero or one argument, the original buffer is used to perform | |
1400 |
the vimdiff. When the other buffer is closed, the original buffer will be |
|
1408 | the vimdiff. When the other buffer is closed, the original buffer will be | |
1401 | returned to normal mode. |
|
1409 | returned to normal mode. | |
1402 |
|
1410 | |||
1403 |
Once vimdiff mode is started using the above methods, additional vimdiff |
|
1411 | Once vimdiff mode is started using the above methods, additional vimdiff | |
1404 |
buffers may be added by passing a single version argument to the command. |
|
1412 | buffers may be added by passing a single version argument to the command. | |
1405 | There may be up to 4 vimdiff buffers total. |
|
1413 | There may be up to 4 vimdiff buffers total. | |
1406 |
|
1414 | |||
1407 |
Using the 2-argument form of the command resets the vimdiff to only those 2 |
|
1415 | Using the 2-argument form of the command resets the vimdiff to only those 2 | |
1408 |
versions. Additionally, invoking the command on a different file will |
|
1416 | versions. Additionally, invoking the command on a different file will | |
1409 | close the previous vimdiff buffers. |
|
1417 | close the previous vimdiff buffers. | |
1410 |
|
1418 | |||
1411 |
|
1419 | |||
1412 | 4.2 Mappings *hgcommand-mappings* |
|
1420 | 4.2 Mappings *hgcommand-mappings* | |
1413 |
|
1421 | |||
1414 |
By default, a mapping is defined for each command. These mappings execute |
|
1422 | By default, a mapping is defined for each command. These mappings execute | |
1415 | the default (no-argument) form of each command. |
|
1423 | the default (no-argument) form of each command. | |
1416 |
|
1424 | |||
1417 | <Leader>hga HGAdd |
|
1425 | <Leader>hga HGAdd | |
@@ -1428,20 +1436,20 b' 4.2 Mappings\t\t\t\t\t\t *hgcommand-mappings*' | |||||
1428 |
|
1436 | |||
1429 | *hgcommand-mappings-override* |
|
1437 | *hgcommand-mappings-override* | |
1430 |
|
1438 | |||
1431 |
The default mappings can be overriden by user-provided instead by mapping |
|
1439 | The default mappings can be overriden by user-provided instead by mapping | |
1432 |
to <Plug>CommandName. This is especially useful when these mappings |
|
1440 | to <Plug>CommandName. This is especially useful when these mappings | |
1433 |
collide with other existing mappings (vim will warn of this during plugin |
|
1441 | collide with other existing mappings (vim will warn of this during plugin | |
1434 | initialization, but will not clobber the existing mappings). |
|
1442 | initialization, but will not clobber the existing mappings). | |
1435 |
|
1443 | |||
1436 |
For instance, to override the default mapping for :HGAdd to set it to |
|
1444 | For instance, to override the default mapping for :HGAdd to set it to | |
1437 | '\add', add the following to the vimrc: > |
|
1445 | '\add', add the following to the vimrc: > | |
1438 |
|
1446 | |||
1439 | nmap \add <Plug>HGAdd |
|
1447 | nmap \add <Plug>HGAdd | |
1440 | < |
|
1448 | < | |
1441 | 4.3 Automatic buffer variables *hgcommand-buffer-variables* |
|
1449 | 4.3 Automatic buffer variables *hgcommand-buffer-variables* | |
1442 |
|
1450 | |||
1443 |
Several buffer variables are defined in each HGCommand result buffer. |
|
1451 | Several buffer variables are defined in each HGCommand result buffer. | |
1444 |
These may be useful for additional customization in callbacks defined in |
|
1452 | These may be useful for additional customization in callbacks defined in | |
1445 | the event handlers (please see |hgcommand-events|). |
|
1453 | the event handlers (please see |hgcommand-events|). | |
1446 |
|
1454 | |||
1447 | The following variables are automatically defined: |
|
1455 | The following variables are automatically defined: | |
@@ -1452,24 +1460,24 b' b:hgOrigBuffNR\t\t\t\t\t\t *b:hgOrigBuffN' | |||||
1452 |
|
1460 | |||
1453 | b:hgcmd *b:hgcmd* |
|
1461 | b:hgcmd *b:hgcmd* | |
1454 |
|
1462 | |||
1455 |
This variable is set to the name of the hg command that created the result |
|
1463 | This variable is set to the name of the hg command that created the result | |
1456 | buffer. |
|
1464 | buffer. | |
1457 | ============================================================================== |
|
1465 | ============================================================================== | |
1458 |
|
1466 | |||
1459 | 5. Configuration and customization *hgcommand-customize* |
|
1467 | 5. Configuration and customization *hgcommand-customize* | |
1460 | *hgcommand-config* |
|
1468 | *hgcommand-config* | |
1461 |
|
1469 | |||
1462 |
The HGCommand plugin can be configured in two ways: by setting |
|
1470 | The HGCommand plugin can be configured in two ways: by setting | |
1463 |
configuration variables (see |hgcommand-options|) or by defining HGCommand |
|
1471 | configuration variables (see |hgcommand-options|) or by defining HGCommand | |
1464 |
event handlers (see |hgcommand-events|). Additionally, the HGCommand |
|
1472 | event handlers (see |hgcommand-events|). Additionally, the HGCommand | |
1465 |
plugin provides several option for naming the HG result buffers (see |
|
1473 | plugin provides several option for naming the HG result buffers (see | |
1466 |
|hgcommand-naming|) and supported a customized status line (see |
|
1474 | |hgcommand-naming|) and supported a customized status line (see | |
1467 | |hgcommand-statusline| and |hgcommand-buffer-management|). |
|
1475 | |hgcommand-statusline| and |hgcommand-buffer-management|). | |
1468 |
|
1476 | |||
1469 | 5.1 HGCommand configuration variables *hgcommand-options* |
|
1477 | 5.1 HGCommand configuration variables *hgcommand-options* | |
1470 |
|
1478 | |||
1471 |
Several variables affect the plugin's behavior. These variables are |
|
1479 | Several variables affect the plugin's behavior. These variables are | |
1472 |
checked at time of execution, and may be defined at the window, buffer, or |
|
1480 | checked at time of execution, and may be defined at the window, buffer, or | |
1473 | global level and are checked in that order of precedence. |
|
1481 | global level and are checked in that order of precedence. | |
1474 |
|
1482 | |||
1475 |
|
1483 | |||
@@ -1490,87 +1498,87 b' 5.1 HGCommand configuration variables\t\t\t' | |||||
1490 |
|
1498 | |||
1491 | HGCommandAnnotateParent *HGCommandAnnotateParent* |
|
1499 | HGCommandAnnotateParent *HGCommandAnnotateParent* | |
1492 |
|
1500 | |||
1493 |
This variable, if set to a non-zero value, causes the zero-argument form of |
|
1501 | This variable, if set to a non-zero value, causes the zero-argument form of | |
1494 |
HGAnnotate when invoked on a HGAnnotate buffer to go to the version |
|
1502 | HGAnnotate when invoked on a HGAnnotate buffer to go to the version | |
1495 |
previous to that displayed on the current line. If not set, it defaults to |
|
1503 | previous to that displayed on the current line. If not set, it defaults to | |
1496 | 0. |
|
1504 | 0. | |
1497 |
|
1505 | |||
1498 | HGCommandCommitOnWrite *HGCommandCommitOnWrite* |
|
1506 | HGCommandCommitOnWrite *HGCommandCommitOnWrite* | |
1499 |
|
1507 | |||
1500 |
This variable, if set to a non-zero value, causes the pending hg commit to |
|
1508 | This variable, if set to a non-zero value, causes the pending hg commit to | |
1501 |
take place immediately as soon as the log message buffer is written. If |
|
1509 | take place immediately as soon as the log message buffer is written. If | |
1502 |
set to zero, only the HGCommit mapping will cause the pending commit to |
|
1510 | set to zero, only the HGCommit mapping will cause the pending commit to | |
1503 | occur. If not set, it defaults to 1. |
|
1511 | occur. If not set, it defaults to 1. | |
1504 |
|
1512 | |||
1505 | HGCommandHGExec *HGCommandHGExec* |
|
1513 | HGCommandHGExec *HGCommandHGExec* | |
1506 |
|
1514 | |||
1507 |
This variable controls the executable used for all HG commands. If not |
|
1515 | This variable controls the executable used for all HG commands. If not | |
1508 | set, it defaults to "hg". |
|
1516 | set, it defaults to "hg". | |
1509 |
|
1517 | |||
1510 | HGCommandDeleteOnHide *HGCommandDeleteOnHide* |
|
1518 | HGCommandDeleteOnHide *HGCommandDeleteOnHide* | |
1511 |
|
1519 | |||
1512 |
This variable, if set to a non-zero value, causes the temporary HG result |
|
1520 | This variable, if set to a non-zero value, causes the temporary HG result | |
1513 | buffers to automatically delete themselves when hidden. |
|
1521 | buffers to automatically delete themselves when hidden. | |
1514 |
|
1522 | |||
1515 | HGCommandDiffOpt *HGCommandDiffOpt* |
|
1523 | HGCommandDiffOpt *HGCommandDiffOpt* | |
1516 |
|
1524 | |||
1517 |
This variable, if set, determines the options passed to the diff command of |
|
1525 | This variable, if set, determines the options passed to the diff command of | |
1518 | HG. If not set, it defaults to 'w'. |
|
1526 | HG. If not set, it defaults to 'w'. | |
1519 |
|
1527 | |||
1520 | HGCommandDiffSplit *HGCommandDiffSplit* |
|
1528 | HGCommandDiffSplit *HGCommandDiffSplit* | |
1521 |
|
1529 | |||
1522 |
This variable overrides the |HGCommandSplit| variable, but only for buffers |
|
1530 | This variable overrides the |HGCommandSplit| variable, but only for buffers | |
1523 | created with |:HGVimDiff|. |
|
1531 | created with |:HGVimDiff|. | |
1524 |
|
1532 | |||
1525 | HGCommandEdit *HGCommandEdit* |
|
1533 | HGCommandEdit *HGCommandEdit* | |
1526 |
|
1534 | |||
1527 |
This variable controls whether the original buffer is replaced ('edit') or |
|
1535 | This variable controls whether the original buffer is replaced ('edit') or | |
1528 | split ('split'). If not set, it defaults to 'edit'. |
|
1536 | split ('split'). If not set, it defaults to 'edit'. | |
1529 |
|
1537 | |||
1530 | HGCommandEnableBufferSetup *HGCommandEnableBufferSetup* |
|
1538 | HGCommandEnableBufferSetup *HGCommandEnableBufferSetup* | |
1531 |
|
1539 | |||
1532 |
This variable, if set to a non-zero value, activates HG buffer management |
|
1540 | This variable, if set to a non-zero value, activates HG buffer management | |
1533 |
mode see (|hgcommand-buffer-management|). This mode means that three |
|
1541 | mode see (|hgcommand-buffer-management|). This mode means that three | |
1534 |
buffer variables, 'HGRepository', 'HGRevision' and 'HGBranch', are set if |
|
1542 | buffer variables, 'HGRepository', 'HGRevision' and 'HGBranch', are set if | |
1535 |
the file is HG-controlled. This is useful for displaying version |
|
1543 | the file is HG-controlled. This is useful for displaying version | |
1536 | information in the status bar. |
|
1544 | information in the status bar. | |
1537 |
|
1545 | |||
1538 | HGCommandInteractive *HGCommandInteractive* |
|
1546 | HGCommandInteractive *HGCommandInteractive* | |
1539 |
|
1547 | |||
1540 |
This variable, if set to a non-zero value, causes appropriate commands (for |
|
1548 | This variable, if set to a non-zero value, causes appropriate commands (for | |
1541 |
the moment, only |:HGReview|) to query the user for a revision to use |
|
1549 | the moment, only |:HGReview|) to query the user for a revision to use | |
1542 | instead of the current revision if none is specified. |
|
1550 | instead of the current revision if none is specified. | |
1543 |
|
1551 | |||
1544 | HGCommandNameMarker *HGCommandNameMarker* |
|
1552 | HGCommandNameMarker *HGCommandNameMarker* | |
1545 |
|
1553 | |||
1546 |
This variable, if set, configures the special attention-getting characters |
|
1554 | This variable, if set, configures the special attention-getting characters | |
1547 |
that appear on either side of the hg buffer type in the buffer name. This |
|
1555 | that appear on either side of the hg buffer type in the buffer name. This | |
1548 |
has no effect unless |HGCommandNameResultBuffers| is set to a true value. |
|
1556 | has no effect unless |HGCommandNameResultBuffers| is set to a true value. | |
1549 |
If not set, it defaults to '_'. |
|
1557 | If not set, it defaults to '_'. | |
1550 |
|
1558 | |||
1551 | HGCommandNameResultBuffers *HGCommandNameResultBuffers* |
|
1559 | HGCommandNameResultBuffers *HGCommandNameResultBuffers* | |
1552 |
|
1560 | |||
1553 |
This variable, if set to a true value, causes the hg result buffers to be |
|
1561 | This variable, if set to a true value, causes the hg result buffers to be | |
1554 |
named in the old way ('<source file name> _<hg command>_'). If not set or |
|
1562 | named in the old way ('<source file name> _<hg command>_'). If not set or | |
1555 | set to a false value, the result buffer is nameless. |
|
1563 | set to a false value, the result buffer is nameless. | |
1556 |
|
1564 | |||
1557 | HGCommandSplit *HGCommandSplit* |
|
1565 | HGCommandSplit *HGCommandSplit* | |
1558 |
|
1566 | |||
1559 |
This variable controls the orientation of the various window splits that |
|
1567 | This variable controls the orientation of the various window splits that | |
1560 |
may occur (such as with HGVimDiff, when using a HG command on a HG command |
|
1568 | may occur (such as with HGVimDiff, when using a HG command on a HG command | |
1561 |
buffer, or when the |HGCommandEdit| variable is set to 'split'. If set to |
|
1569 | buffer, or when the |HGCommandEdit| variable is set to 'split'. If set to | |
1562 |
'horizontal', the resulting windows will be on stacked on top of one |
|
1570 | 'horizontal', the resulting windows will be on stacked on top of one | |
1563 |
another. If set to 'vertical', the resulting windows will be side-by-side. |
|
1571 | another. If set to 'vertical', the resulting windows will be side-by-side. | |
1564 | If not set, it defaults to 'horizontal' for all but HGVimDiff windows. |
|
1572 | If not set, it defaults to 'horizontal' for all but HGVimDiff windows. | |
1565 |
|
1573 | |||
1566 | 5.2 HGCommand events *hgcommand-events* |
|
1574 | 5.2 HGCommand events *hgcommand-events* | |
1567 |
|
1575 | |||
1568 |
For additional customization, HGCommand can trigger user-defined events. |
|
1576 | For additional customization, HGCommand can trigger user-defined events. | |
1569 |
Event handlers are provided by defining User event autocommands (see |
|
1577 | Event handlers are provided by defining User event autocommands (see | |
1570 |
|autocommand|, |User|) in the HGCommand group with patterns matching the |
|
1578 | |autocommand|, |User|) in the HGCommand group with patterns matching the | |
1571 | event name. |
|
1579 | event name. | |
1572 |
|
1580 | |||
1573 |
For instance, the following could be added to the vimrc to provide a 'q' |
|
1581 | For instance, the following could be added to the vimrc to provide a 'q' | |
1574 | mapping to quit a HGCommand scratch buffer: > |
|
1582 | mapping to quit a HGCommand scratch buffer: > | |
1575 |
|
1583 | |||
1576 | augroup HGCommand |
|
1584 | augroup HGCommand | |
@@ -1582,10 +1590,10 b' 5.2 HGCommand events\t\t\t\t *hgc' | |||||
1582 | The following hooks are available: |
|
1590 | The following hooks are available: | |
1583 |
|
1591 | |||
1584 | HGBufferCreated This event is fired just after a hg command result |
|
1592 | HGBufferCreated This event is fired just after a hg command result | |
1585 |
buffer is created and filled with the result of a hg |
|
1593 | buffer is created and filled with the result of a hg | |
1586 |
command. It is executed within the context of the HG |
|
1594 | command. It is executed within the context of the HG | |
1587 |
command buffer. The HGCommand buffer variables may be |
|
1595 | command buffer. The HGCommand buffer variables may be | |
1588 |
useful for handlers of this event (please see |
|
1596 | useful for handlers of this event (please see | |
1589 | |hgcommand-buffer-variables|). |
|
1597 | |hgcommand-buffer-variables|). | |
1590 |
|
1598 | |||
1591 | HGBufferSetup This event is fired just after HG buffer setup occurs, |
|
1599 | HGBufferSetup This event is fired just after HG buffer setup occurs, | |
@@ -1598,50 +1606,50 b' HGPluginFinish\t\tThis event is fired just' | |||||
1598 | loads. |
|
1606 | loads. | |
1599 |
|
1607 | |||
1600 | HGVimDiffFinish This event is fired just after the HGVimDiff command |
|
1608 | HGVimDiffFinish This event is fired just after the HGVimDiff command | |
1601 |
executes to allow customization of, for instance, |
|
1609 | executes to allow customization of, for instance, | |
1602 | window placement and focus. |
|
1610 | window placement and focus. | |
1603 |
|
1611 | |||
1604 | 5.3 HGCommand buffer naming *hgcommand-naming* |
|
1612 | 5.3 HGCommand buffer naming *hgcommand-naming* | |
1605 |
|
1613 | |||
1606 |
By default, the buffers containing the result of HG commands are nameless |
|
1614 | By default, the buffers containing the result of HG commands are nameless | |
1607 |
scratch buffers. It is intended that buffer variables of those buffers be |
|
1615 | scratch buffers. It is intended that buffer variables of those buffers be | |
1608 |
used to customize the statusline option so that the user may fully control |
|
1616 | used to customize the statusline option so that the user may fully control | |
1609 | the display of result buffers. |
|
1617 | the display of result buffers. | |
1610 |
|
1618 | |||
1611 |
If the old-style naming is desired, please enable the |
|
1619 | If the old-style naming is desired, please enable the | |
1612 |
|HGCommandNameResultBuffers| variable. Then, each result buffer will |
|
1620 | |HGCommandNameResultBuffers| variable. Then, each result buffer will | |
1613 |
receive a unique name that includes the source file name, the HG command, |
|
1621 | receive a unique name that includes the source file name, the HG command, | |
1614 |
and any extra data (such as revision numbers) that were part of the |
|
1622 | and any extra data (such as revision numbers) that were part of the | |
1615 | command. |
|
1623 | command. | |
1616 |
|
1624 | |||
1617 | 5.4 HGCommand status line support *hgcommand-statusline* |
|
1625 | 5.4 HGCommand status line support *hgcommand-statusline* | |
1618 |
|
1626 | |||
1619 |
It is intended that the user will customize the |'statusline'| option to |
|
1627 | It is intended that the user will customize the |'statusline'| option to | |
1620 |
include HG result buffer attributes. A sample function that may be used in |
|
1628 | include HG result buffer attributes. A sample function that may be used in | |
1621 |
the |'statusline'| option is provided by the plugin, HGGetStatusLine(). In |
|
1629 | the |'statusline'| option is provided by the plugin, HGGetStatusLine(). In | |
1622 |
order to use that function in the status line, do something like the |
|
1630 | order to use that function in the status line, do something like the | |
1623 | following: > |
|
1631 | following: > | |
1624 |
|
1632 | |||
1625 | set statusline=%<%f\ %{HGGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P |
|
1633 | set statusline=%<%f\ %{HGGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P | |
1626 | < |
|
1634 | < | |
1627 | of which %{HGGetStatusLine()} is the relevant portion. |
|
1635 | of which %{HGGetStatusLine()} is the relevant portion. | |
1628 |
|
1636 | |||
1629 |
The sample HGGetStatusLine() function handles both HG result buffers and |
|
1637 | The sample HGGetStatusLine() function handles both HG result buffers and | |
1630 |
HG-managed files if HGCommand buffer management is enabled (please see |
|
1638 | HG-managed files if HGCommand buffer management is enabled (please see | |
1631 | |hgcommand-buffer-management|). |
|
1639 | |hgcommand-buffer-management|). | |
1632 |
|
1640 | |||
1633 | 5.5 HGCommand buffer management *hgcommand-buffer-management* |
|
1641 | 5.5 HGCommand buffer management *hgcommand-buffer-management* | |
1634 |
|
1642 | |||
1635 |
The HGCommand plugin can operate in buffer management mode, which means |
|
1643 | The HGCommand plugin can operate in buffer management mode, which means | |
1636 |
that it attempts to set two buffer variables ('HGRevision' and 'HGBranch') |
|
1644 | that it attempts to set two buffer variables ('HGRevision' and 'HGBranch') | |
1637 |
upon entry into a buffer. This is rather slow because it means that 'hg |
|
1645 | upon entry into a buffer. This is rather slow because it means that 'hg | |
1638 |
status' will be invoked at each entry into a buffer (during the |BufEnter| |
|
1646 | status' will be invoked at each entry into a buffer (during the |BufEnter| | |
1639 | autocommand). |
|
1647 | autocommand). | |
1640 |
|
1648 | |||
1641 |
This mode is enabl |
|
1649 | This mode is enabled by default. In order to disable it, set the | |
1642 |
|HGCommandEnableBufferSetup| variable to a false (zero) value. Enabling |
|
1650 | |HGCommandEnableBufferSetup| variable to a false (zero) value. Enabling | |
1643 |
this mode simply provides the buffer variables mentioned above. The user |
|
1651 | this mode simply provides the buffer variables mentioned above. The user | |
1644 |
must explicitly include those in the |'statusline'| option if they are to |
|
1652 | must explicitly include those in the |'statusline'| option if they are to | |
1645 | appear in the status line (but see |hgcommand-statusline| for a simple way |
|
1653 | appear in the status line (but see |hgcommand-statusline| for a simple way | |
1646 | to do that). |
|
1654 | to do that). | |
1647 |
|
1655 | |||
@@ -1655,10 +1663,10 b' 9.1 Split window annotation, by Michael ' | |||||
1655 | \:set nowrap<CR> |
|
1663 | \:set nowrap<CR> | |
1656 | < |
|
1664 | < | |
1657 |
|
1665 | |||
1658 |
This splits the buffer vertically, puts an annotation on the left (minus |
|
1666 | This splits the buffer vertically, puts an annotation on the left (minus | |
1659 |
the header) with the width set to 40. An editable/normal copy is placed on |
|
1667 | the header) with the width set to 40. An editable/normal copy is placed on | |
1660 |
the right. The two versions are scroll locked so they move as one. and |
|
1668 | the right. The two versions are scroll locked so they move as one. and | |
1661 |
wrapping is turned off so that the lines line up correctly. The advantages |
|
1669 | wrapping is turned off so that the lines line up correctly. The advantages | |
1662 | are... |
|
1670 | are... | |
1663 |
|
1671 | |||
1664 | 1) You get a versioning on the right. |
|
1672 | 1) You get a versioning on the right. | |
@@ -1671,9 +1679,9 b' 8. Known bugs\t\t\t\t\t\t *hgcommand-bugs' | |||||
1671 |
|
1679 | |||
1672 | Please let me know if you run across any. |
|
1680 | Please let me know if you run across any. | |
1673 |
|
1681 | |||
1674 |
HGVimDiff, when using the original (real) source buffer as one of the diff |
|
1682 | HGVimDiff, when using the original (real) source buffer as one of the diff | |
1675 |
buffers, uses some hacks to try to restore the state of the original buffer |
|
1683 | buffers, uses some hacks to try to restore the state of the original buffer | |
1676 |
when the scratch buffer containing the other version is destroyed. There |
|
1684 | when the scratch buffer containing the other version is destroyed. There | |
1677 | may still be bugs in here, depending on many configuration details. |
|
1685 | may still be bugs in here, depending on many configuration details. | |
1678 |
|
1686 | |||
1679 | ============================================================================== |
|
1687 | ============================================================================== | |
@@ -1686,4 +1694,4 b' 9. TODO \t\t\t\t\t\t *hgcommand-todo*' | |||||
1686 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
|
1694 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" | |
1687 | " v im:tw=78:ts=8:ft=help:norl: |
|
1695 | " v im:tw=78:ts=8:ft=help:norl: | |
1688 | " vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab : |
|
1696 | " vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab : | |
1689 |
"fileencoding=iso-8859-15 |
|
1697 | "fileencoding=iso-8859-15 |
@@ -14,7 +14,7 b'' | |||||
14 | </head> |
|
14 | </head> | |
15 |
|
15 | |||
16 | <body> |
|
16 | <body> | |
17 | <h1>Mercurial version 0.9 for Windows</h1> |
|
17 | <h1>Mercurial version 0.9.1 for Windows</h1> | |
18 |
|
18 | |||
19 | <p>Welcome to Mercurial for Windows!</p> |
|
19 | <p>Welcome to Mercurial for Windows!</p> | |
20 |
|
20 |
@@ -4,7 +4,7 b'' | |||||
4 | [Setup] |
|
4 | [Setup] | |
5 | AppCopyright=Copyright 2005, 2006 Matt Mackall and others |
|
5 | AppCopyright=Copyright 2005, 2006 Matt Mackall and others | |
6 | AppName=Mercurial |
|
6 | AppName=Mercurial | |
7 | AppVerName=Mercurial version 0.9 |
|
7 | AppVerName=Mercurial version 0.9.1 | |
8 | InfoAfterFile=contrib/win32/postinstall.txt |
|
8 | InfoAfterFile=contrib/win32/postinstall.txt | |
9 | LicenseFile=COPYING |
|
9 | LicenseFile=COPYING | |
10 | ShowLanguageDialog=yes |
|
10 | ShowLanguageDialog=yes | |
@@ -14,10 +14,10 b' AppSupportURL=http://www.selenic.com/mer' | |||||
14 | AppUpdatesURL=http://www.selenic.com/mercurial |
|
14 | AppUpdatesURL=http://www.selenic.com/mercurial | |
15 | AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} |
|
15 | AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} | |
16 | AppContact=mercurial@selenic.com |
|
16 | AppContact=mercurial@selenic.com | |
17 | OutputBaseFilename=Mercurial-0.9 |
|
17 | OutputBaseFilename=Mercurial-0.9.1 | |
18 | DefaultDirName={sd}\Mercurial |
|
18 | DefaultDirName={sd}\Mercurial | |
19 | SourceDir=C:\hg\hg-release |
|
19 | SourceDir=C:\hg\hg-release | |
20 | VersionInfoVersion=0.9 |
|
20 | VersionInfoVersion=0.9.1 | |
21 | VersionInfoDescription=Mercurial distributed SCM |
|
21 | VersionInfoDescription=Mercurial distributed SCM | |
22 | VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others |
|
22 | VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others | |
23 | VersionInfoCompany=Matt Mackall and others |
|
23 | VersionInfoCompany=Matt Mackall and others |
@@ -7,6 +7,62 b' file that comes with this package.' | |||||
7 | Release Notes |
|
7 | Release Notes | |
8 | ------------- |
|
8 | ------------- | |
9 |
|
9 | |||
|
10 | 2006-07-24 v0.9.1 | |||
|
11 | ||||
|
12 | Major changes between Mercurial 0.9 and 0.9.1: | |||
|
13 | ||||
|
14 | New features: | |||
|
15 | - You can now configure your 'hgweb' server to let remote users | |||
|
16 | 'push' changes over http. | |||
|
17 | - You can now 'import' a patch in a mail message by saving the mail | |||
|
18 | message, and importing it. This works for patches sent either | |||
|
19 | inline or as attachments. | |||
|
20 | - The 'diff' command now accepts '-rA:B' syntax as a synonym for | |||
|
21 | '-r A -r B', and adds '-b' and '-B' options. | |||
|
22 | ||||
|
23 | New contributions and extensions: | |||
|
24 | - The 'acl' extension lets you lock down parts of a repository | |||
|
25 | against incoming changes | |||
|
26 | - The 'extdiff' extension lets you run your favourite graphical | |||
|
27 | change viewer | |||
|
28 | - Comprehensive integration with the 'vim' editor | |||
|
29 | - A restricted shell for 'ssh'-hosted repositories | |||
|
30 | - An importer for 'darcs' repositories | |||
|
31 | ||||
|
32 | New hooks added: | |||
|
33 | - 'preupdate' is run before an update or merge in the working | |||
|
34 | directory. | |||
|
35 | - 'update' is run after an update or merge in the working | |||
|
36 | directory. | |||
|
37 | ||||
|
38 | Behaviour changes: | |||
|
39 | - NOTE: Mercurial as installed by the Windows binary | |||
|
40 | installer no longer performs automatic line-ending conversion for | |||
|
41 | Unix/Linux compatibility. To re-enable this feature, edit your | |||
|
42 | 'mercurial.ini' file after you upgrade. | |||
|
43 | - The Windows binary installer now automatically adds 'hg' to your | |||
|
44 | '%PATH%'. | |||
|
45 | - The 'backout' command now runs an editor by default, to let you | |||
|
46 | modify the commit message for a backed-out changeset. | |||
|
47 | - An earlier problem with parsing of tags has been fixed. | |||
|
48 | This makes tag parsing slower but more reliable. | |||
|
49 | ||||
|
50 | Memory usage and performance improvements: | |||
|
51 | - The 'remove' command has been rewritten to be hundreds of times | |||
|
52 | faster in large repositories. | |||
|
53 | - It is now possible to 'clone' a repository very quickly over a | |||
|
54 | LAN, if the server is configured to allow it. See the new 'server' | |||
|
55 | section in the 'hgrc' documentation. | |||
|
56 | ||||
|
57 | Other changes of note: | |||
|
58 | - Mercurial will now print help for an extension if you type 'hg | |||
|
59 | help EXT_NAME'. | |||
|
60 | - The usual array of bug fixes and documentation improvements. | |||
|
61 | - The integrated web server is now more WSGI-compliant. | |||
|
62 | - Work has begun to solidify Mercurial's API for use by third-party | |||
|
63 | packages. | |||
|
64 | ||||
|
65 | ||||
10 | 2006-05-10 v0.9 |
|
66 | 2006-05-10 v0.9 | |
11 |
|
67 | |||
12 | * Major changes between Mercurial 0.8.1 and 0.9: |
|
68 | * Major changes between Mercurial 0.8.1 and 0.9: |
@@ -216,6 +216,6 b' http://selenic.com/mailman/listinfo/merc' | |||||
216 |
|
216 | |||
217 | COPYING |
|
217 | COPYING | |
218 | ------- |
|
218 | ------- | |
219 | Copyright \(C) 2005 Matt Mackall. |
|
219 | Copyright \(C) 2005, 2006 Matt Mackall. | |
220 | Free use of this software is granted under the terms of the GNU General |
|
220 | Free use of this software is granted under the terms of the GNU General | |
221 | Public License (GPL). |
|
221 | Public License (GPL). |
@@ -30,6 +30,6 b' hg(1) - the command line interface to Me' | |||||
30 |
|
30 | |||
31 | COPYING |
|
31 | COPYING | |
32 | ------- |
|
32 | ------- | |
33 | Copyright \(C) 2005 Matt Mackall. |
|
33 | Copyright \(C) 2005, 2006 Matt Mackall. | |
34 | Free use of this software is granted under the terms of the GNU General |
|
34 | Free use of this software is granted under the terms of the GNU General | |
35 | Public License (GPL). |
|
35 | Public License (GPL). |
@@ -138,9 +138,17 b' email::' | |||||
138 | from;; |
|
138 | from;; | |
139 | Optional. Email address to use in "From" header and SMTP envelope |
|
139 | Optional. Email address to use in "From" header and SMTP envelope | |
140 | of outgoing messages. |
|
140 | of outgoing messages. | |
|
141 | to;; | |||
|
142 | Optional. Comma-separated list of recipients' email addresses. | |||
|
143 | cc;; | |||
|
144 | Optional. Comma-separated list of carbon copy recipients' | |||
|
145 | email addresses. | |||
|
146 | bcc;; | |||
|
147 | Optional. Comma-separated list of blind carbon copy | |||
|
148 | recipients' email addresses. Cannot be set interactively. | |||
141 | method;; |
|
149 | method;; | |
142 | Optional. Method to use to send email messages. If value is |
|
150 | Optional. Method to use to send email messages. If value is | |
143 |
"smtp" (default), use SMTP (see section "[ |
|
151 | "smtp" (default), use SMTP (see section "[smtp]" for | |
144 | configuration). Otherwise, use as name of program to run that |
|
152 | configuration). Otherwise, use as name of program to run that | |
145 | acts like sendmail (takes "-f" option for sender, list of |
|
153 | acts like sendmail (takes "-f" option for sender, list of | |
146 | recipients on command line, message on stdin). Normally, setting |
|
154 | recipients on command line, message on stdin). Normally, setting | |
@@ -194,7 +202,8 b' hooks::' | |||||
194 |
|
202 | |||
195 | changegroup;; |
|
203 | changegroup;; | |
196 | Run after a changegroup has been added via push, pull or |
|
204 | Run after a changegroup has been added via push, pull or | |
197 | unbundle. ID of the first new changeset is in $HG_NODE. |
|
205 | unbundle. ID of the first new changeset is in $HG_NODE. URL from | |
|
206 | which changes came is in $HG_URL. | |||
198 | commit;; |
|
207 | commit;; | |
199 | Run after a changeset has been created in the local repository. |
|
208 | Run after a changeset has been created in the local repository. | |
200 | ID of the newly created changeset is in $HG_NODE. Parent |
|
209 | ID of the newly created changeset is in $HG_NODE. Parent | |
@@ -202,7 +211,7 b' hooks::' | |||||
202 | incoming;; |
|
211 | incoming;; | |
203 | Run after a changeset has been pulled, pushed, or unbundled into |
|
212 | Run after a changeset has been pulled, pushed, or unbundled into | |
204 | the local repository. The ID of the newly arrived changeset is in |
|
213 | the local repository. The ID of the newly arrived changeset is in | |
205 | $HG_NODE. |
|
214 | $HG_NODE. URL that was source of changes came is in $HG_URL. | |
206 | outgoing;; |
|
215 | outgoing;; | |
207 | Run after sending changes from local repository to another. ID of |
|
216 | Run after sending changes from local repository to another. ID of | |
208 | first changeset sent is in $HG_NODE. Source of operation is in |
|
217 | first changeset sent is in $HG_NODE. Source of operation is in | |
@@ -210,7 +219,8 b' hooks::' | |||||
210 | prechangegroup;; |
|
219 | prechangegroup;; | |
211 | Run before a changegroup is added via push, pull or unbundle. |
|
220 | Run before a changegroup is added via push, pull or unbundle. | |
212 | Exit status 0 allows the changegroup to proceed. Non-zero status |
|
221 | Exit status 0 allows the changegroup to proceed. Non-zero status | |
213 | will cause the push, pull or unbundle to fail. |
|
222 | will cause the push, pull or unbundle to fail. URL from which | |
|
223 | changes will come is in $HG_URL. | |||
214 | precommit;; |
|
224 | precommit;; | |
215 | Run before starting a local commit. Exit status 0 allows the |
|
225 | Run before starting a local commit. Exit status 0 allows the | |
216 | commit to proceed. Non-zero status will cause the commit to fail. |
|
226 | commit to proceed. Non-zero status will cause the commit to fail. | |
@@ -236,7 +246,8 b' hooks::' | |||||
236 | before accepting them. Passed the ID of the first new changeset |
|
246 | before accepting them. Passed the ID of the first new changeset | |
237 | in $HG_NODE. Exit status 0 allows the transaction to commit. |
|
247 | in $HG_NODE. Exit status 0 allows the transaction to commit. | |
238 | Non-zero status will cause the transaction to be rolled back and |
|
248 | Non-zero status will cause the transaction to be rolled back and | |
239 | the push, pull or unbundle will fail. |
|
249 | the push, pull or unbundle will fail. URL that was source of | |
|
250 | changes is in $HG_URL. | |||
240 | pretxncommit;; |
|
251 | pretxncommit;; | |
241 | Run after a changeset has been created but the transaction not yet |
|
252 | Run after a changeset has been created but the transaction not yet | |
242 | committed. Changeset is visible to hook program. This lets you |
|
253 | committed. Changeset is visible to hook program. This lets you | |
@@ -295,7 +306,7 b' http_proxy::' | |||||
295 | smtp:: |
|
306 | smtp:: | |
296 | Configuration for extensions that need to send email messages. |
|
307 | Configuration for extensions that need to send email messages. | |
297 | host;; |
|
308 | host;; | |
298 |
|
|
309 | Host name of mail server, e.g. "mail.example.com". | |
299 | port;; |
|
310 | port;; | |
300 | Optional. Port to connect to on mail server. Default: 25. |
|
311 | Optional. Port to connect to on mail server. Default: 25. | |
301 | tls;; |
|
312 | tls;; | |
@@ -440,6 +451,9 b' web::' | |||||
440 | push_ssl;; |
|
451 | push_ssl;; | |
441 | Whether to require that inbound pushes be transported over SSL to |
|
452 | Whether to require that inbound pushes be transported over SSL to | |
442 | prevent password sniffing. Default is true. |
|
453 | prevent password sniffing. Default is true. | |
|
454 | stripes;; | |||
|
455 | How many lines a "zebra stripe" should span in multiline output. | |||
|
456 | Default is 1; set to 0 to disable. | |||
443 | style;; |
|
457 | style;; | |
444 | Which template map style to use. |
|
458 | Which template map style to use. | |
445 | templates;; |
|
459 | templates;; |
@@ -862,6 +862,6 b' http://selenic.com/mailman/listinfo/mercurial[\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xb0\xe3\x83\xaa\xe3\x82\xb9\xe3\x83\x88]' | |||||
862 |
|
862 | |||
863 | 著作権情報 |
|
863 | 著作権情報 | |
864 | ----- |
|
864 | ----- | |
865 | Copyright (C) 2005 Matt Mackall. |
|
865 | Copyright (C) 2005, 2006 Matt Mackall. | |
866 | このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで |
|
866 | このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで | |
867 | 認められます。 |
|
867 | 認められます。 |
@@ -32,6 +32,6 b' hg(1) - Mercurial \xe3\x82\xb7\xe3\x82\xb9\xe3\x83\x86\xe3\x83\xa0\xe3\x81\xb8\xe3\x81\xae\xe3\x82\xb3\xe3\x83\x9e\xe3\x83\xb3\xe3\x83\x89\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x95\xe3\x82\xa7\xe3\x82\xa4\xe3\x82\xb9' | |||||
32 |
|
32 | |||
33 | 著作権情報 |
|
33 | 著作権情報 | |
34 | ---- |
|
34 | ---- | |
35 | Copyright (C) 2005 Matt Mackall. |
|
35 | Copyright (C) 2005, 2006 Matt Mackall. | |
36 | このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで |
|
36 | このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで | |
37 | 認められます。 |
|
37 | 認められます。 |
@@ -5,34 +5,49 b'' | |||||
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
7 | # |
|
7 | # | |
8 | # allow to use external programs to compare revisions, or revision |
|
8 | # The `extdiff' Mercurial extension allows you to use external programs | |
9 | # with working dir. program is called with two arguments: paths to |
|
9 | # to compare revisions, or revision with working dir. The external diff | |
10 | # directories containing snapshots of files to compare. |
|
10 | # programs are called with a configurable set of options and two | |
|
11 | # non-option arguments: paths to directories containing snapshots of | |||
|
12 | # files to compare. | |||
11 | # |
|
13 | # | |
12 | # to enable: |
|
14 | # To enable this extension: | |
13 | # |
|
15 | # | |
14 | # [extensions] |
|
16 | # [extensions] | |
15 | # hgext.extdiff = |
|
17 | # hgext.extdiff = | |
16 | # |
|
18 | # | |
17 |
# also allows to configure new diff commands, so |
|
19 | # The `extdiff' extension also allows to configure new diff commands, so | |
18 | # type "hg extdiff -p kdiff3" always. |
|
20 | # you do not need to type "hg extdiff -p kdiff3" always. | |
19 | # |
|
21 | # | |
20 | # [extdiff] |
|
22 | # [extdiff] | |
|
23 | # # add new command that runs GNU diff(1) in 'context diff' mode | |||
|
24 | # cmd.cdiff = gdiff | |||
|
25 | # opts.cdiff = -Nprc5 | |||
21 | # # add new command called vdiff, runs kdiff3 |
|
26 | # # add new command called vdiff, runs kdiff3 | |
22 | # cmd.vdiff = kdiff3 |
|
27 | # cmd.vdiff = kdiff3 | |
23 | # # add new command called meld, runs meld (no need to name twice) |
|
28 | # # add new command called meld, runs meld (no need to name twice) | |
24 | # cmd.meld = |
|
29 | # cmd.meld = | |
|
30 | # # add new command called vimdiff, runs gvimdiff with DirDiff plugin | |||
|
31 | # #(see http://www.vim.org/scripts/script.php?script_id=102) | |||
|
32 | # cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)' | |||
25 | # |
|
33 | # | |
26 | # you can use -I/-X and list of file or directory names like normal |
|
34 | # Each custom diff commands can have two parts: a `cmd' and an `opts' | |
27 | # "hg diff" command. extdiff makes snapshots of only needed files, so |
|
35 | # part. The cmd.xxx option defines the name of an executable program | |
28 | # compare program will be fast. |
|
36 | # that will be run, and opts.xxx defines a set of command-line options | |
|
37 | # which will be inserted to the command between the program name and | |||
|
38 | # the files/directories to diff (i.e. the cdiff example above). | |||
|
39 | # | |||
|
40 | # You can use -I/-X and list of file or directory names like normal | |||
|
41 | # "hg diff" command. The `extdiff' extension makes snapshots of only | |||
|
42 | # needed files, so running the external diff program will actually be | |||
|
43 | # pretty fast (at least faster than having to compare the entire tree). | |||
29 |
|
44 | |||
30 | from mercurial.demandload import demandload |
|
45 | from mercurial.demandload import demandload | |
31 | from mercurial.i18n import gettext as _ |
|
46 | from mercurial.i18n import gettext as _ | |
32 | from mercurial.node import * |
|
47 | from mercurial.node import * | |
33 | demandload(globals(), 'mercurial:commands,util os shutil tempfile') |
|
48 | demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile') | |
34 |
|
49 | |||
35 | def dodiff(ui, repo, diffcmd, pats, opts): |
|
50 | def dodiff(ui, repo, diffcmd, diffopts, pats, opts): | |
36 | def snapshot_node(files, node): |
|
51 | def snapshot_node(files, node): | |
37 | '''snapshot files as of some revision''' |
|
52 | '''snapshot files as of some revision''' | |
38 | changes = repo.changelog.read(node) |
|
53 | changes = repo.changelog.read(node) | |
@@ -76,9 +91,9 b' def dodiff(ui, repo, diffcmd, pats, opts' | |||||
76 | return dirname |
|
91 | return dirname | |
77 |
|
92 | |||
78 | node1, node2 = commands.revpair(ui, repo, opts['rev']) |
|
93 | node1, node2 = commands.revpair(ui, repo, opts['rev']) | |
79 |
files, matchfn, anypats = c |
|
94 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
80 |
modified, added, removed, deleted, unknown = repo. |
|
95 | modified, added, removed, deleted, unknown = repo.status( | |
81 | node1, node2, files, match=matchfn) |
|
96 | node1, node2, files, match=matchfn)[:5] | |
82 | if not (modified or added or removed): |
|
97 | if not (modified or added or removed): | |
83 | return 0 |
|
98 | return 0 | |
84 |
|
99 | |||
@@ -89,9 +104,12 b' def dodiff(ui, repo, diffcmd, pats, opts' | |||||
89 | dir2 = snapshot_node(modified + added, node2) |
|
104 | dir2 = snapshot_node(modified + added, node2) | |
90 | else: |
|
105 | else: | |
91 | dir2 = snapshot_wdir(modified + added) |
|
106 | dir2 = snapshot_wdir(modified + added) | |
92 |
|
|
107 | cmdline = ('%s %s %s %s' % | |
93 | (diffcmd, ' '.join(opts['option']), dir1, dir2), |
|
108 | (util.shellquote(diffcmd), | |
94 | cwd=tmproot) |
|
109 | ' '.join(map(util.shellquote, diffopts)), | |
|
110 | util.shellquote(dir1), util.shellquote(dir2))) | |||
|
111 | ui.debug('running %r in %s\n' % (cmdline, tmproot)) | |||
|
112 | util.system(cmdline, cwd=tmproot) | |||
95 | return 1 |
|
113 | return 1 | |
96 | finally: |
|
114 | finally: | |
97 | ui.note(_('cleaning up temp directory\n')) |
|
115 | ui.note(_('cleaning up temp directory\n')) | |
@@ -101,7 +119,9 b' def extdiff(ui, repo, *pats, **opts):' | |||||
101 | '''use external program to diff repository (or selected files) |
|
119 | '''use external program to diff repository (or selected files) | |
102 |
|
120 | |||
103 | Show differences between revisions for the specified files, using |
|
121 | Show differences between revisions for the specified files, using | |
104 |
an external program. The default program used is |
|
122 | an external program. The default program used is diff, with | |
|
123 | default options "-Npru". | |||
|
124 | ||||
105 | To select a different program, use the -p option. The program |
|
125 | To select a different program, use the -p option. The program | |
106 | will be passed the names of two directories to compare. To pass |
|
126 | will be passed the names of two directories to compare. To pass | |
107 | additional options to the program, use the -o option. These will |
|
127 | additional options to the program, use the -o option. These will | |
@@ -112,7 +132,8 b' def extdiff(ui, repo, *pats, **opts):' | |||||
112 | specified then that revision is compared to the working |
|
132 | specified then that revision is compared to the working | |
113 | directory, and, when no revisions are specified, the |
|
133 | directory, and, when no revisions are specified, the | |
114 | working directory files are compared to its parent.''' |
|
134 | working directory files are compared to its parent.''' | |
115 |
return dodiff(ui, repo, opts['program'] or 'diff |
|
135 | return dodiff(ui, repo, opts['program'] or 'diff', | |
|
136 | opts['option'] or ['-Npru'], pats, opts) | |||
116 |
|
137 | |||
117 | cmdtable = { |
|
138 | cmdtable = { | |
118 | "extdiff": |
|
139 | "extdiff": | |
@@ -130,20 +151,24 b' def uisetup(ui):' | |||||
130 | if not cmd.startswith('cmd.'): continue |
|
151 | if not cmd.startswith('cmd.'): continue | |
131 | cmd = cmd[4:] |
|
152 | cmd = cmd[4:] | |
132 | if not path: path = cmd |
|
153 | if not path: path = cmd | |
|
154 | diffopts = ui.config('extdiff', 'opts.' + cmd, '') | |||
|
155 | diffopts = diffopts and [diffopts] or [] | |||
133 | def save(cmd, path): |
|
156 | def save(cmd, path): | |
134 | '''use closure to save diff command to use''' |
|
157 | '''use closure to save diff command to use''' | |
135 | def mydiff(ui, repo, *pats, **opts): |
|
158 | def mydiff(ui, repo, *pats, **opts): | |
136 | return dodiff(ui, repo, path, pats, opts) |
|
159 | return dodiff(ui, repo, path, diffopts, pats, opts) | |
137 |
mydiff.__doc__ = '''use % |
|
160 | mydiff.__doc__ = '''use %(path)r to diff repository (or selected files) | |
138 |
|
161 | |||
139 | Show differences between revisions for the specified |
|
162 | Show differences between revisions for the specified | |
140 |
files, using the % |
|
163 | files, using the %(path)r program. | |
141 |
|
164 | |||
142 | When two revision arguments are given, then changes are |
|
165 | When two revision arguments are given, then changes are | |
143 | shown between those revisions. If only one revision is |
|
166 | shown between those revisions. If only one revision is | |
144 | specified then that revision is compared to the working |
|
167 | specified then that revision is compared to the working | |
145 | directory, and, when no revisions are specified, the |
|
168 | directory, and, when no revisions are specified, the | |
146 |
working directory files are compared to its parent.''' % |
|
169 | working directory files are compared to its parent.''' % { | |
|
170 | 'path': path, | |||
|
171 | } | |||
147 | return mydiff |
|
172 | return mydiff | |
148 | cmdtable[cmd] = (save(cmd, path), |
|
173 | cmdtable[cmd] = (save(cmd, path), | |
149 | cmdtable['extdiff'][1][1:], |
|
174 | cmdtable['extdiff'][1][1:], |
@@ -221,7 +221,7 b' def sign(ui, repo, *revs, **opts):' | |||||
221 | repo.opener("localsigs", "ab").write(sigmessage) |
|
221 | repo.opener("localsigs", "ab").write(sigmessage) | |
222 | return |
|
222 | return | |
223 |
|
223 | |||
224 |
for x in repo. |
|
224 | for x in repo.status()[:5]: | |
225 | if ".hgsigs" in x and not opts["force"]: |
|
225 | if ".hgsigs" in x and not opts["force"]: | |
226 | raise util.Abort(_("working copy of .hgsigs is changed " |
|
226 | raise util.Abort(_("working copy of .hgsigs is changed " | |
227 | "(please commit .hgsigs manually " |
|
227 | "(please commit .hgsigs manually " |
@@ -23,10 +23,10 b' def lookup_rev(ui, repo, rev=None):' | |||||
23 | return parents.pop() |
|
23 | return parents.pop() | |
24 |
|
24 | |||
25 | def check_clean(ui, repo): |
|
25 | def check_clean(ui, repo): | |
26 |
|
|
26 | modified, added, removed, deleted, unknown = repo.status()[:5] | |
27 |
|
|
27 | if modified or added or removed: | |
28 |
|
|
28 | ui.warn("Repository is not clean, please commit or revert\n") | |
29 |
|
|
29 | sys.exit(1) | |
30 |
|
30 | |||
31 | class bisect(object): |
|
31 | class bisect(object): | |
32 | """dichotomic search in the DAG of changesets""" |
|
32 | """dichotomic search in the DAG of changesets""" | |
@@ -50,7 +50,7 b' class bisect(object):' | |||||
50 | if r: |
|
50 | if r: | |
51 | self.badrev = hg.bin(r.pop(0)) |
|
51 | self.badrev = hg.bin(r.pop(0)) | |
52 |
|
52 | |||
53 |
def |
|
53 | def write(self): | |
54 | if not os.path.isdir(self.path): |
|
54 | if not os.path.isdir(self.path): | |
55 | return |
|
55 | return | |
56 | f = self.opener(self.good_path, "w") |
|
56 | f = self.opener(self.good_path, "w") | |
@@ -197,7 +197,7 b' class bisect(object):' | |||||
197 | check_clean(self.ui, self.repo) |
|
197 | check_clean(self.ui, self.repo) | |
198 | rev = self.next() |
|
198 | rev = self.next() | |
199 | if rev is not None: |
|
199 | if rev is not None: | |
200 |
return self.repo |
|
200 | return hg.clean(self.repo, rev) | |
201 |
|
201 | |||
202 | def good(self, rev): |
|
202 | def good(self, rev): | |
203 | self.goodrevs.append(rev) |
|
203 | self.goodrevs.append(rev) | |
@@ -288,7 +288,10 b' for subcommands see "hg bisect help\\"' | |||||
288 | if len(args) > bisectcmdtable[cmd][1]: |
|
288 | if len(args) > bisectcmdtable[cmd][1]: | |
289 | ui.warn(_("bisect: Too many arguments\n")) |
|
289 | ui.warn(_("bisect: Too many arguments\n")) | |
290 | return help_() |
|
290 | return help_() | |
291 | return bisectcmdtable[cmd][0](*args) |
|
291 | try: | |
|
292 | return bisectcmdtable[cmd][0](*args) | |||
|
293 | finally: | |||
|
294 | b.write() | |||
292 |
|
295 | |||
293 | cmdtable = { |
|
296 | cmdtable = { | |
294 | "bisect": (bisect_run, [], _("hg bisect [help|init|reset|next|good|bad]")), |
|
297 | "bisect": (bisect_run, [], _("hg bisect [help|init|reset|next|good|bad]")), |
@@ -1,12 +1,13 b'' | |||||
1 | # Minimal support for git commands on an hg repository |
|
1 | # Minimal support for git commands on an hg repository | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Chris Mason <mason@suse.com> |
|
3 | # Copyright 2005, 2006 Chris Mason <mason@suse.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
7 |
|
7 | |||
8 | import time, sys, signal, os |
|
8 | from mercurial.demandload import * | |
9 | from mercurial import hg, mdiff, fancyopts, commands, ui, util |
|
9 | demandload(globals(), 'time sys signal os') | |
|
10 | demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util') | |||
10 |
|
11 | |||
11 | def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, |
|
12 | def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, | |
12 | changes=None, text=False): |
|
13 | changes=None, text=False): | |
@@ -14,7 +15,7 b' def dodiff(fp, ui, repo, node1, node2, f' | |||||
14 | return time.asctime(time.gmtime(c[2][0])) |
|
15 | return time.asctime(time.gmtime(c[2][0])) | |
15 |
|
16 | |||
16 | if not changes: |
|
17 | if not changes: | |
17 |
changes = repo. |
|
18 | changes = repo.status(node1, node2, files, match=match)[:5] | |
18 | modified, added, removed, deleted, unknown = changes |
|
19 | modified, added, removed, deleted, unknown = changes | |
19 | if files: |
|
20 | if files: | |
20 | modified, added, removed = map(lambda x: filterfiles(files, x), |
|
21 | modified, added, removed = map(lambda x: filterfiles(files, x), | |
@@ -67,12 +68,12 b' def difftree(ui, repo, node1=None, node2' | |||||
67 | if node2: |
|
68 | if node2: | |
68 | change = repo.changelog.read(node2) |
|
69 | change = repo.changelog.read(node2) | |
69 | mmap2 = repo.manifest.read(change[0]) |
|
70 | mmap2 = repo.manifest.read(change[0]) | |
70 |
modified, added, removed, deleted, unknown = repo. |
|
71 | modified, added, removed, deleted, unknown = repo.status(node1, node2)[:5] | |
71 | def read(f): return repo.file(f).read(mmap2[f]) |
|
72 | def read(f): return repo.file(f).read(mmap2[f]) | |
72 | date2 = date(change) |
|
73 | date2 = date(change) | |
73 | else: |
|
74 | else: | |
74 | date2 = time.asctime() |
|
75 | date2 = time.asctime() | |
75 |
modified, added, removed, deleted, unknown = repo. |
|
76 | modified, added, removed, deleted, unknown = repo.status(node1)[:5] | |
76 | if not node1: |
|
77 | if not node1: | |
77 | node1 = repo.dirstate.parents()[0] |
|
78 | node1 = repo.dirstate.parents()[0] | |
78 | def read(f): return file(os.path.join(repo.root, f)).read() |
|
79 | def read(f): return file(os.path.join(repo.root, f)).read() | |
@@ -334,6 +335,3 b' cmdtable = {' | |||||
334 | ('n', 'max-count', 0, 'max-count')], |
|
335 | ('n', 'max-count', 0, 'max-count')], | |
335 | "hg debug-rev-list [options] revs"), |
|
336 | "hg debug-rev-list [options] revs"), | |
336 | } |
|
337 | } | |
337 |
|
||||
338 | def reposetup(ui, repo): |
|
|||
339 | pass |
|
This diff has been collapsed as it changes many lines, (1338 lines changed) Show them Hide them | |||||
@@ -1,6 +1,6 b'' | |||||
1 | # queue.py - patch queues for mercurial |
|
1 | # queue.py - patch queues for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Chris Mason <mason@suse.com> |
|
3 | # Copyright 2005, 2006 Chris Mason <mason@suse.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -30,22 +30,30 b' refresh contents of top applied patch ' | |||||
30 | ''' |
|
30 | ''' | |
31 |
|
31 | |||
32 | from mercurial.demandload import * |
|
32 | from mercurial.demandload import * | |
|
33 | from mercurial.i18n import gettext as _ | |||
33 | demandload(globals(), "os sys re struct traceback errno bz2") |
|
34 | demandload(globals(), "os sys re struct traceback errno bz2") | |
34 | from mercurial.i18n import gettext as _ |
|
35 | demandload(globals(), "mercurial:cmdutil,commands,hg,patch,revlog,ui,util") | |
35 | from mercurial import ui, hg, revlog, commands, util |
|
36 | ||
|
37 | commands.norepo += " qclone qversion" | |||
36 |
|
38 | |||
37 | versionstr = "0.45" |
|
39 | class statusentry: | |
|
40 | def __init__(self, rev, name=None): | |||
|
41 | if not name: | |||
|
42 | fields = rev.split(':') | |||
|
43 | if len(fields) == 2: | |||
|
44 | self.rev, self.name = fields | |||
|
45 | else: | |||
|
46 | self.rev, self.name = None, None | |||
|
47 | else: | |||
|
48 | self.rev, self.name = rev, name | |||
38 |
|
49 | |||
39 | repomap = {} |
|
50 | def __str__(self): | |
|
51 | return self.rev + ':' + self.name | |||
40 |
|
52 | |||
41 | commands.norepo += " qversion" |
|
|||
42 | class queue: |
|
53 | class queue: | |
43 | def __init__(self, ui, path, patchdir=None): |
|
54 | def __init__(self, ui, path, patchdir=None): | |
44 | self.basepath = path |
|
55 | self.basepath = path | |
45 | if patchdir: |
|
56 | self.path = patchdir or os.path.join(path, "patches") | |
46 | self.path = patchdir |
|
|||
47 | else: |
|
|||
48 | self.path = os.path.join(path, "patches") |
|
|||
49 | self.opener = util.opener(self.path) |
|
57 | self.opener = util.opener(self.path) | |
50 | self.ui = ui |
|
58 | self.ui = ui | |
51 | self.applied = [] |
|
59 | self.applied = [] | |
@@ -54,13 +62,26 b' class queue:' | |||||
54 | self.series_dirty = 0 |
|
62 | self.series_dirty = 0 | |
55 | self.series_path = "series" |
|
63 | self.series_path = "series" | |
56 | self.status_path = "status" |
|
64 | self.status_path = "status" | |
|
65 | self.guards_path = "guards" | |||
|
66 | self.active_guards = None | |||
|
67 | self.guards_dirty = False | |||
|
68 | self._diffopts = None | |||
57 |
|
69 | |||
58 |
if os.path.exists( |
|
70 | if os.path.exists(self.join(self.series_path)): | |
59 | self.full_series = self.opener(self.series_path).read().splitlines() |
|
71 | self.full_series = self.opener(self.series_path).read().splitlines() | |
60 |
self.re |
|
72 | self.parse_series() | |
|
73 | ||||
|
74 | if os.path.exists(self.join(self.status_path)): | |||
|
75 | lines = self.opener(self.status_path).read().splitlines() | |||
|
76 | self.applied = [statusentry(l) for l in lines] | |||
61 |
|
77 | |||
62 | if os.path.exists(os.path.join(self.path, self.status_path)): |
|
78 | def diffopts(self): | |
63 | self.applied = self.opener(self.status_path).read().splitlines() |
|
79 | if self._diffopts is None: | |
|
80 | self._diffopts = patch.diffopts(self.ui) | |||
|
81 | return self._diffopts | |||
|
82 | ||||
|
83 | def join(self, *p): | |||
|
84 | return os.path.join(self.path, *p) | |||
64 |
|
85 | |||
65 | def find_series(self, patch): |
|
86 | def find_series(self, patch): | |
66 | pre = re.compile("(\s*)([^#]+)") |
|
87 | pre = re.compile("(\s*)([^#]+)") | |
@@ -75,34 +96,132 b' class queue:' | |||||
75 | index += 1 |
|
96 | index += 1 | |
76 | return None |
|
97 | return None | |
77 |
|
98 | |||
78 | def read_series(self, list): |
|
99 | guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)') | |
79 | def matcher(list): |
|
100 | ||
80 | pre = re.compile("(\s*)([^#]+)") |
|
101 | def parse_series(self): | |
81 | for l in list: |
|
|||
82 | m = pre.match(l) |
|
|||
83 | if m: |
|
|||
84 | s = m.group(2) |
|
|||
85 | s = s.rstrip() |
|
|||
86 | if len(s) > 0: |
|
|||
87 | yield s |
|
|||
88 | self.series = [] |
|
102 | self.series = [] | |
89 | self.series = [ x for x in matcher(list) ] |
|
103 | self.series_guards = [] | |
|
104 | for l in self.full_series: | |||
|
105 | h = l.find('#') | |||
|
106 | if h == -1: | |||
|
107 | patch = l | |||
|
108 | comment = '' | |||
|
109 | elif h == 0: | |||
|
110 | continue | |||
|
111 | else: | |||
|
112 | patch = l[:h] | |||
|
113 | comment = l[h:] | |||
|
114 | patch = patch.strip() | |||
|
115 | if patch: | |||
|
116 | self.series.append(patch) | |||
|
117 | self.series_guards.append(self.guard_re.findall(comment)) | |||
|
118 | ||||
|
119 | def check_guard(self, guard): | |||
|
120 | bad_chars = '# \t\r\n\f' | |||
|
121 | first = guard[0] | |||
|
122 | for c in '-+': | |||
|
123 | if first == c: | |||
|
124 | return (_('guard %r starts with invalid character: %r') % | |||
|
125 | (guard, c)) | |||
|
126 | for c in bad_chars: | |||
|
127 | if c in guard: | |||
|
128 | return _('invalid character in guard %r: %r') % (guard, c) | |||
|
129 | ||||
|
130 | def set_active(self, guards): | |||
|
131 | for guard in guards: | |||
|
132 | bad = self.check_guard(guard) | |||
|
133 | if bad: | |||
|
134 | raise util.Abort(bad) | |||
|
135 | guards = dict.fromkeys(guards).keys() | |||
|
136 | guards.sort() | |||
|
137 | self.ui.debug('active guards: %s\n' % ' '.join(guards)) | |||
|
138 | self.active_guards = guards | |||
|
139 | self.guards_dirty = True | |||
|
140 | ||||
|
141 | def active(self): | |||
|
142 | if self.active_guards is None: | |||
|
143 | self.active_guards = [] | |||
|
144 | try: | |||
|
145 | guards = self.opener(self.guards_path).read().split() | |||
|
146 | except IOError, err: | |||
|
147 | if err.errno != errno.ENOENT: raise | |||
|
148 | guards = [] | |||
|
149 | for i, guard in enumerate(guards): | |||
|
150 | bad = self.check_guard(guard) | |||
|
151 | if bad: | |||
|
152 | self.ui.warn('%s:%d: %s\n' % | |||
|
153 | (self.join(self.guards_path), i + 1, bad)) | |||
|
154 | else: | |||
|
155 | self.active_guards.append(guard) | |||
|
156 | return self.active_guards | |||
|
157 | ||||
|
158 | def set_guards(self, idx, guards): | |||
|
159 | for g in guards: | |||
|
160 | if len(g) < 2: | |||
|
161 | raise util.Abort(_('guard %r too short') % g) | |||
|
162 | if g[0] not in '-+': | |||
|
163 | raise util.Abort(_('guard %r starts with invalid char') % g) | |||
|
164 | bad = self.check_guard(g[1:]) | |||
|
165 | if bad: | |||
|
166 | raise util.Abort(bad) | |||
|
167 | drop = self.guard_re.sub('', self.full_series[idx]) | |||
|
168 | self.full_series[idx] = drop + ''.join([' #' + g for g in guards]) | |||
|
169 | self.parse_series() | |||
|
170 | self.series_dirty = True | |||
|
171 | ||||
|
172 | def pushable(self, idx): | |||
|
173 | if isinstance(idx, str): | |||
|
174 | idx = self.series.index(idx) | |||
|
175 | patchguards = self.series_guards[idx] | |||
|
176 | if not patchguards: | |||
|
177 | return True, None | |||
|
178 | default = False | |||
|
179 | guards = self.active() | |||
|
180 | exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards] | |||
|
181 | if exactneg: | |||
|
182 | return False, exactneg[0] | |||
|
183 | pos = [g for g in patchguards if g[0] == '+'] | |||
|
184 | exactpos = [g for g in pos if g[1:] in guards] | |||
|
185 | if pos: | |||
|
186 | if exactpos: | |||
|
187 | return True, exactpos[0] | |||
|
188 | return False, pos | |||
|
189 | return True, '' | |||
|
190 | ||||
|
191 | def explain_pushable(self, idx, all_patches=False): | |||
|
192 | write = all_patches and self.ui.write or self.ui.warn | |||
|
193 | if all_patches or self.ui.verbose: | |||
|
194 | if isinstance(idx, str): | |||
|
195 | idx = self.series.index(idx) | |||
|
196 | pushable, why = self.pushable(idx) | |||
|
197 | if all_patches and pushable: | |||
|
198 | if why is None: | |||
|
199 | write(_('allowing %s - no guards in effect\n') % | |||
|
200 | self.series[idx]) | |||
|
201 | else: | |||
|
202 | if not why: | |||
|
203 | write(_('allowing %s - no matching negative guards\n') % | |||
|
204 | self.series[idx]) | |||
|
205 | else: | |||
|
206 | write(_('allowing %s - guarded by %r\n') % | |||
|
207 | (self.series[idx], why)) | |||
|
208 | if not pushable: | |||
|
209 | if why: | |||
|
210 | write(_('skipping %s - guarded by %r\n') % | |||
|
211 | (self.series[idx], ' '.join(why))) | |||
|
212 | else: | |||
|
213 | write(_('skipping %s - no matching guards\n') % | |||
|
214 | self.series[idx]) | |||
90 |
|
215 | |||
91 | def save_dirty(self): |
|
216 | def save_dirty(self): | |
92 | if self.applied_dirty: |
|
217 | def write_list(items, path): | |
93 | if len(self.applied) > 0: |
|
218 | fp = self.opener(path, 'w') | |
94 | nl = "\n" |
|
219 | for i in items: | |
95 | else: |
|
220 | print >> fp, i | |
96 | nl = "" |
|
221 | fp.close() | |
97 | f = self.opener(self.status_path, "w") |
|
222 | if self.applied_dirty: write_list(map(str, self.applied), self.status_path) | |
98 | f.write("\n".join(self.applied) + nl) |
|
223 | if self.series_dirty: write_list(self.full_series, self.series_path) | |
99 | if self.series_dirty: |
|
224 | if self.guards_dirty: write_list(self.active_guards, self.guards_path) | |
100 | if len(self.full_series) > 0: |
|
|||
101 | nl = "\n" |
|
|||
102 | else: |
|
|||
103 | nl = "" |
|
|||
104 | f = self.opener(self.series_path, "w") |
|
|||
105 | f.write("\n".join(self.full_series) + nl) |
|
|||
106 |
|
225 | |||
107 | def readheaders(self, patch): |
|
226 | def readheaders(self, patch): | |
108 | def eatdiff(lines): |
|
227 | def eatdiff(lines): | |
@@ -122,7 +241,7 b' class queue:' | |||||
122 | else: |
|
241 | else: | |
123 | break |
|
242 | break | |
124 |
|
243 | |||
125 |
pf = |
|
244 | pf = self.join(patch) | |
126 | message = [] |
|
245 | message = [] | |
127 | comments = [] |
|
246 | comments = [] | |
128 | user = None |
|
247 | user = None | |
@@ -133,6 +252,9 b' class queue:' | |||||
133 |
|
252 | |||
134 | for line in file(pf): |
|
253 | for line in file(pf): | |
135 | line = line.rstrip() |
|
254 | line = line.rstrip() | |
|
255 | if line.startswith('diff --git'): | |||
|
256 | diffstart = 2 | |||
|
257 | break | |||
136 | if diffstart: |
|
258 | if diffstart: | |
137 | if line.startswith('+++ '): |
|
259 | if line.startswith('+++ '): | |
138 | diffstart = 2 |
|
260 | diffstart = 2 | |
@@ -178,6 +300,13 b' class queue:' | |||||
178 | message.insert(0, subject) |
|
300 | message.insert(0, subject) | |
179 | return (message, comments, user, date, diffstart > 1) |
|
301 | return (message, comments, user, date, diffstart > 1) | |
180 |
|
302 | |||
|
303 | def printdiff(self, repo, node1, node2=None, files=None, | |||
|
304 | fp=None, changes=None, opts={}): | |||
|
305 | fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts) | |||
|
306 | ||||
|
307 | patch.diff(repo, node1, node2, fns, match=matchfn, | |||
|
308 | fp=fp, changes=changes, opts=self.diffopts()) | |||
|
309 | ||||
181 | def mergeone(self, repo, mergeq, head, patch, rev, wlock): |
|
310 | def mergeone(self, repo, mergeq, head, patch, rev, wlock): | |
182 | # first try just applying the patch |
|
311 | # first try just applying the patch | |
183 | (err, n) = self.apply(repo, [ patch ], update_status=False, |
|
312 | (err, n) = self.apply(repo, [ patch ], update_status=False, | |
@@ -187,35 +316,31 b' class queue:' | |||||
187 | return (err, n) |
|
316 | return (err, n) | |
188 |
|
317 | |||
189 | if n is None: |
|
318 | if n is None: | |
190 |
sel |
|
319 | raise util.Abort(_("apply failed for patch %s") % patch) | |
191 | sys.exit(1) |
|
|||
192 |
|
320 | |||
193 | self.ui.warn("patch didn't work out, merging %s\n" % patch) |
|
321 | self.ui.warn("patch didn't work out, merging %s\n" % patch) | |
194 |
|
322 | |||
195 | # apply failed, strip away that rev and merge. |
|
323 | # apply failed, strip away that rev and merge. | |
196 | repo.update(head, allow=False, force=True, wlock=wlock) |
|
324 | hg.clean(repo, head, wlock=wlock) | |
197 | self.strip(repo, n, update=False, backup='strip', wlock=wlock) |
|
325 | self.strip(repo, n, update=False, backup='strip', wlock=wlock) | |
198 |
|
326 | |||
199 | c = repo.changelog.read(rev) |
|
327 | c = repo.changelog.read(rev) | |
200 |
ret = repo |
|
328 | ret = hg.merge(repo, rev, wlock=wlock) | |
201 | if ret: |
|
329 | if ret: | |
202 |
sel |
|
330 | raise util.Abort(_("update returned %d") % ret) | |
203 | sys.exit(1) |
|
|||
204 | n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) |
|
331 | n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) | |
205 | if n == None: |
|
332 | if n == None: | |
206 |
sel |
|
333 | raise util.Abort(_("repo commit failed")) | |
207 | sys.exit(1) |
|
|||
208 | try: |
|
334 | try: | |
209 | message, comments, user, date, patchfound = mergeq.readheaders(patch) |
|
335 | message, comments, user, date, patchfound = mergeq.readheaders(patch) | |
210 | except: |
|
336 | except: | |
211 |
sel |
|
337 | raise util.Abort(_("unable to read %s") % patch) | |
212 | sys.exit(1) |
|
|||
213 |
|
338 | |||
214 | patchf = self.opener(patch, "w") |
|
339 | patchf = self.opener(patch, "w") | |
215 | if comments: |
|
340 | if comments: | |
216 | comments = "\n".join(comments) + '\n\n' |
|
341 | comments = "\n".join(comments) + '\n\n' | |
217 | patchf.write(comments) |
|
342 | patchf.write(comments) | |
218 | commands.dodiff(patchf, self.ui, repo, head, n) |
|
343 | self.printdiff(repo, head, n, fp=patchf) | |
219 | patchf.close() |
|
344 | patchf.close() | |
220 | return (0, n) |
|
345 | return (0, n) | |
221 |
|
346 | |||
@@ -226,12 +351,10 b' class queue:' | |||||
226 | return p1 |
|
351 | return p1 | |
227 | if len(self.applied) == 0: |
|
352 | if len(self.applied) == 0: | |
228 | return None |
|
353 | return None | |
229 | (top, patch) = self.applied[-1].split(':') |
|
354 | return revlog.bin(self.applied[-1].rev) | |
230 | top = revlog.bin(top) |
|
|||
231 | return top |
|
|||
232 | pp = repo.changelog.parents(rev) |
|
355 | pp = repo.changelog.parents(rev) | |
233 | if pp[1] != revlog.nullid: |
|
356 | if pp[1] != revlog.nullid: | |
234 |
arevs = [ x. |
|
357 | arevs = [ x.rev for x in self.applied ] | |
235 | p0 = revlog.hex(pp[0]) |
|
358 | p0 = revlog.hex(pp[0]) | |
236 | p1 = revlog.hex(pp[1]) |
|
359 | p1 = revlog.hex(pp[1]) | |
237 | if p0 in arevs: |
|
360 | if p0 in arevs: | |
@@ -251,17 +374,20 b' class queue:' | |||||
251 | pname = ".hg.patches.merge.marker" |
|
374 | pname = ".hg.patches.merge.marker" | |
252 | n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
|
375 | n = repo.commit(None, '[mq]: merge marker', user=None, force=1, | |
253 | wlock=wlock) |
|
376 | wlock=wlock) | |
254 |
self.applied.append(revlog.hex(n) |
|
377 | self.applied.append(statusentry(revlog.hex(n), pname)) | |
255 | self.applied_dirty = 1 |
|
378 | self.applied_dirty = 1 | |
256 |
|
379 | |||
257 | head = self.qparents(repo) |
|
380 | head = self.qparents(repo) | |
258 |
|
381 | |||
259 | for patch in series: |
|
382 | for patch in series: | |
260 | patch = mergeq.lookup(patch) |
|
383 | patch = mergeq.lookup(patch, strict=True) | |
261 | if not patch: |
|
384 | if not patch: | |
262 | self.ui.warn("patch %s does not exist\n" % patch) |
|
385 | self.ui.warn("patch %s does not exist\n" % patch) | |
263 | return (1, None) |
|
386 | return (1, None) | |
264 |
|
387 | pushable, reason = self.pushable(patch) | ||
|
388 | if not pushable: | |||
|
389 | self.explain_pushable(patch, all_patches=True) | |||
|
390 | continue | |||
265 | info = mergeq.isapplied(patch) |
|
391 | info = mergeq.isapplied(patch) | |
266 | if not info: |
|
392 | if not info: | |
267 | self.ui.warn("patch %s is not applied\n" % patch) |
|
393 | self.ui.warn("patch %s is not applied\n" % patch) | |
@@ -269,102 +395,80 b' class queue:' | |||||
269 | rev = revlog.bin(info[1]) |
|
395 | rev = revlog.bin(info[1]) | |
270 | (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
|
396 | (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) | |
271 | if head: |
|
397 | if head: | |
272 |
self.applied.append(revlog.hex(head) |
|
398 | self.applied.append(statusentry(revlog.hex(head), patch)) | |
273 | self.applied_dirty = 1 |
|
399 | self.applied_dirty = 1 | |
274 | if err: |
|
400 | if err: | |
275 | return (err, head) |
|
401 | return (err, head) | |
276 | return (0, head) |
|
402 | return (0, head) | |
277 |
|
403 | |||
|
404 | def patch(self, repo, patchfile): | |||
|
405 | '''Apply patchfile to the working directory. | |||
|
406 | patchfile: file name of patch''' | |||
|
407 | try: | |||
|
408 | (files, fuzz) = patch.patch(patchfile, self.ui, strip=1, | |||
|
409 | cwd=repo.root) | |||
|
410 | except Exception, inst: | |||
|
411 | self.ui.note(str(inst) + '\n') | |||
|
412 | if not self.ui.verbose: | |||
|
413 | self.ui.warn("patch failed, unable to continue (try -v)\n") | |||
|
414 | return (False, [], False) | |||
|
415 | ||||
|
416 | return (True, files, fuzz) | |||
|
417 | ||||
278 | def apply(self, repo, series, list=False, update_status=True, |
|
418 | def apply(self, repo, series, list=False, update_status=True, | |
279 | strict=False, patchdir=None, merge=None, wlock=None): |
|
419 | strict=False, patchdir=None, merge=None, wlock=None): | |
280 | # TODO unify with commands.py |
|
420 | # TODO unify with commands.py | |
281 | if not patchdir: |
|
421 | if not patchdir: | |
282 | patchdir = self.path |
|
422 | patchdir = self.path | |
283 | pwd = os.getcwd() |
|
|||
284 | os.chdir(repo.root) |
|
|||
285 | err = 0 |
|
423 | err = 0 | |
286 | if not wlock: |
|
424 | if not wlock: | |
287 | wlock = repo.wlock() |
|
425 | wlock = repo.wlock() | |
288 | lock = repo.lock() |
|
426 | lock = repo.lock() | |
289 | tr = repo.transaction() |
|
427 | tr = repo.transaction() | |
290 | n = None |
|
428 | n = None | |
291 | for patch in series: |
|
429 | for patchname in series: | |
292 | self.ui.warn("applying %s\n" % patch) |
|
430 | pushable, reason = self.pushable(patchname) | |
293 | pf = os.path.join(patchdir, patch) |
|
431 | if not pushable: | |
|
432 | self.explain_pushable(patchname, all_patches=True) | |||
|
433 | continue | |||
|
434 | self.ui.warn("applying %s\n" % patchname) | |||
|
435 | pf = os.path.join(patchdir, patchname) | |||
294 |
|
436 | |||
295 | try: |
|
437 | try: | |
296 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
438 | message, comments, user, date, patchfound = self.readheaders(patchname) | |
297 | except: |
|
439 | except: | |
298 |
self.ui.warn("Unable to read %s\n" % p |
|
440 | self.ui.warn("Unable to read %s\n" % patchname) | |
299 | err = 1 |
|
441 | err = 1 | |
300 | break |
|
442 | break | |
301 |
|
443 | |||
302 | if not message: |
|
444 | if not message: | |
303 | message = "imported patch %s\n" % patch |
|
445 | message = "imported patch %s\n" % patchname | |
304 | else: |
|
446 | else: | |
305 | if list: |
|
447 | if list: | |
306 | message.append("\nimported patch %s" % patch) |
|
448 | message.append("\nimported patch %s" % patchname) | |
307 | message = '\n'.join(message) |
|
449 | message = '\n'.join(message) | |
308 |
|
450 | |||
309 | try: |
|
451 | (patcherr, files, fuzz) = self.patch(repo, pf) | |
310 | pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
|
452 | patcherr = not patcherr | |
311 | f = os.popen("%s -p1 --no-backup-if-mismatch < '%s'" % (pp, pf)) |
|
|||
312 | except: |
|
|||
313 | self.ui.warn("patch failed, unable to continue (try -v)\n") |
|
|||
314 | err = 1 |
|
|||
315 | break |
|
|||
316 | files = [] |
|
|||
317 | fuzz = False |
|
|||
318 | for l in f: |
|
|||
319 | l = l.rstrip('\r\n'); |
|
|||
320 | if self.ui.verbose: |
|
|||
321 | self.ui.warn(l + "\n") |
|
|||
322 | if l[:14] == 'patching file ': |
|
|||
323 | pf = os.path.normpath(l[14:]) |
|
|||
324 | # when patch finds a space in the file name, it puts |
|
|||
325 | # single quotes around the filename. strip them off |
|
|||
326 | if pf[0] == "'" and pf[-1] == "'": |
|
|||
327 | pf = pf[1:-1] |
|
|||
328 | if pf not in files: |
|
|||
329 | files.append(pf) |
|
|||
330 | printed_file = False |
|
|||
331 | file_str = l |
|
|||
332 | elif l.find('with fuzz') >= 0: |
|
|||
333 | if not printed_file: |
|
|||
334 | self.ui.warn(file_str + '\n') |
|
|||
335 | printed_file = True |
|
|||
336 | self.ui.warn(l + '\n') |
|
|||
337 | fuzz = True |
|
|||
338 | elif l.find('saving rejects to file') >= 0: |
|
|||
339 | self.ui.warn(l + '\n') |
|
|||
340 | elif l.find('FAILED') >= 0: |
|
|||
341 | if not printed_file: |
|
|||
342 | self.ui.warn(file_str + '\n') |
|
|||
343 | printed_file = True |
|
|||
344 | self.ui.warn(l + '\n') |
|
|||
345 | patcherr = f.close() |
|
|||
346 |
|
453 | |||
347 |
if merge and |
|
454 | if merge and files: | |
348 | # Mark as merged and update dirstate parent info |
|
455 | # Mark as merged and update dirstate parent info | |
349 | repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') |
|
456 | repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm') | |
350 | p1, p2 = repo.dirstate.parents() |
|
457 | p1, p2 = repo.dirstate.parents() | |
351 | repo.dirstate.setparents(p1, merge) |
|
458 | repo.dirstate.setparents(p1, merge) | |
352 | if len(files) > 0: |
|
459 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) | |
353 | commands.addremove_lock(self.ui, repo, files, |
|
|||
354 | opts={}, wlock=wlock) |
|
|||
355 | n = repo.commit(files, message, user, date, force=1, lock=lock, |
|
460 | n = repo.commit(files, message, user, date, force=1, lock=lock, | |
356 | wlock=wlock) |
|
461 | wlock=wlock) | |
357 |
|
462 | |||
358 | if n == None: |
|
463 | if n == None: | |
359 |
sel |
|
464 | raise util.Abort(_("repo commit failed")) | |
360 | sys.exit(1) |
|
|||
361 |
|
465 | |||
362 | if update_status: |
|
466 | if update_status: | |
363 |
self.applied.append(revlog.hex(n) |
|
467 | self.applied.append(statusentry(revlog.hex(n), patchname)) | |
364 |
|
468 | |||
365 | if patcherr: |
|
469 | if patcherr: | |
366 | if not patchfound: |
|
470 | if not patchfound: | |
367 | self.ui.warn("patch %s is empty\n" % patch) |
|
471 | self.ui.warn("patch %s is empty\n" % patchname) | |
368 | err = 0 |
|
472 | err = 0 | |
369 | else: |
|
473 | else: | |
370 | self.ui.warn("patch failed, rejects left in working dir\n") |
|
474 | self.ui.warn("patch failed, rejects left in working dir\n") | |
@@ -376,49 +480,58 b' class queue:' | |||||
376 | err = 1 |
|
480 | err = 1 | |
377 | break |
|
481 | break | |
378 | tr.close() |
|
482 | tr.close() | |
379 | os.chdir(pwd) |
|
|||
380 | return (err, n) |
|
483 | return (err, n) | |
381 |
|
484 | |||
382 | def delete(self, repo, patch): |
|
485 | def delete(self, repo, patches, keep=False): | |
383 | patch = self.lookup(patch) |
|
486 | realpatches = [] | |
384 | info = self.isapplied(patch) |
|
487 | for patch in patches: | |
385 | if info: |
|
488 | patch = self.lookup(patch, strict=True) | |
386 | self.ui.warn("cannot delete applied patch %s\n" % patch) |
|
489 | info = self.isapplied(patch) | |
387 |
|
|
490 | if info: | |
388 | if patch not in self.series: |
|
491 | raise util.Abort(_("cannot delete applied patch %s") % patch) | |
389 |
self. |
|
492 | if patch not in self.series: | |
390 | sys.exit(1) |
|
493 | raise util.Abort(_("patch %s not in series file") % patch) | |
391 | i = self.find_series(patch) |
|
494 | realpatches.append(patch) | |
392 | del self.full_series[i] |
|
495 | ||
393 | self.read_series(self.full_series) |
|
496 | if not keep: | |
|
497 | r = self.qrepo() | |||
|
498 | if r: | |||
|
499 | r.remove(realpatches, True) | |||
|
500 | else: | |||
|
501 | os.unlink(self.join(patch)) | |||
|
502 | ||||
|
503 | indices = [self.find_series(p) for p in realpatches] | |||
|
504 | indices.sort() | |||
|
505 | for i in indices[-1::-1]: | |||
|
506 | del self.full_series[i] | |||
|
507 | self.parse_series() | |||
394 | self.series_dirty = 1 |
|
508 | self.series_dirty = 1 | |
395 |
|
509 | |||
396 | def check_toppatch(self, repo): |
|
510 | def check_toppatch(self, repo): | |
397 | if len(self.applied) > 0: |
|
511 | if len(self.applied) > 0: | |
398 |
|
|
512 | top = revlog.bin(self.applied[-1].rev) | |
399 | top = revlog.bin(top) |
|
|||
400 | pp = repo.dirstate.parents() |
|
513 | pp = repo.dirstate.parents() | |
401 | if top not in pp: |
|
514 | if top not in pp: | |
402 | self.ui.warn("queue top not at dirstate parents. top %s dirstate %s %s\n" %( revlog.short(top), revlog.short(pp[0]), revlog.short(pp[1]))) |
|
515 | raise util.Abort(_("queue top not at same revision as working directory")) | |
403 | sys.exit(1) |
|
|||
404 | return top |
|
516 | return top | |
405 | return None |
|
517 | return None | |
406 | def check_localchanges(self, repo): |
|
518 | def check_localchanges(self, repo, force=False, refresh=True): | |
407 |
|
|
519 | m, a, r, d = repo.status()[:4] | |
408 |
if |
|
520 | if m or a or r or d: | |
409 | self.ui.write("Local changes found, refresh first\n") |
|
521 | if not force: | |
410 | sys.exit(1) |
|
522 | if refresh: | |
|
523 | raise util.Abort(_("local changes found, refresh first")) | |||
|
524 | else: | |||
|
525 | raise util.Abort(_("local changes found")) | |||
|
526 | return m, a, r, d | |||
411 | def new(self, repo, patch, msg=None, force=None): |
|
527 | def new(self, repo, patch, msg=None, force=None): | |
412 | commitfiles = [] |
|
528 | if os.path.exists(self.join(patch)): | |
413 | (c, a, r, d, u) = repo.changes(None, None) |
|
529 | raise util.Abort(_('patch "%s" already exists') % patch) | |
414 | if c or a or d or r: |
|
530 | m, a, r, d = self.check_localchanges(repo, force) | |
415 | if not force: |
|
531 | commitfiles = m + a + r | |
416 | raise util.Abort(_("Local changes found, refresh first")) |
|
|||
417 | else: |
|
|||
418 | commitfiles = c + a + r |
|
|||
419 | self.check_toppatch(repo) |
|
532 | self.check_toppatch(repo) | |
420 | wlock = repo.wlock() |
|
533 | wlock = repo.wlock() | |
421 | insert = self.series_end() |
|
534 | insert = self.full_series_end() | |
422 | if msg: |
|
535 | if msg: | |
423 | n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True, |
|
536 | n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True, | |
424 | wlock=wlock) |
|
537 | wlock=wlock) | |
@@ -426,11 +539,10 b' class queue:' | |||||
426 | n = repo.commit(commitfiles, |
|
539 | n = repo.commit(commitfiles, | |
427 | "New patch: %s" % patch, force=True, wlock=wlock) |
|
540 | "New patch: %s" % patch, force=True, wlock=wlock) | |
428 | if n == None: |
|
541 | if n == None: | |
429 |
sel |
|
542 | raise util.Abort(_("repo commit failed")) | |
430 | sys.exit(1) |
|
|||
431 | self.full_series[insert:insert] = [patch] |
|
543 | self.full_series[insert:insert] = [patch] | |
432 |
self.applied.append(revlog.hex(n) |
|
544 | self.applied.append(statusentry(revlog.hex(n), patch)) | |
433 |
self.re |
|
545 | self.parse_series() | |
434 | self.series_dirty = 1 |
|
546 | self.series_dirty = 1 | |
435 | self.applied_dirty = 1 |
|
547 | self.applied_dirty = 1 | |
436 | p = self.opener(patch, "w") |
|
548 | p = self.opener(patch, "w") | |
@@ -509,9 +621,9 b' class queue:' | |||||
509 | # we go in two steps here so the strip loop happens in a |
|
621 | # we go in two steps here so the strip loop happens in a | |
510 | # sensible order. When stripping many files, this helps keep |
|
622 | # sensible order. When stripping many files, this helps keep | |
511 | # our disk access patterns under control. |
|
623 | # our disk access patterns under control. | |
512 | list = seen.keys() |
|
624 | seen_list = seen.keys() | |
513 | list.sort() |
|
625 | seen_list.sort() | |
514 | for f in list: |
|
626 | for f in seen_list: | |
515 | ff = repo.file(f) |
|
627 | ff = repo.file(f) | |
516 | filerev = seen[f] |
|
628 | filerev = seen[f] | |
517 | if filerev != 0: |
|
629 | if filerev != 0: | |
@@ -530,8 +642,9 b' class queue:' | |||||
530 | revnum = chlog.rev(rev) |
|
642 | revnum = chlog.rev(rev) | |
531 |
|
643 | |||
532 | if update: |
|
644 | if update: | |
|
645 | self.check_localchanges(repo, refresh=False) | |||
533 | urev = self.qparents(repo, rev) |
|
646 | urev = self.qparents(repo, rev) | |
534 |
repo |
|
647 | hg.clean(repo, urev, wlock=wlock) | |
535 | repo.dirstate.write() |
|
648 | repo.dirstate.write() | |
536 |
|
649 | |||
537 | # save is a list of all the branches we are truncating away |
|
650 | # save is a list of all the branches we are truncating away | |
@@ -540,7 +653,6 b' class queue:' | |||||
540 | saveheads = [] |
|
653 | saveheads = [] | |
541 | savebases = {} |
|
654 | savebases = {} | |
542 |
|
655 | |||
543 | tip = chlog.tip() |
|
|||
544 | heads = limitheads(chlog, rev) |
|
656 | heads = limitheads(chlog, rev) | |
545 | seen = {} |
|
657 | seen = {} | |
546 |
|
658 | |||
@@ -571,7 +683,7 b' class queue:' | |||||
571 | savebases[x] = 1 |
|
683 | savebases[x] = 1 | |
572 |
|
684 | |||
573 | # create a changegroup for all the branches we need to keep |
|
685 | # create a changegroup for all the branches we need to keep | |
574 |
if backup |
|
686 | if backup == "all": | |
575 | backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') |
|
687 | backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') | |
576 | bundle(backupch) |
|
688 | bundle(backupch) | |
577 | if saveheads: |
|
689 | if saveheads: | |
@@ -586,37 +698,89 b' class queue:' | |||||
586 | if saveheads: |
|
698 | if saveheads: | |
587 | self.ui.status("adding branch\n") |
|
699 | self.ui.status("adding branch\n") | |
588 | commands.unbundle(self.ui, repo, chgrpfile, update=False) |
|
700 | commands.unbundle(self.ui, repo, chgrpfile, update=False) | |
589 |
if backup |
|
701 | if backup != "strip": | |
590 | os.unlink(chgrpfile) |
|
702 | os.unlink(chgrpfile) | |
591 |
|
703 | |||
592 | def isapplied(self, patch): |
|
704 | def isapplied(self, patch): | |
593 | """returns (index, rev, patch)""" |
|
705 | """returns (index, rev, patch)""" | |
594 | for i in xrange(len(self.applied)): |
|
706 | for i in xrange(len(self.applied)): | |
595 |
|
|
707 | a = self.applied[i] | |
596 |
a = p |
|
708 | if a.name == patch: | |
597 | if a[1] == patch: |
|
709 | return (i, a.rev, a.name) | |
598 | return (i, a[0], a[1]) |
|
|||
599 | return None |
|
710 | return None | |
600 |
|
711 | |||
601 | def lookup(self, patch): |
|
712 | # if the exact patch name does not exist, we try a few | |
|
713 | # variations. If strict is passed, we try only #1 | |||
|
714 | # | |||
|
715 | # 1) a number to indicate an offset in the series file | |||
|
716 | # 2) a unique substring of the patch name was given | |||
|
717 | # 3) patchname[-+]num to indicate an offset in the series file | |||
|
718 | def lookup(self, patch, strict=False): | |||
|
719 | patch = patch and str(patch) | |||
|
720 | ||||
|
721 | def partial_name(s): | |||
|
722 | if s in self.series: | |||
|
723 | return s | |||
|
724 | matches = [x for x in self.series if s in x] | |||
|
725 | if len(matches) > 1: | |||
|
726 | self.ui.warn(_('patch name "%s" is ambiguous:\n') % s) | |||
|
727 | for m in matches: | |||
|
728 | self.ui.warn(' %s\n' % m) | |||
|
729 | return None | |||
|
730 | if matches: | |||
|
731 | return matches[0] | |||
|
732 | if len(self.series) > 0 and len(self.applied) > 0: | |||
|
733 | if s == 'qtip': | |||
|
734 | return self.series[self.series_end()-1] | |||
|
735 | if s == 'qbase': | |||
|
736 | return self.series[0] | |||
|
737 | return None | |||
602 | if patch == None: |
|
738 | if patch == None: | |
603 | return None |
|
739 | return None | |
604 | if patch in self.series: |
|
740 | ||
605 | return patch |
|
741 | # we don't want to return a partial match until we make | |
606 | if not os.path.isfile(os.path.join(self.path, patch)): |
|
742 | # sure the file name passed in does not exist (checked below) | |
|
743 | res = partial_name(patch) | |||
|
744 | if res and res == patch: | |||
|
745 | return res | |||
|
746 | ||||
|
747 | if not os.path.isfile(self.join(patch)): | |||
607 | try: |
|
748 | try: | |
608 | sno = int(patch) |
|
749 | sno = int(patch) | |
609 | except(ValueError, OverflowError): |
|
750 | except(ValueError, OverflowError): | |
610 | self.ui.warn("patch %s not in series\n" % patch) |
|
751 | pass | |
611 |
|
|
752 | else: | |
612 |
if sno |
|
753 | if sno < len(self.series): | |
613 | self.ui.warn("patch number %d is out of range\n" % sno) |
|
754 | return self.series[sno] | |
614 |
|
|
755 | if not strict: | |
615 | patch = self.series[sno] |
|
756 | # return any partial match made above | |
616 |
e |
|
757 | if res: | |
617 | self.ui.warn("patch %s not in series\n" % patch) |
|
758 | return res | |
618 | sys.exit(1) |
|
759 | minus = patch.rsplit('-', 1) | |
619 | return patch |
|
760 | if len(minus) > 1: | |
|
761 | res = partial_name(minus[0]) | |||
|
762 | if res: | |||
|
763 | i = self.series.index(res) | |||
|
764 | try: | |||
|
765 | off = int(minus[1] or 1) | |||
|
766 | except(ValueError, OverflowError): | |||
|
767 | pass | |||
|
768 | else: | |||
|
769 | if i - off >= 0: | |||
|
770 | return self.series[i - off] | |||
|
771 | plus = patch.rsplit('+', 1) | |||
|
772 | if len(plus) > 1: | |||
|
773 | res = partial_name(plus[0]) | |||
|
774 | if res: | |||
|
775 | i = self.series.index(res) | |||
|
776 | try: | |||
|
777 | off = int(plus[1] or 1) | |||
|
778 | except(ValueError, OverflowError): | |||
|
779 | pass | |||
|
780 | else: | |||
|
781 | if i + off < len(self.series): | |||
|
782 | return self.series[i + off] | |||
|
783 | raise util.Abort(_("patch %s not in series") % patch) | |||
620 |
|
784 | |||
621 | def push(self, repo, patch=None, force=False, list=False, |
|
785 | def push(self, repo, patch=None, force=False, list=False, | |
622 | mergeq=None, wlock=None): |
|
786 | mergeq=None, wlock=None): | |
@@ -624,10 +788,10 b' class queue:' | |||||
624 | wlock = repo.wlock() |
|
788 | wlock = repo.wlock() | |
625 | patch = self.lookup(patch) |
|
789 | patch = self.lookup(patch) | |
626 | if patch and self.isapplied(patch): |
|
790 | if patch and self.isapplied(patch): | |
627 | self.ui.warn("patch %s is already applied\n" % patch) |
|
791 | self.ui.warn(_("patch %s is already applied\n") % patch) | |
628 | sys.exit(1) |
|
792 | sys.exit(1) | |
629 | if self.series_end() == len(self.series): |
|
793 | if self.series_end() == len(self.series): | |
630 |
self.ui.warn(" |
|
794 | self.ui.warn(_("patch series fully applied\n")) | |
631 | sys.exit(1) |
|
795 | sys.exit(1) | |
632 | if not force: |
|
796 | if not force: | |
633 | self.check_localchanges(repo) |
|
797 | self.check_localchanges(repo) | |
@@ -646,7 +810,7 b' class queue:' | |||||
646 | ret = self.mergepatch(repo, mergeq, s, wlock) |
|
810 | ret = self.mergepatch(repo, mergeq, s, wlock) | |
647 | else: |
|
811 | else: | |
648 | ret = self.apply(repo, s, list, wlock=wlock) |
|
812 | ret = self.apply(repo, s, list, wlock=wlock) | |
649 |
top = self.applied[-1]. |
|
813 | top = self.applied[-1].name | |
650 | if ret[0]: |
|
814 | if ret[0]: | |
651 | self.ui.write("Errors during apply, please fix and refresh %s\n" % |
|
815 | self.ui.write("Errors during apply, please fix and refresh %s\n" % | |
652 | top) |
|
816 | top) | |
@@ -654,7 +818,8 b' class queue:' | |||||
654 | self.ui.write("Now at: %s\n" % top) |
|
818 | self.ui.write("Now at: %s\n" % top) | |
655 | return ret[0] |
|
819 | return ret[0] | |
656 |
|
820 | |||
657 |
def pop(self, repo, patch=None, force=False, update=True, |
|
821 | def pop(self, repo, patch=None, force=False, update=True, all=False, | |
|
822 | wlock=None): | |||
658 | def getfile(f, rev): |
|
823 | def getfile(f, rev): | |
659 | t = repo.file(f).read(rev) |
|
824 | t = repo.file(f).read(rev) | |
660 | try: |
|
825 | try: | |
@@ -675,15 +840,14 b' class queue:' | |||||
675 | patch = self.lookup(patch) |
|
840 | patch = self.lookup(patch) | |
676 | info = self.isapplied(patch) |
|
841 | info = self.isapplied(patch) | |
677 | if not info: |
|
842 | if not info: | |
678 |
sel |
|
843 | raise util.Abort(_("patch %s is not applied") % patch) | |
679 | sys.exit(1) |
|
|||
680 | if len(self.applied) == 0: |
|
844 | if len(self.applied) == 0: | |
681 |
self.ui.warn(" |
|
845 | self.ui.warn(_("no patches applied\n")) | |
682 | sys.exit(1) |
|
846 | sys.exit(1) | |
683 |
|
847 | |||
684 | if not update: |
|
848 | if not update: | |
685 | parents = repo.dirstate.parents() |
|
849 | parents = repo.dirstate.parents() | |
686 |
rr = [ revlog.bin(x. |
|
850 | rr = [ revlog.bin(x.rev) for x in self.applied ] | |
687 | for p in parents: |
|
851 | for p in parents: | |
688 | if p in rr: |
|
852 | if p in rr: | |
689 | self.ui.warn("qpop: forcing dirstate update\n") |
|
853 | self.ui.warn("qpop: forcing dirstate update\n") | |
@@ -695,7 +859,17 b' class queue:' | |||||
695 | self.applied_dirty = 1; |
|
859 | self.applied_dirty = 1; | |
696 | end = len(self.applied) |
|
860 | end = len(self.applied) | |
697 | if not patch: |
|
861 | if not patch: | |
698 | info = [len(self.applied) - 1] + self.applied[-1].split(':') |
|
862 | if all: | |
|
863 | popi = 0 | |||
|
864 | else: | |||
|
865 | popi = len(self.applied) - 1 | |||
|
866 | else: | |||
|
867 | popi = info[0] + 1 | |||
|
868 | if popi >= end: | |||
|
869 | self.ui.warn("qpop: %s is already at the top\n" % patch) | |||
|
870 | return | |||
|
871 | info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] | |||
|
872 | ||||
699 | start = info[0] |
|
873 | start = info[0] | |
700 | rev = revlog.bin(info[1]) |
|
874 | rev = revlog.bin(info[1]) | |
701 |
|
875 | |||
@@ -705,17 +879,16 b' class queue:' | |||||
705 | top = self.check_toppatch(repo) |
|
879 | top = self.check_toppatch(repo) | |
706 | qp = self.qparents(repo, rev) |
|
880 | qp = self.qparents(repo, rev) | |
707 | changes = repo.changelog.read(qp) |
|
881 | changes = repo.changelog.read(qp) | |
708 | mf1 = repo.manifest.readflags(changes[0]) |
|
|||
709 | mmap = repo.manifest.read(changes[0]) |
|
882 | mmap = repo.manifest.read(changes[0]) | |
710 |
|
|
883 | m, a, r, d, u = repo.status(qp, top)[:5] | |
711 | if d: |
|
884 | if d: | |
712 | raise util.Abort("deletions found between repo revs") |
|
885 | raise util.Abort("deletions found between repo revs") | |
713 |
for f in |
|
886 | for f in m: | |
714 | getfile(f, mmap[f]) |
|
887 | getfile(f, mmap[f]) | |
715 | for f in r: |
|
888 | for f in r: | |
716 | getfile(f, mmap[f]) |
|
889 | getfile(f, mmap[f]) | |
717 |
util.set_exec(repo.wjoin(f), m |
|
890 | util.set_exec(repo.wjoin(f), mmap.execf(f)) | |
718 |
repo.dirstate.update( |
|
891 | repo.dirstate.update(m + r, 'n') | |
719 | for f in a: |
|
892 | for f in a: | |
720 | try: os.unlink(repo.wjoin(f)) |
|
893 | try: os.unlink(repo.wjoin(f)) | |
721 | except: raise |
|
894 | except: raise | |
@@ -727,36 +900,46 b' class queue:' | |||||
727 | self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
|
900 | self.strip(repo, rev, update=False, backup='strip', wlock=wlock) | |
728 | del self.applied[start:end] |
|
901 | del self.applied[start:end] | |
729 | if len(self.applied): |
|
902 | if len(self.applied): | |
730 |
self.ui.write("Now at: %s\n" % self.applied[-1]. |
|
903 | self.ui.write("Now at: %s\n" % self.applied[-1].name) | |
731 | else: |
|
904 | else: | |
732 | self.ui.write("Patch queue now empty\n") |
|
905 | self.ui.write("Patch queue now empty\n") | |
733 |
|
906 | |||
734 |
def diff(self, repo, |
|
907 | def diff(self, repo, pats, opts): | |
735 | top = self.check_toppatch(repo) |
|
908 | top = self.check_toppatch(repo) | |
736 | if not top: |
|
909 | if not top: | |
737 | self.ui.write("No patches applied\n") |
|
910 | self.ui.write("No patches applied\n") | |
738 | return |
|
911 | return | |
739 | qp = self.qparents(repo, top) |
|
912 | qp = self.qparents(repo, top) | |
740 | commands.dodiff(sys.stdout, self.ui, repo, qp, None, files) |
|
913 | self.printdiff(repo, qp, files=pats, opts=opts) | |
741 |
|
914 | |||
742 |
def refresh(self, repo, s |
|
915 | def refresh(self, repo, pats=None, **opts): | |
743 | if len(self.applied) == 0: |
|
916 | if len(self.applied) == 0: | |
744 | self.ui.write("No patches applied\n") |
|
917 | self.ui.write("No patches applied\n") | |
745 | return |
|
918 | return | |
746 | wlock = repo.wlock() |
|
919 | wlock = repo.wlock() | |
747 | self.check_toppatch(repo) |
|
920 | self.check_toppatch(repo) | |
748 | qp = self.qparents(repo) |
|
921 | (top, patch) = (self.applied[-1].rev, self.applied[-1].name) | |
749 | (top, patch) = self.applied[-1].split(':') |
|
|||
750 | top = revlog.bin(top) |
|
922 | top = revlog.bin(top) | |
751 | cparents = repo.changelog.parents(top) |
|
923 | cparents = repo.changelog.parents(top) | |
752 | patchparent = self.qparents(repo, top) |
|
924 | patchparent = self.qparents(repo, top) | |
753 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
925 | message, comments, user, date, patchfound = self.readheaders(patch) | |
754 |
|
926 | |||
755 | patchf = self.opener(patch, "w") |
|
927 | patchf = self.opener(patch, "w") | |
|
928 | msg = opts.get('msg', '').rstrip() | |||
|
929 | if msg: | |||
|
930 | if comments: | |||
|
931 | # Remove existing message. | |||
|
932 | ci = 0 | |||
|
933 | for mi in range(len(message)): | |||
|
934 | while message[mi] != comments[ci]: | |||
|
935 | ci += 1 | |||
|
936 | del comments[ci] | |||
|
937 | comments.append(msg) | |||
756 | if comments: |
|
938 | if comments: | |
757 | comments = "\n".join(comments) + '\n\n' |
|
939 | comments = "\n".join(comments) + '\n\n' | |
758 | patchf.write(comments) |
|
940 | patchf.write(comments) | |
759 |
|
941 | |||
|
942 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |||
760 | tip = repo.changelog.tip() |
|
943 | tip = repo.changelog.tip() | |
761 | if top == tip: |
|
944 | if top == tip: | |
762 | # if the top of our patch queue is also the tip, there is an |
|
945 | # if the top of our patch queue is also the tip, there is an | |
@@ -769,30 +952,30 b' class queue:' | |||||
769 | # patch already |
|
952 | # patch already | |
770 | # |
|
953 | # | |
771 | # this should really read: |
|
954 | # this should really read: | |
772 |
# |
|
955 | # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] | |
773 | # but we do it backwards to take advantage of manifest/chlog |
|
956 | # but we do it backwards to take advantage of manifest/chlog | |
774 |
# caching against the next repo. |
|
957 | # caching against the next repo.status call | |
775 | # |
|
958 | # | |
776 |
|
|
959 | mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] | |
777 | if short: |
|
960 | if opts.get('short'): | |
778 |
filelist = |
|
961 | filelist = mm + aa + dd | |
779 | else: |
|
962 | else: | |
780 | filelist = None |
|
963 | filelist = None | |
781 |
|
|
964 | m, a, r, d, u = repo.status(files=filelist)[:5] | |
782 |
|
965 | |||
783 | # we might end up with files that were added between tip and |
|
966 | # we might end up with files that were added between tip and | |
784 | # the dirstate parent, but then changed in the local dirstate. |
|
967 | # the dirstate parent, but then changed in the local dirstate. | |
785 | # in this case, we want them to only show up in the added section |
|
968 | # in this case, we want them to only show up in the added section | |
786 |
for x in |
|
969 | for x in m: | |
787 | if x not in aa: |
|
970 | if x not in aa: | |
788 |
|
|
971 | mm.append(x) | |
789 | # we might end up with files added by the local dirstate that |
|
972 | # we might end up with files added by the local dirstate that | |
790 | # were deleted by the patch. In this case, they should only |
|
973 | # were deleted by the patch. In this case, they should only | |
791 | # show up in the changed section. |
|
974 | # show up in the changed section. | |
792 | for x in a: |
|
975 | for x in a: | |
793 | if x in dd: |
|
976 | if x in dd: | |
794 | del dd[dd.index(x)] |
|
977 | del dd[dd.index(x)] | |
795 |
|
|
978 | mm.append(x) | |
796 | else: |
|
979 | else: | |
797 | aa.append(x) |
|
980 | aa.append(x) | |
798 | # make sure any files deleted in the local dirstate |
|
981 | # make sure any files deleted in the local dirstate | |
@@ -803,70 +986,97 b' class queue:' | |||||
803 | del aa[aa.index(x)] |
|
986 | del aa[aa.index(x)] | |
804 | forget.append(x) |
|
987 | forget.append(x) | |
805 | continue |
|
988 | continue | |
806 |
elif x in |
|
989 | elif x in mm: | |
807 |
del |
|
990 | del mm[mm.index(x)] | |
808 | dd.append(x) |
|
991 | dd.append(x) | |
809 |
|
992 | |||
810 |
|
|
993 | m = list(util.unique(mm)) | |
811 | r = list(util.unique(dd)) |
|
994 | r = list(util.unique(dd)) | |
812 | a = list(util.unique(aa)) |
|
995 | a = list(util.unique(aa)) | |
813 |
filelist = |
|
996 | filelist = filter(matchfn, util.unique(m + r + a)) | |
814 |
|
|
997 | self.printdiff(repo, patchparent, files=filelist, | |
815 |
|
|
998 | changes=(m, a, r, [], u), fp=patchf) | |
816 | patchf.close() |
|
999 | patchf.close() | |
817 |
|
1000 | |||
818 | changes = repo.changelog.read(tip) |
|
1001 | changes = repo.changelog.read(tip) | |
819 | repo.dirstate.setparents(*cparents) |
|
1002 | repo.dirstate.setparents(*cparents) | |
|
1003 | copies = [(f, repo.dirstate.copied(f)) for f in a] | |||
820 | repo.dirstate.update(a, 'a') |
|
1004 | repo.dirstate.update(a, 'a') | |
|
1005 | for dst, src in copies: | |||
|
1006 | repo.dirstate.copy(src, dst) | |||
821 | repo.dirstate.update(r, 'r') |
|
1007 | repo.dirstate.update(r, 'r') | |
822 | repo.dirstate.update(c, 'n') |
|
1008 | # if the patch excludes a modified file, mark that file with mtime=0 | |
|
1009 | # so status can see it. | |||
|
1010 | mm = [] | |||
|
1011 | for i in range(len(m)-1, -1, -1): | |||
|
1012 | if not matchfn(m[i]): | |||
|
1013 | mm.append(m[i]) | |||
|
1014 | del m[i] | |||
|
1015 | repo.dirstate.update(m, 'n') | |||
|
1016 | repo.dirstate.update(mm, 'n', st_mtime=0) | |||
823 | repo.dirstate.forget(forget) |
|
1017 | repo.dirstate.forget(forget) | |
824 |
|
1018 | |||
825 |
if not m |
|
1019 | if not msg: | |
826 | message = "patch queue: %s\n" % patch |
|
1020 | if not message: | |
|
1021 | message = "patch queue: %s\n" % patch | |||
|
1022 | else: | |||
|
1023 | message = "\n".join(message) | |||
827 | else: |
|
1024 | else: | |
828 |
message = |
|
1025 | message = msg | |
|
1026 | ||||
829 | self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
|
1027 | self.strip(repo, top, update=False, backup='strip', wlock=wlock) | |
830 | n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
|
1028 | n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) | |
831 |
self.applied[-1] = revlog.hex(n) |
|
1029 | self.applied[-1] = statusentry(revlog.hex(n), patch) | |
832 | self.applied_dirty = 1 |
|
1030 | self.applied_dirty = 1 | |
833 | else: |
|
1031 | else: | |
834 |
|
|
1032 | self.printdiff(repo, patchparent, fp=patchf) | |
835 | patchf.close() |
|
1033 | patchf.close() | |
836 | self.pop(repo, force=True, wlock=wlock) |
|
1034 | self.pop(repo, force=True, wlock=wlock) | |
837 | self.push(repo, force=True, wlock=wlock) |
|
1035 | self.push(repo, force=True, wlock=wlock) | |
838 |
|
1036 | |||
839 | def init(self, repo, create=False): |
|
1037 | def init(self, repo, create=False): | |
840 | if os.path.isdir(self.path): |
|
1038 | if os.path.isdir(self.path): | |
841 | raise util.Abort("patch queue directory already exists") |
|
1039 | raise util.Abort(_("patch queue directory already exists")) | |
842 | os.mkdir(self.path) |
|
1040 | os.mkdir(self.path) | |
843 | if create: |
|
1041 | if create: | |
844 | return self.qrepo(create=True) |
|
1042 | return self.qrepo(create=True) | |
845 |
|
1043 | |||
846 | def unapplied(self, repo, patch=None): |
|
1044 | def unapplied(self, repo, patch=None): | |
847 | if patch and patch not in self.series: |
|
1045 | if patch and patch not in self.series: | |
848 |
sel |
|
1046 | raise util.Abort(_("patch %s is not in series file") % patch) | |
849 | sys.exit(1) |
|
|||
850 | if not patch: |
|
1047 | if not patch: | |
851 | start = self.series_end() |
|
1048 | start = self.series_end() | |
852 | else: |
|
1049 | else: | |
853 | start = self.series.index(patch) + 1 |
|
1050 | start = self.series.index(patch) + 1 | |
854 | for p in self.series[start:]: |
|
1051 | unapplied = [] | |
855 | self.ui.write("%s\n" % p) |
|
1052 | for i in xrange(start, len(self.series)): | |
|
1053 | pushable, reason = self.pushable(i) | |||
|
1054 | if pushable: | |||
|
1055 | unapplied.append((i, self.series[i])) | |||
|
1056 | self.explain_pushable(i) | |||
|
1057 | return unapplied | |||
856 |
|
1058 | |||
857 | def qseries(self, repo, missing=None): |
|
1059 | def qseries(self, repo, missing=None, summary=False): | |
858 | start = self.series_end() |
|
1060 | start = self.series_end(all_patches=True) | |
859 | if not missing: |
|
1061 | if not missing: | |
860 |
for |
|
1062 | for i in range(len(self.series)): | |
|
1063 | patch = self.series[i] | |||
861 | if self.ui.verbose: |
|
1064 | if self.ui.verbose: | |
862 | self.ui.write("%d A " % self.series.index(p)) |
|
1065 | if i < start: | |
863 | self.ui.write("%s\n" % p) |
|
1066 | status = 'A' | |
864 | for p in self.series[start:]: |
|
1067 | elif self.pushable(i)[0]: | |
865 | if self.ui.verbose: |
|
1068 | status = 'U' | |
866 | self.ui.write("%d U " % self.series.index(p)) |
|
1069 | else: | |
867 | self.ui.write("%s\n" % p) |
|
1070 | status = 'G' | |
|
1071 | self.ui.write('%d %s ' % (i, status)) | |||
|
1072 | if summary: | |||
|
1073 | msg = self.readheaders(patch)[0] | |||
|
1074 | msg = msg and ': ' + msg[0] or ': ' | |||
|
1075 | else: | |||
|
1076 | msg = '' | |||
|
1077 | self.ui.write('%s%s\n' % (patch, msg)) | |||
868 | else: |
|
1078 | else: | |
869 | list = [] |
|
1079 | msng_list = [] | |
870 | for root, dirs, files in os.walk(self.path): |
|
1080 | for root, dirs, files in os.walk(self.path): | |
871 | d = root[len(self.path) + 1:] |
|
1081 | d = root[len(self.path) + 1:] | |
872 | for f in files: |
|
1082 | for f in files: | |
@@ -874,21 +1084,19 b' class queue:' | |||||
874 | if (fl not in self.series and |
|
1084 | if (fl not in self.series and | |
875 | fl not in (self.status_path, self.series_path) |
|
1085 | fl not in (self.status_path, self.series_path) | |
876 | and not fl.startswith('.')): |
|
1086 | and not fl.startswith('.')): | |
877 | list.append(fl) |
|
1087 | msng_list.append(fl) | |
878 | list.sort() |
|
1088 | msng_list.sort() | |
879 |
|
|
1089 | for x in msng_list: | |
880 |
f |
|
1090 | if self.ui.verbose: | |
881 |
|
|
1091 | self.ui.write("D ") | |
882 |
|
|
1092 | self.ui.write("%s\n" % x) | |
883 | self.ui.write("%s\n" % x) |
|
|||
884 |
|
1093 | |||
885 | def issaveline(self, l): |
|
1094 | def issaveline(self, l): | |
886 | name = l.split(':')[1] |
|
1095 | if l.name == '.hg.patches.save.line': | |
887 | if name == '.hg.patches.save.line': |
|
|||
888 | return True |
|
1096 | return True | |
889 |
|
1097 | |||
890 | def qrepo(self, create=False): |
|
1098 | def qrepo(self, create=False): | |
891 |
if create or os.path.isdir( |
|
1099 | if create or os.path.isdir(self.join(".hg")): | |
892 | return hg.repository(self.ui, path=self.path, create=create) |
|
1100 | return hg.repository(self.ui, path=self.path, create=create) | |
893 |
|
1101 | |||
894 | def restore(self, repo, rev, delete=None, qupdate=None): |
|
1102 | def restore(self, repo, rev, delete=None, qupdate=None): | |
@@ -909,19 +1117,18 b' class queue:' | |||||
909 | qpp = [ hg.bin(x) for x in l ] |
|
1117 | qpp = [ hg.bin(x) for x in l ] | |
910 | elif datastart != None: |
|
1118 | elif datastart != None: | |
911 | l = lines[i].rstrip() |
|
1119 | l = lines[i].rstrip() | |
912 |
|
|
1120 | se = statusentry(l) | |
913 |
|
|
1121 | file_ = se.name | |
914 |
|
|
1122 | if se.rev: | |
915 |
|
|
1123 | applied.append(se) | |
916 |
|
|
1124 | series.append(file_) | |
917 | series.append(file) |
|
|||
918 | if datastart == None: |
|
1125 | if datastart == None: | |
919 | self.ui.warn("No saved patch data found\n") |
|
1126 | self.ui.warn("No saved patch data found\n") | |
920 | return 1 |
|
1127 | return 1 | |
921 | self.ui.warn("restoring status: %s\n" % lines[0]) |
|
1128 | self.ui.warn("restoring status: %s\n" % lines[0]) | |
922 | self.full_series = series |
|
1129 | self.full_series = series | |
923 | self.applied = applied |
|
1130 | self.applied = applied | |
924 |
self.re |
|
1131 | self.parse_series() | |
925 | self.series_dirty = 1 |
|
1132 | self.series_dirty = 1 | |
926 | self.applied_dirty = 1 |
|
1133 | self.applied_dirty = 1 | |
927 | heads = repo.changelog.heads() |
|
1134 | heads = repo.changelog.heads() | |
@@ -945,7 +1152,7 b' class queue:' | |||||
945 | if not r: |
|
1152 | if not r: | |
946 | self.ui.warn("Unable to load queue repository\n") |
|
1153 | self.ui.warn("Unable to load queue repository\n") | |
947 | return 1 |
|
1154 | return 1 | |
948 | r.update(qpp[0], allow=False, force=True) |
|
1155 | hg.clean(r, qpp[0]) | |
949 |
|
1156 | |||
950 | def save(self, repo, msg=None): |
|
1157 | def save(self, repo, msg=None): | |
951 | if len(self.applied) == 0: |
|
1158 | if len(self.applied) == 0: | |
@@ -965,30 +1172,49 b' class queue:' | |||||
965 | pp = r.dirstate.parents() |
|
1172 | pp = r.dirstate.parents() | |
966 | msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
|
1173 | msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) | |
967 | msg += "\n\nPatch Data:\n" |
|
1174 | msg += "\n\nPatch Data:\n" | |
968 |
text = msg + "\n".join(self.applied) + '\n' + (ar and |
|
1175 | text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and | |
969 | + '\n' or "") |
|
1176 | "\n".join(ar) + '\n' or "") | |
970 | n = repo.commit(None, text, user=None, force=1) |
|
1177 | n = repo.commit(None, text, user=None, force=1) | |
971 | if not n: |
|
1178 | if not n: | |
972 | self.ui.warn("repo commit failed\n") |
|
1179 | self.ui.warn("repo commit failed\n") | |
973 | return 1 |
|
1180 | return 1 | |
974 |
self.applied.append(revlog.hex(n) |
|
1181 | self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line')) | |
975 | self.applied_dirty = 1 |
|
1182 | self.applied_dirty = 1 | |
976 |
|
1183 | |||
977 | def series_end(self): |
|
1184 | def full_series_end(self): | |
|
1185 | if len(self.applied) > 0: | |||
|
1186 | p = self.applied[-1].name | |||
|
1187 | end = self.find_series(p) | |||
|
1188 | if end == None: | |||
|
1189 | return len(self.full_series) | |||
|
1190 | return end + 1 | |||
|
1191 | return 0 | |||
|
1192 | ||||
|
1193 | def series_end(self, all_patches=False): | |||
978 | end = 0 |
|
1194 | end = 0 | |
|
1195 | def next(start): | |||
|
1196 | if all_patches: | |||
|
1197 | return start | |||
|
1198 | i = start | |||
|
1199 | while i < len(self.series): | |||
|
1200 | p, reason = self.pushable(i) | |||
|
1201 | if p: | |||
|
1202 | break | |||
|
1203 | self.explain_pushable(i) | |||
|
1204 | i += 1 | |||
|
1205 | return i | |||
979 | if len(self.applied) > 0: |
|
1206 | if len(self.applied) > 0: | |
980 |
|
|
1207 | p = self.applied[-1].name | |
981 | try: |
|
1208 | try: | |
982 | end = self.series.index(p) |
|
1209 | end = self.series.index(p) | |
983 | except ValueError: |
|
1210 | except ValueError: | |
984 | return 0 |
|
1211 | return 0 | |
985 | return end + 1 |
|
1212 | return next(end + 1) | |
986 | return end |
|
1213 | return next(end) | |
987 |
|
1214 | |||
988 | def qapplied(self, repo, patch=None): |
|
1215 | def qapplied(self, repo, patch=None): | |
989 | if patch and patch not in self.series: |
|
1216 | if patch and patch not in self.series: | |
990 |
sel |
|
1217 | raise util.Abort(_("patch %s is not in series file") % patch) | |
991 | sys.exit(1) |
|
|||
992 | if not patch: |
|
1218 | if not patch: | |
993 | end = len(self.applied) |
|
1219 | end = len(self.applied) | |
994 | else: |
|
1220 | else: | |
@@ -998,9 +1224,11 b' class queue:' | |||||
998 | self.ui.write("%s\n" % p) |
|
1224 | self.ui.write("%s\n" % p) | |
999 |
|
1225 | |||
1000 | def appliedname(self, index): |
|
1226 | def appliedname(self, index): | |
1001 | p = self.applied[index] |
|
1227 | pname = self.applied[index].name | |
1002 | if not self.ui.verbose: |
|
1228 | if not self.ui.verbose: | |
1003 |
p = p |
|
1229 | p = pname | |
|
1230 | else: | |||
|
1231 | p = str(self.series.index(pname)) + " " + pname | |||
1004 | return p |
|
1232 | return p | |
1005 |
|
1233 | |||
1006 | def top(self, repo): |
|
1234 | def top(self, repo): | |
@@ -1015,7 +1243,10 b' class queue:' | |||||
1015 | if end == len(self.series): |
|
1243 | if end == len(self.series): | |
1016 | self.ui.write("All patches applied\n") |
|
1244 | self.ui.write("All patches applied\n") | |
1017 | else: |
|
1245 | else: | |
1018 |
|
|
1246 | p = self.series[end] | |
|
1247 | if self.ui.verbose: | |||
|
1248 | self.ui.write("%d " % self.series.index(p)) | |||
|
1249 | self.ui.write(p + '\n') | |||
1019 |
|
1250 | |||
1020 | def prev(self, repo): |
|
1251 | def prev(self, repo): | |
1021 | if len(self.applied) > 1: |
|
1252 | if len(self.applied) > 1: | |
@@ -1028,36 +1259,33 b' class queue:' | |||||
1028 |
|
1259 | |||
1029 | def qimport(self, repo, files, patch=None, existing=None, force=None): |
|
1260 | def qimport(self, repo, files, patch=None, existing=None, force=None): | |
1030 | if len(files) > 1 and patch: |
|
1261 | if len(files) > 1 and patch: | |
1031 |
sel |
|
1262 | raise util.Abort(_('option "-n" not valid when importing multiple ' | |
1032 | sys.exit(1) |
|
1263 | 'files')) | |
1033 | i = 0 |
|
1264 | i = 0 | |
1034 | added = [] |
|
1265 | added = [] | |
1035 | for filename in files: |
|
1266 | for filename in files: | |
1036 | if existing: |
|
1267 | if existing: | |
1037 | if not patch: |
|
1268 | if not patch: | |
1038 | patch = filename |
|
1269 | patch = filename | |
1039 |
if not os.path.isfile( |
|
1270 | if not os.path.isfile(self.join(patch)): | |
1040 |
sel |
|
1271 | raise util.Abort(_("patch %s does not exist") % patch) | |
1041 | sys.exit(1) |
|
|||
1042 | else: |
|
1272 | else: | |
1043 | try: |
|
1273 | try: | |
1044 | text = file(filename).read() |
|
1274 | text = file(filename).read() | |
1045 | except IOError: |
|
1275 | except IOError: | |
1046 |
sel |
|
1276 | raise util.Abort(_("unable to read %s") % patch) | |
1047 | sys.exit(1) |
|
|||
1048 | if not patch: |
|
1277 | if not patch: | |
1049 | patch = os.path.split(filename)[1] |
|
1278 | patch = os.path.split(filename)[1] | |
1050 |
if not force and os.path. |
|
1279 | if not force and os.path.exists(self.join(patch)): | |
1051 |
sel |
|
1280 | raise util.Abort(_('patch "%s" already exists') % patch) | |
1052 | sys.exit(1) |
|
|||
1053 | patchf = self.opener(patch, "w") |
|
1281 | patchf = self.opener(patch, "w") | |
1054 | patchf.write(text) |
|
1282 | patchf.write(text) | |
1055 | if patch in self.series: |
|
1283 | if patch in self.series: | |
1056 |
sel |
|
1284 | raise util.Abort(_('patch %s is already in the series file') | |
1057 | sys.exit(1) |
|
1285 | % patch) | |
1058 | index = self.series_end() + i |
|
1286 | index = self.full_series_end() + i | |
1059 | self.full_series[index:index] = [patch] |
|
1287 | self.full_series[index:index] = [patch] | |
1060 |
self.re |
|
1288 | self.parse_series() | |
1061 | self.ui.warn("adding %s to series file\n" % patch) |
|
1289 | self.ui.warn("adding %s to series file\n" % patch) | |
1062 | i += 1 |
|
1290 | i += 1 | |
1063 | added.append(patch) |
|
1291 | added.append(patch) | |
@@ -1067,34 +1295,44 b' class queue:' | |||||
1067 | if qrepo: |
|
1295 | if qrepo: | |
1068 | qrepo.add(added) |
|
1296 | qrepo.add(added) | |
1069 |
|
1297 | |||
1070 | def delete(ui, repo, patch, **opts): |
|
1298 | def delete(ui, repo, patch, *patches, **opts): | |
1071 |
"""remove |
|
1299 | """remove patches from queue | |
1072 | q = repomap[repo] |
|
1300 | ||
1073 | q.delete(repo, patch) |
|
1301 | The patches must not be applied. | |
|
1302 | With -k, the patch files are preserved in the patch directory.""" | |||
|
1303 | q = repo.mq | |||
|
1304 | q.delete(repo, (patch,) + patches, keep=opts.get('keep')) | |||
1074 | q.save_dirty() |
|
1305 | q.save_dirty() | |
1075 | return 0 |
|
1306 | return 0 | |
1076 |
|
1307 | |||
1077 | def applied(ui, repo, patch=None, **opts): |
|
1308 | def applied(ui, repo, patch=None, **opts): | |
1078 | """print the patches already applied""" |
|
1309 | """print the patches already applied""" | |
1079 |
|
|
1310 | repo.mq.qapplied(repo, patch) | |
1080 | return 0 |
|
1311 | return 0 | |
1081 |
|
1312 | |||
1082 | def unapplied(ui, repo, patch=None, **opts): |
|
1313 | def unapplied(ui, repo, patch=None, **opts): | |
1083 | """print the patches not yet applied""" |
|
1314 | """print the patches not yet applied""" | |
1084 |
|
|
1315 | for i, p in repo.mq.unapplied(repo, patch): | |
1085 | return 0 |
|
1316 | if ui.verbose: | |
|
1317 | ui.write("%d " % i) | |||
|
1318 | ui.write("%s\n" % p) | |||
1086 |
|
1319 | |||
1087 | def qimport(ui, repo, *filename, **opts): |
|
1320 | def qimport(ui, repo, *filename, **opts): | |
1088 | """import a patch""" |
|
1321 | """import a patch""" | |
1089 |
q = |
|
1322 | q = repo.mq | |
1090 | q.qimport(repo, filename, patch=opts['name'], |
|
1323 | q.qimport(repo, filename, patch=opts['name'], | |
1091 | existing=opts['existing'], force=opts['force']) |
|
1324 | existing=opts['existing'], force=opts['force']) | |
1092 | q.save_dirty() |
|
1325 | q.save_dirty() | |
1093 | return 0 |
|
1326 | return 0 | |
1094 |
|
1327 | |||
1095 | def init(ui, repo, **opts): |
|
1328 | def init(ui, repo, **opts): | |
1096 |
"""init a new queue repository |
|
1329 | """init a new queue repository | |
1097 | q = repomap[repo] |
|
1330 | ||
|
1331 | The queue repository is unversioned by default. If -c is | |||
|
1332 | specified, qinit will create a separate nested repository | |||
|
1333 | for patches. Use qcommit to commit changes to this queue | |||
|
1334 | repository.""" | |||
|
1335 | q = repo.mq | |||
1098 | r = q.init(repo, create=opts['create_repo']) |
|
1336 | r = q.init(repo, create=opts['create_repo']) | |
1099 | q.save_dirty() |
|
1337 | q.save_dirty() | |
1100 | if r: |
|
1338 | if r: | |
@@ -1106,68 +1344,254 b' def init(ui, repo, **opts):' | |||||
1106 | r.add(['.hgignore', 'series']) |
|
1344 | r.add(['.hgignore', 'series']) | |
1107 | return 0 |
|
1345 | return 0 | |
1108 |
|
1346 | |||
|
1347 | def clone(ui, source, dest=None, **opts): | |||
|
1348 | '''clone main and patch repository at same time | |||
|
1349 | ||||
|
1350 | If source is local, destination will have no patches applied. If | |||
|
1351 | source is remote, this command can not check if patches are | |||
|
1352 | applied in source, so cannot guarantee that patches are not | |||
|
1353 | applied in destination. If you clone remote repository, be sure | |||
|
1354 | before that it has no patches applied. | |||
|
1355 | ||||
|
1356 | Source patch repository is looked for in <src>/.hg/patches by | |||
|
1357 | default. Use -p <url> to change. | |||
|
1358 | ''' | |||
|
1359 | commands.setremoteconfig(ui, opts) | |||
|
1360 | if dest is None: | |||
|
1361 | dest = hg.defaultdest(source) | |||
|
1362 | sr = hg.repository(ui, ui.expandpath(source)) | |||
|
1363 | qbase, destrev = None, None | |||
|
1364 | if sr.local(): | |||
|
1365 | reposetup(ui, sr) | |||
|
1366 | if sr.mq.applied: | |||
|
1367 | qbase = revlog.bin(sr.mq.applied[0].rev) | |||
|
1368 | if not hg.islocal(dest): | |||
|
1369 | destrev = sr.parents(qbase)[0] | |||
|
1370 | ui.note(_('cloning main repo\n')) | |||
|
1371 | sr, dr = hg.clone(ui, sr, dest, | |||
|
1372 | pull=opts['pull'], | |||
|
1373 | rev=destrev, | |||
|
1374 | update=False, | |||
|
1375 | stream=opts['uncompressed']) | |||
|
1376 | ui.note(_('cloning patch repo\n')) | |||
|
1377 | spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'), | |||
|
1378 | dr.url() + '/.hg/patches', | |||
|
1379 | pull=opts['pull'], | |||
|
1380 | update=not opts['noupdate'], | |||
|
1381 | stream=opts['uncompressed']) | |||
|
1382 | if dr.local(): | |||
|
1383 | if qbase: | |||
|
1384 | ui.note(_('stripping applied patches from destination repo\n')) | |||
|
1385 | reposetup(ui, dr) | |||
|
1386 | dr.mq.strip(dr, qbase, update=False, backup=None) | |||
|
1387 | if not opts['noupdate']: | |||
|
1388 | ui.note(_('updating destination repo\n')) | |||
|
1389 | hg.update(dr, dr.changelog.tip()) | |||
|
1390 | ||||
1109 | def commit(ui, repo, *pats, **opts): |
|
1391 | def commit(ui, repo, *pats, **opts): | |
1110 | """commit changes in the queue repository""" |
|
1392 | """commit changes in the queue repository""" | |
1111 |
q = |
|
1393 | q = repo.mq | |
1112 | r = q.qrepo() |
|
1394 | r = q.qrepo() | |
1113 | if not r: raise util.Abort('no queue repository') |
|
1395 | if not r: raise util.Abort('no queue repository') | |
1114 | commands.commit(r.ui, r, *pats, **opts) |
|
1396 | commands.commit(r.ui, r, *pats, **opts) | |
1115 |
|
1397 | |||
1116 | def series(ui, repo, **opts): |
|
1398 | def series(ui, repo, **opts): | |
1117 | """print the entire series file""" |
|
1399 | """print the entire series file""" | |
1118 |
|
|
1400 | repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary']) | |
1119 | return 0 |
|
1401 | return 0 | |
1120 |
|
1402 | |||
1121 | def top(ui, repo, **opts): |
|
1403 | def top(ui, repo, **opts): | |
1122 | """print the name of the current patch""" |
|
1404 | """print the name of the current patch""" | |
1123 |
|
|
1405 | repo.mq.top(repo) | |
1124 | return 0 |
|
1406 | return 0 | |
1125 |
|
1407 | |||
1126 | def next(ui, repo, **opts): |
|
1408 | def next(ui, repo, **opts): | |
1127 | """print the name of the next patch""" |
|
1409 | """print the name of the next patch""" | |
1128 |
|
|
1410 | repo.mq.next(repo) | |
1129 | return 0 |
|
1411 | return 0 | |
1130 |
|
1412 | |||
1131 | def prev(ui, repo, **opts): |
|
1413 | def prev(ui, repo, **opts): | |
1132 | """print the name of the previous patch""" |
|
1414 | """print the name of the previous patch""" | |
1133 |
|
|
1415 | repo.mq.prev(repo) | |
1134 | return 0 |
|
1416 | return 0 | |
1135 |
|
1417 | |||
1136 | def new(ui, repo, patch, **opts): |
|
1418 | def new(ui, repo, patch, **opts): | |
1137 |
"""create a new patch |
|
1419 | """create a new patch | |
1138 | q = repomap[repo] |
|
1420 | ||
1139 | q.new(repo, patch, msg=opts['message'], force=opts['force']) |
|
1421 | qnew creates a new patch on top of the currently-applied patch | |
|
1422 | (if any). It will refuse to run if there are any outstanding | |||
|
1423 | changes unless -f is specified, in which case the patch will | |||
|
1424 | be initialised with them. | |||
|
1425 | ||||
|
1426 | -e, -m or -l set the patch header as well as the commit message. | |||
|
1427 | If none is specified, the patch header is empty and the | |||
|
1428 | commit message is 'New patch: PATCH'""" | |||
|
1429 | q = repo.mq | |||
|
1430 | message = commands.logmessage(opts) | |||
|
1431 | if opts['edit']: | |||
|
1432 | message = ui.edit(message, ui.username()) | |||
|
1433 | q.new(repo, patch, msg=message, force=opts['force']) | |||
|
1434 | q.save_dirty() | |||
|
1435 | return 0 | |||
|
1436 | ||||
|
1437 | def refresh(ui, repo, *pats, **opts): | |||
|
1438 | """update the current patch | |||
|
1439 | ||||
|
1440 | If any file patterns are provided, the refreshed patch will contain only | |||
|
1441 | the modifications that match those patterns; the remaining modifications | |||
|
1442 | will remain in the working directory. | |||
|
1443 | """ | |||
|
1444 | q = repo.mq | |||
|
1445 | message = commands.logmessage(opts) | |||
|
1446 | if opts['edit']: | |||
|
1447 | if message: | |||
|
1448 | raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) | |||
|
1449 | patch = q.applied[-1].name | |||
|
1450 | (message, comment, user, date, hasdiff) = q.readheaders(patch) | |||
|
1451 | message = ui.edit('\n'.join(message), user or ui.username()) | |||
|
1452 | q.refresh(repo, pats, msg=message, **opts) | |||
1140 | q.save_dirty() |
|
1453 | q.save_dirty() | |
1141 | return 0 |
|
1454 | return 0 | |
1142 |
|
1455 | |||
1143 |
def |
|
1456 | def diff(ui, repo, *pats, **opts): | |
1144 |
""" |
|
1457 | """diff of the current patch""" | |
1145 | q = repomap[repo] |
|
1458 | repo.mq.diff(repo, pats, opts) | |
1146 | q.refresh(repo, short=opts['short']) |
|
|||
1147 | q.save_dirty() |
|
|||
1148 | return 0 |
|
1459 | return 0 | |
1149 |
|
1460 | |||
1150 |
def |
|
1461 | def fold(ui, repo, *files, **opts): | |
1151 |
""" |
|
1462 | """fold the named patches into the current patch | |
1152 | # deep in the dirstate code, the walkhelper method wants a list, not a tuple |
|
1463 | ||
1153 | repomap[repo].diff(repo, list(files)) |
|
1464 | Patches must not yet be applied. Each patch will be successively | |
1154 | return 0 |
|
1465 | applied to the current patch in the order given. If all the | |
|
1466 | patches apply successfully, the current patch will be refreshed | |||
|
1467 | with the new cumulative patch, and the folded patches will | |||
|
1468 | be deleted. With -k/--keep, the folded patch files will not | |||
|
1469 | be removed afterwards. | |||
|
1470 | ||||
|
1471 | The header for each folded patch will be concatenated with | |||
|
1472 | the current patch header, separated by a line of '* * *'.""" | |||
|
1473 | ||||
|
1474 | q = repo.mq | |||
|
1475 | ||||
|
1476 | if not files: | |||
|
1477 | raise util.Abort(_('qfold requires at least one patch name')) | |||
|
1478 | if not q.check_toppatch(repo): | |||
|
1479 | raise util.Abort(_('No patches applied\n')) | |||
|
1480 | ||||
|
1481 | message = commands.logmessage(opts) | |||
|
1482 | if opts['edit']: | |||
|
1483 | if message: | |||
|
1484 | raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) | |||
|
1485 | ||||
|
1486 | parent = q.lookup('qtip') | |||
|
1487 | patches = [] | |||
|
1488 | messages = [] | |||
|
1489 | for f in files: | |||
|
1490 | p = q.lookup(f) | |||
|
1491 | if p in patches or p == parent: | |||
|
1492 | ui.warn(_('Skipping already folded patch %s') % p) | |||
|
1493 | if q.isapplied(p): | |||
|
1494 | raise util.Abort(_('qfold cannot fold already applied patch %s') % p) | |||
|
1495 | patches.append(p) | |||
|
1496 | ||||
|
1497 | for p in patches: | |||
|
1498 | if not message: | |||
|
1499 | messages.append(q.readheaders(p)[0]) | |||
|
1500 | pf = q.join(p) | |||
|
1501 | (patchsuccess, files, fuzz) = q.patch(repo, pf) | |||
|
1502 | if not patchsuccess: | |||
|
1503 | raise util.Abort(_('Error folding patch %s') % p) | |||
|
1504 | patch.updatedir(ui, repo, files) | |||
|
1505 | ||||
|
1506 | if not message: | |||
|
1507 | message, comments, user = q.readheaders(parent)[0:3] | |||
|
1508 | for msg in messages: | |||
|
1509 | message.append('* * *') | |||
|
1510 | message.extend(msg) | |||
|
1511 | message = '\n'.join(message) | |||
|
1512 | ||||
|
1513 | if opts['edit']: | |||
|
1514 | message = ui.edit(message, user or ui.username()) | |||
|
1515 | ||||
|
1516 | q.refresh(repo, msg=message) | |||
|
1517 | q.delete(repo, patches, keep=opts['keep']) | |||
|
1518 | q.save_dirty() | |||
|
1519 | ||||
|
1520 | def guard(ui, repo, *args, **opts): | |||
|
1521 | '''set or print guards for a patch | |||
|
1522 | ||||
|
1523 | Guards control whether a patch can be pushed. A patch with no | |||
|
1524 | guards is always pushed. A patch with a positive guard ("+foo") is | |||
|
1525 | pushed only if the qselect command has activated it. A patch with | |||
|
1526 | a negative guard ("-foo") is never pushed if the qselect command | |||
|
1527 | has activated it. | |||
|
1528 | ||||
|
1529 | With no arguments, print the currently active guards. | |||
|
1530 | With arguments, set guards for the named patch. | |||
|
1531 | ||||
|
1532 | To set a negative guard "-foo" on topmost patch ("--" is needed so | |||
|
1533 | hg will not interpret "-foo" as an option): | |||
|
1534 | hg qguard -- -foo | |||
|
1535 | ||||
|
1536 | To set guards on another patch: | |||
|
1537 | hg qguard other.patch +2.6.17 -stable | |||
|
1538 | ''' | |||
|
1539 | def status(idx): | |||
|
1540 | guards = q.series_guards[idx] or ['unguarded'] | |||
|
1541 | ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards))) | |||
|
1542 | q = repo.mq | |||
|
1543 | patch = None | |||
|
1544 | args = list(args) | |||
|
1545 | if opts['list']: | |||
|
1546 | if args or opts['none']: | |||
|
1547 | raise util.Abort(_('cannot mix -l/--list with options or arguments')) | |||
|
1548 | for i in xrange(len(q.series)): | |||
|
1549 | status(i) | |||
|
1550 | return | |||
|
1551 | if not args or args[0][0:1] in '-+': | |||
|
1552 | if not q.applied: | |||
|
1553 | raise util.Abort(_('no patches applied')) | |||
|
1554 | patch = q.applied[-1].name | |||
|
1555 | if patch is None and args[0][0:1] not in '-+': | |||
|
1556 | patch = args.pop(0) | |||
|
1557 | if patch is None: | |||
|
1558 | raise util.Abort(_('no patch to work with')) | |||
|
1559 | if args or opts['none']: | |||
|
1560 | q.set_guards(q.find_series(patch), args) | |||
|
1561 | q.save_dirty() | |||
|
1562 | else: | |||
|
1563 | status(q.series.index(q.lookup(patch))) | |||
|
1564 | ||||
|
1565 | def header(ui, repo, patch=None): | |||
|
1566 | """Print the header of the topmost or specified patch""" | |||
|
1567 | q = repo.mq | |||
|
1568 | ||||
|
1569 | if patch: | |||
|
1570 | patch = q.lookup(patch) | |||
|
1571 | else: | |||
|
1572 | if not q.applied: | |||
|
1573 | ui.write('No patches applied\n') | |||
|
1574 | return | |||
|
1575 | patch = q.lookup('qtip') | |||
|
1576 | message = repo.mq.readheaders(patch)[0] | |||
|
1577 | ||||
|
1578 | ui.write('\n'.join(message) + '\n') | |||
1155 |
|
1579 | |||
1156 | def lastsavename(path): |
|
1580 | def lastsavename(path): | |
1157 | (dir, base) = os.path.split(path) |
|
1581 | (directory, base) = os.path.split(path) | |
1158 | names = os.listdir(dir) |
|
1582 | names = os.listdir(directory) | |
1159 | namere = re.compile("%s.([0-9]+)" % base) |
|
1583 | namere = re.compile("%s.([0-9]+)" % base) | |
1160 | max = None |
|
1584 | maxindex = None | |
1161 | maxname = None |
|
1585 | maxname = None | |
1162 | for f in names: |
|
1586 | for f in names: | |
1163 | m = namere.match(f) |
|
1587 | m = namere.match(f) | |
1164 | if m: |
|
1588 | if m: | |
1165 | index = int(m.group(1)) |
|
1589 | index = int(m.group(1)) | |
1166 | if max == None or index > max: |
|
1590 | if maxindex == None or index > maxindex: | |
1167 | max = index |
|
1591 | maxindex = index | |
1168 | maxname = f |
|
1592 | maxname = f | |
1169 | if maxname: |
|
1593 | if maxname: | |
1170 | return (os.path.join(dir, maxname), max) |
|
1594 | return (os.path.join(directory, maxname), maxindex) | |
1171 | return (None, None) |
|
1595 | return (None, None) | |
1172 |
|
1596 | |||
1173 | def savename(path): |
|
1597 | def savename(path): | |
@@ -1179,7 +1603,7 b' def savename(path):' | |||||
1179 |
|
1603 | |||
1180 | def push(ui, repo, patch=None, **opts): |
|
1604 | def push(ui, repo, patch=None, **opts): | |
1181 | """push the next patch onto the stack""" |
|
1605 | """push the next patch onto the stack""" | |
1182 |
q = |
|
1606 | q = repo.mq | |
1183 | mergeq = None |
|
1607 | mergeq = None | |
1184 |
|
1608 | |||
1185 | if opts['all']: |
|
1609 | if opts['all']: | |
@@ -1207,17 +1631,65 b' def pop(ui, repo, patch=None, **opts):' | |||||
1207 | ui.warn('using patch queue: %s\n' % q.path) |
|
1631 | ui.warn('using patch queue: %s\n' % q.path) | |
1208 | localupdate = False |
|
1632 | localupdate = False | |
1209 | else: |
|
1633 | else: | |
1210 |
q = |
|
1634 | q = repo.mq | |
1211 | if opts['all'] and len(q.applied) > 0: |
|
1635 | q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all']) | |
1212 | patch = q.applied[0].split(':')[1] |
|
|||
1213 | q.pop(repo, patch, force=opts['force'], update=localupdate) |
|
|||
1214 | q.save_dirty() |
|
1636 | q.save_dirty() | |
1215 | return 0 |
|
1637 | return 0 | |
1216 |
|
1638 | |||
|
1639 | def rename(ui, repo, patch, name=None, **opts): | |||
|
1640 | """rename a patch | |||
|
1641 | ||||
|
1642 | With one argument, renames the current patch to PATCH1. | |||
|
1643 | With two arguments, renames PATCH1 to PATCH2.""" | |||
|
1644 | ||||
|
1645 | q = repo.mq | |||
|
1646 | ||||
|
1647 | if not name: | |||
|
1648 | name = patch | |||
|
1649 | patch = None | |||
|
1650 | ||||
|
1651 | if name in q.series: | |||
|
1652 | raise util.Abort(_('A patch named %s already exists in the series file') % name) | |||
|
1653 | ||||
|
1654 | absdest = q.join(name) | |||
|
1655 | if os.path.exists(absdest): | |||
|
1656 | raise util.Abort(_('%s already exists') % absdest) | |||
|
1657 | ||||
|
1658 | if patch: | |||
|
1659 | patch = q.lookup(patch) | |||
|
1660 | else: | |||
|
1661 | if not q.applied: | |||
|
1662 | ui.write(_('No patches applied\n')) | |||
|
1663 | return | |||
|
1664 | patch = q.lookup('qtip') | |||
|
1665 | ||||
|
1666 | if ui.verbose: | |||
|
1667 | ui.write('Renaming %s to %s\n' % (patch, name)) | |||
|
1668 | i = q.find_series(patch) | |||
|
1669 | q.full_series[i] = name | |||
|
1670 | q.parse_series() | |||
|
1671 | q.series_dirty = 1 | |||
|
1672 | ||||
|
1673 | info = q.isapplied(patch) | |||
|
1674 | if info: | |||
|
1675 | q.applied[info[0]] = statusentry(info[1], name) | |||
|
1676 | q.applied_dirty = 1 | |||
|
1677 | ||||
|
1678 | util.rename(q.join(patch), absdest) | |||
|
1679 | r = q.qrepo() | |||
|
1680 | if r: | |||
|
1681 | wlock = r.wlock() | |||
|
1682 | if r.dirstate.state(name) == 'r': | |||
|
1683 | r.undelete([name], wlock) | |||
|
1684 | r.copy(patch, name, wlock) | |||
|
1685 | r.remove([patch], False, wlock) | |||
|
1686 | ||||
|
1687 | q.save_dirty() | |||
|
1688 | ||||
1217 | def restore(ui, repo, rev, **opts): |
|
1689 | def restore(ui, repo, rev, **opts): | |
1218 | """restore the queue state saved by a rev""" |
|
1690 | """restore the queue state saved by a rev""" | |
1219 | rev = repo.lookup(rev) |
|
1691 | rev = repo.lookup(rev) | |
1220 |
q = |
|
1692 | q = repo.mq | |
1221 | q.restore(repo, rev, delete=opts['delete'], |
|
1693 | q.restore(repo, rev, delete=opts['delete'], | |
1222 | qupdate=opts['update']) |
|
1694 | qupdate=opts['update']) | |
1223 | q.save_dirty() |
|
1695 | q.save_dirty() | |
@@ -1225,8 +1697,9 b' def restore(ui, repo, rev, **opts):' | |||||
1225 |
|
1697 | |||
1226 | def save(ui, repo, **opts): |
|
1698 | def save(ui, repo, **opts): | |
1227 | """save current queue state""" |
|
1699 | """save current queue state""" | |
1228 |
q = |
|
1700 | q = repo.mq | |
1229 | ret = q.save(repo, msg=opts['message']) |
|
1701 | message = commands.logmessage(opts) | |
|
1702 | ret = q.save(repo, msg=message) | |||
1230 | if ret: |
|
1703 | if ret: | |
1231 | return ret |
|
1704 | return ret | |
1232 | q.save_dirty() |
|
1705 | q.save_dirty() | |
@@ -1236,20 +1709,18 b' def save(ui, repo, **opts):' | |||||
1236 | newpath = os.path.join(q.basepath, opts['name']) |
|
1709 | newpath = os.path.join(q.basepath, opts['name']) | |
1237 | if os.path.exists(newpath): |
|
1710 | if os.path.exists(newpath): | |
1238 | if not os.path.isdir(newpath): |
|
1711 | if not os.path.isdir(newpath): | |
1239 |
ui. |
|
1712 | raise util.Abort(_('destination %s exists and is not ' | |
1240 | newpath) |
|
1713 | 'a directory') % newpath) | |
1241 | sys.exit(1) |
|
|||
1242 | if not opts['force']: |
|
1714 | if not opts['force']: | |
1243 |
ui. |
|
1715 | raise util.Abort(_('destination %s exists, ' | |
1244 | newpath) |
|
1716 | 'use -f to force') % newpath) | |
1245 | sys.exit(1) |
|
|||
1246 | else: |
|
1717 | else: | |
1247 | newpath = savename(path) |
|
1718 | newpath = savename(path) | |
1248 | ui.warn("copy %s to %s\n" % (path, newpath)) |
|
1719 | ui.warn("copy %s to %s\n" % (path, newpath)) | |
1249 | util.copyfiles(path, newpath) |
|
1720 | util.copyfiles(path, newpath) | |
1250 | if opts['empty']: |
|
1721 | if opts['empty']: | |
1251 | try: |
|
1722 | try: | |
1252 |
os.unlink( |
|
1723 | os.unlink(q.join(q.status_path)) | |
1253 | except: |
|
1724 | except: | |
1254 | pass |
|
1725 | pass | |
1255 | return 0 |
|
1726 | return 0 | |
@@ -1262,25 +1733,196 b' def strip(ui, repo, rev, **opts):' | |||||
1262 | backup = 'strip' |
|
1733 | backup = 'strip' | |
1263 | elif opts['nobackup']: |
|
1734 | elif opts['nobackup']: | |
1264 | backup = 'none' |
|
1735 | backup = 'none' | |
1265 |
|
|
1736 | repo.mq.strip(repo, rev, backup=backup) | |
1266 | return 0 |
|
1737 | return 0 | |
1267 |
|
1738 | |||
1268 | def version(ui, q=None): |
|
1739 | def select(ui, repo, *args, **opts): | |
1269 | """print the version number""" |
|
1740 | '''set or print guarded patches to push | |
1270 | ui.write("mq version %s\n" % versionstr) |
|
1741 | ||
1271 | return 0 |
|
1742 | Use the qguard command to set or print guards on patch, then use | |
|
1743 | qselect to tell mq which guards to use. A patch will be pushed if it | |||
|
1744 | has no guards or any positive guards match the currently selected guard, | |||
|
1745 | but will not be pushed if any negative guards match the current guard. | |||
|
1746 | For example: | |||
|
1747 | ||||
|
1748 | qguard foo.patch -stable (negative guard) | |||
|
1749 | qguard bar.patch +stable (positive guard) | |||
|
1750 | qselect stable | |||
|
1751 | ||||
|
1752 | This activates the "stable" guard. mq will skip foo.patch (because | |||
|
1753 | it has a negative match) but push bar.patch (because it | |||
|
1754 | has a positive match). | |||
|
1755 | ||||
|
1756 | With no arguments, prints the currently active guards. | |||
|
1757 | With one argument, sets the active guard. | |||
|
1758 | ||||
|
1759 | Use -n/--none to deactivate guards (no other arguments needed). | |||
|
1760 | When no guards are active, patches with positive guards are skipped | |||
|
1761 | and patches with negative guards are pushed. | |||
|
1762 | ||||
|
1763 | qselect can change the guards on applied patches. It does not pop | |||
|
1764 | guarded patches by default. Use --pop to pop back to the last applied | |||
|
1765 | patch that is not guarded. Use --reapply (which implies --pop) to push | |||
|
1766 | back to the current patch afterwards, but skip guarded patches. | |||
|
1767 | ||||
|
1768 | Use -s/--series to print a list of all guards in the series file (no | |||
|
1769 | other arguments needed). Use -v for more information.''' | |||
|
1770 | ||||
|
1771 | q = repo.mq | |||
|
1772 | guards = q.active() | |||
|
1773 | if args or opts['none']: | |||
|
1774 | old_unapplied = q.unapplied(repo) | |||
|
1775 | old_guarded = [i for i in xrange(len(q.applied)) if | |||
|
1776 | not q.pushable(i)[0]] | |||
|
1777 | q.set_active(args) | |||
|
1778 | q.save_dirty() | |||
|
1779 | if not args: | |||
|
1780 | ui.status(_('guards deactivated\n')) | |||
|
1781 | if not opts['pop'] and not opts['reapply']: | |||
|
1782 | unapplied = q.unapplied(repo) | |||
|
1783 | guarded = [i for i in xrange(len(q.applied)) | |||
|
1784 | if not q.pushable(i)[0]] | |||
|
1785 | if len(unapplied) != len(old_unapplied): | |||
|
1786 | ui.status(_('number of unguarded, unapplied patches has ' | |||
|
1787 | 'changed from %d to %d\n') % | |||
|
1788 | (len(old_unapplied), len(unapplied))) | |||
|
1789 | if len(guarded) != len(old_guarded): | |||
|
1790 | ui.status(_('number of guarded, applied patches has changed ' | |||
|
1791 | 'from %d to %d\n') % | |||
|
1792 | (len(old_guarded), len(guarded))) | |||
|
1793 | elif opts['series']: | |||
|
1794 | guards = {} | |||
|
1795 | noguards = 0 | |||
|
1796 | for gs in q.series_guards: | |||
|
1797 | if not gs: | |||
|
1798 | noguards += 1 | |||
|
1799 | for g in gs: | |||
|
1800 | guards.setdefault(g, 0) | |||
|
1801 | guards[g] += 1 | |||
|
1802 | if ui.verbose: | |||
|
1803 | guards['NONE'] = noguards | |||
|
1804 | guards = guards.items() | |||
|
1805 | guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:])) | |||
|
1806 | if guards: | |||
|
1807 | ui.note(_('guards in series file:\n')) | |||
|
1808 | for guard, count in guards: | |||
|
1809 | ui.note('%2d ' % count) | |||
|
1810 | ui.write(guard, '\n') | |||
|
1811 | else: | |||
|
1812 | ui.note(_('no guards in series file\n')) | |||
|
1813 | else: | |||
|
1814 | if guards: | |||
|
1815 | ui.note(_('active guards:\n')) | |||
|
1816 | for g in guards: | |||
|
1817 | ui.write(g, '\n') | |||
|
1818 | else: | |||
|
1819 | ui.write(_('no active guards\n')) | |||
|
1820 | reapply = opts['reapply'] and q.applied and q.appliedname(-1) | |||
|
1821 | popped = False | |||
|
1822 | if opts['pop'] or opts['reapply']: | |||
|
1823 | for i in xrange(len(q.applied)): | |||
|
1824 | pushable, reason = q.pushable(i) | |||
|
1825 | if not pushable: | |||
|
1826 | ui.status(_('popping guarded patches\n')) | |||
|
1827 | popped = True | |||
|
1828 | if i == 0: | |||
|
1829 | q.pop(repo, all=True) | |||
|
1830 | else: | |||
|
1831 | q.pop(repo, i-1) | |||
|
1832 | break | |||
|
1833 | if popped: | |||
|
1834 | try: | |||
|
1835 | if reapply: | |||
|
1836 | ui.status(_('reapplying unguarded patches\n')) | |||
|
1837 | q.push(repo, reapply) | |||
|
1838 | finally: | |||
|
1839 | q.save_dirty() | |||
1272 |
|
1840 | |||
1273 | def reposetup(ui, repo): |
|
1841 | def reposetup(ui, repo): | |
1274 | repomap[repo] = queue(ui, repo.join("")) |
|
1842 | class mqrepo(repo.__class__): | |
|
1843 | def abort_if_wdir_patched(self, errmsg, force=False): | |||
|
1844 | if self.mq.applied and not force: | |||
|
1845 | parent = revlog.hex(self.dirstate.parents()[0]) | |||
|
1846 | if parent in [s.rev for s in self.mq.applied]: | |||
|
1847 | raise util.Abort(errmsg) | |||
|
1848 | ||||
|
1849 | def commit(self, *args, **opts): | |||
|
1850 | if len(args) >= 6: | |||
|
1851 | force = args[5] | |||
|
1852 | else: | |||
|
1853 | force = opts.get('force') | |||
|
1854 | self.abort_if_wdir_patched( | |||
|
1855 | _('cannot commit over an applied mq patch'), | |||
|
1856 | force) | |||
|
1857 | ||||
|
1858 | return super(mqrepo, self).commit(*args, **opts) | |||
|
1859 | ||||
|
1860 | def push(self, remote, force=False, revs=None): | |||
|
1861 | if self.mq.applied and not force: | |||
|
1862 | raise util.Abort(_('source has mq patches applied')) | |||
|
1863 | return super(mqrepo, self).push(remote, force, revs) | |||
|
1864 | ||||
|
1865 | def tags(self): | |||
|
1866 | if self.tagscache: | |||
|
1867 | return self.tagscache | |||
|
1868 | ||||
|
1869 | tagscache = super(mqrepo, self).tags() | |||
|
1870 | ||||
|
1871 | q = self.mq | |||
|
1872 | if not q.applied: | |||
|
1873 | return tagscache | |||
|
1874 | ||||
|
1875 | mqtags = [(patch.rev, patch.name) for patch in q.applied] | |||
|
1876 | mqtags.append((mqtags[-1][0], 'qtip')) | |||
|
1877 | mqtags.append((mqtags[0][0], 'qbase')) | |||
|
1878 | for patch in mqtags: | |||
|
1879 | if patch[1] in tagscache: | |||
|
1880 | self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) | |||
|
1881 | else: | |||
|
1882 | tagscache[patch[1]] = revlog.bin(patch[0]) | |||
|
1883 | ||||
|
1884 | return tagscache | |||
|
1885 | ||||
|
1886 | if repo.local(): | |||
|
1887 | repo.__class__ = mqrepo | |||
|
1888 | repo.mq = queue(ui, repo.join("")) | |||
1275 |
|
1889 | |||
1276 | cmdtable = { |
|
1890 | cmdtable = { | |
1277 | "qapplied": (applied, [], 'hg qapplied [PATCH]'), |
|
1891 | "qapplied": (applied, [], 'hg qapplied [PATCH]'), | |
|
1892 | "qclone": (clone, | |||
|
1893 | [('', 'pull', None, _('use pull protocol to copy metadata')), | |||
|
1894 | ('U', 'noupdate', None, _('do not update the new working directories')), | |||
|
1895 | ('', 'uncompressed', None, | |||
|
1896 | _('use uncompressed transfer (fast over LAN)')), | |||
|
1897 | ('e', 'ssh', '', _('specify ssh command to use')), | |||
|
1898 | ('p', 'patches', '', _('location of source patch repo')), | |||
|
1899 | ('', 'remotecmd', '', | |||
|
1900 | _('specify hg command to run on the remote side'))], | |||
|
1901 | 'hg qclone [OPTION]... SOURCE [DEST]'), | |||
1278 | "qcommit|qci": |
|
1902 | "qcommit|qci": | |
1279 | (commit, |
|
1903 | (commit, | |
1280 | commands.table["^commit|ci"][1], |
|
1904 | commands.table["^commit|ci"][1], | |
1281 | 'hg qcommit [OPTION]... [FILE]...'), |
|
1905 | 'hg qcommit [OPTION]... [FILE]...'), | |
1282 | "^qdiff": (diff, [], 'hg qdiff [FILE]...'), |
|
1906 | "^qdiff": (diff, | |
1283 | "qdelete": (delete, [], 'hg qdelete PATCH'), |
|
1907 | [('I', 'include', [], _('include names matching the given patterns')), | |
|
1908 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |||
|
1909 | 'hg qdiff [-I] [-X] [FILE]...'), | |||
|
1910 | "qdelete|qremove|qrm": | |||
|
1911 | (delete, | |||
|
1912 | [('k', 'keep', None, _('keep patch file'))], | |||
|
1913 | 'hg qdelete [-k] PATCH'), | |||
|
1914 | 'qfold': | |||
|
1915 | (fold, | |||
|
1916 | [('e', 'edit', None, _('edit patch header')), | |||
|
1917 | ('k', 'keep', None, _('keep folded patch files')), | |||
|
1918 | ('m', 'message', '', _('set patch header to <text>')), | |||
|
1919 | ('l', 'logfile', '', _('set patch header to contents of <file>'))], | |||
|
1920 | 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'), | |||
|
1921 | 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')), | |||
|
1922 | ('n', 'none', None, _('drop all guards'))], | |||
|
1923 | 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'), | |||
|
1924 | 'qheader': (header, [], | |||
|
1925 | _('hg qheader [PATCH]')), | |||
1284 | "^qimport": |
|
1926 | "^qimport": | |
1285 | (qimport, |
|
1927 | (qimport, | |
1286 | [('e', 'existing', None, 'import file in patch dir'), |
|
1928 | [('e', 'existing', None, 'import file in patch dir'), | |
@@ -1293,9 +1935,11 b' cmdtable = {' | |||||
1293 | 'hg qinit [-c]'), |
|
1935 | 'hg qinit [-c]'), | |
1294 | "qnew": |
|
1936 | "qnew": | |
1295 | (new, |
|
1937 | (new, | |
1296 |
[(' |
|
1938 | [('e', 'edit', None, _('edit commit message')), | |
1297 | ('f', 'force', None, 'force')], |
|
1939 | ('m', 'message', '', _('use <text> as commit message')), | |
1298 | 'hg qnew [-m TEXT] [-f] PATCH'), |
|
1940 | ('l', 'logfile', '', _('read the commit message from <file>')), | |
|
1941 | ('f', 'force', None, _('import uncommitted changes into patch'))], | |||
|
1942 | 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'), | |||
1299 | "qnext": (next, [], 'hg qnext'), |
|
1943 | "qnext": (next, [], 'hg qnext'), | |
1300 | "qprev": (prev, [], 'hg qprev'), |
|
1944 | "qprev": (prev, [], 'hg qprev'), | |
1301 | "^qpop": |
|
1945 | "^qpop": | |
@@ -1314,8 +1958,15 b' cmdtable = {' | |||||
1314 | 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'), |
|
1958 | 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'), | |
1315 | "^qrefresh": |
|
1959 | "^qrefresh": | |
1316 | (refresh, |
|
1960 | (refresh, | |
1317 |
[(' |
|
1961 | [('e', 'edit', None, _('edit commit message')), | |
1318 | 'hg qrefresh [-s]'), |
|
1962 | ('m', 'message', '', _('change commit message with <text>')), | |
|
1963 | ('l', 'logfile', '', _('change commit message with <file> content')), | |||
|
1964 | ('s', 'short', None, 'short refresh'), | |||
|
1965 | ('I', 'include', [], _('include names matching the given patterns')), | |||
|
1966 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |||
|
1967 | 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'), | |||
|
1968 | 'qrename|qmv': | |||
|
1969 | (rename, [], 'hg qrename PATCH1 [PATCH2]'), | |||
1319 | "qrestore": |
|
1970 | "qrestore": | |
1320 | (restore, |
|
1971 | (restore, | |
1321 | [('d', 'delete', None, 'delete save entry'), |
|
1972 | [('d', 'delete', None, 'delete save entry'), | |
@@ -1323,15 +1974,24 b' cmdtable = {' | |||||
1323 | 'hg qrestore [-d] [-u] REV'), |
|
1974 | 'hg qrestore [-d] [-u] REV'), | |
1324 | "qsave": |
|
1975 | "qsave": | |
1325 | (save, |
|
1976 | (save, | |
1326 | [('m', 'message', '', 'commit message'), |
|
1977 | [('m', 'message', '', _('use <text> as commit message')), | |
|
1978 | ('l', 'logfile', '', _('read the commit message from <file>')), | |||
1327 | ('c', 'copy', None, 'copy patch directory'), |
|
1979 | ('c', 'copy', None, 'copy patch directory'), | |
1328 | ('n', 'name', '', 'copy directory name'), |
|
1980 | ('n', 'name', '', 'copy directory name'), | |
1329 | ('e', 'empty', None, 'clear queue status file'), |
|
1981 | ('e', 'empty', None, 'clear queue status file'), | |
1330 | ('f', 'force', None, 'force copy')], |
|
1982 | ('f', 'force', None, 'force copy')], | |
1331 | 'hg qsave [-m TEXT] [-c] [-n NAME] [-e] [-f]'), |
|
1983 | 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'), | |
|
1984 | "qselect": (select, | |||
|
1985 | [('n', 'none', None, _('disable all guards')), | |||
|
1986 | ('s', 'series', None, _('list all guards in series file')), | |||
|
1987 | ('', 'pop', None, | |||
|
1988 | _('pop to before first guarded applied patch')), | |||
|
1989 | ('', 'reapply', None, _('pop, then reapply patches'))], | |||
|
1990 | 'hg qselect [OPTION...] [GUARD...]'), | |||
1332 | "qseries": |
|
1991 | "qseries": | |
1333 | (series, |
|
1992 | (series, | |
1334 |
[('m', 'missing', None, 'print patches not in series') |
|
1993 | [('m', 'missing', None, 'print patches not in series'), | |
|
1994 | ('s', 'summary', None, _('print first line of patch header'))], | |||
1335 | 'hg qseries [-m]'), |
|
1995 | 'hg qseries [-m]'), | |
1336 | "^strip": |
|
1996 | "^strip": | |
1337 | (strip, |
|
1997 | (strip, | |
@@ -1341,6 +2001,4 b' cmdtable = {' | |||||
1341 | 'hg strip [-f] [-b] [-n] REV'), |
|
2001 | 'hg strip [-f] [-b] [-n] REV'), | |
1342 | "qtop": (top, [], 'hg qtop'), |
|
2002 | "qtop": (top, [], 'hg qtop'), | |
1343 | "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'), |
|
2003 | "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'), | |
1344 | "qversion": (version, [], 'hg qversion') |
|
|||
1345 | } |
|
2004 | } | |
1346 |
|
@@ -67,8 +67,8 b'' | |||||
67 | from mercurial.demandload import * |
|
67 | from mercurial.demandload import * | |
68 | from mercurial.i18n import gettext as _ |
|
68 | from mercurial.i18n import gettext as _ | |
69 | from mercurial.node import * |
|
69 | from mercurial.node import * | |
70 |
demandload(globals(), ' |
|
70 | demandload(globals(), 'mercurial:commands,patch,templater,util,mail') | |
71 | demandload(globals(), 'fnmatch socket time') |
|
71 | demandload(globals(), 'email.Parser fnmatch socket time') | |
72 |
|
72 | |||
73 | # template for single changeset can include email headers. |
|
73 | # template for single changeset can include email headers. | |
74 | single_template = ''' |
|
74 | single_template = ''' | |
@@ -229,8 +229,8 b' class notifier(object):' | |||||
229 | else: |
|
229 | else: | |
230 | self.ui.status(_('notify: sending %d subscribers %d changes\n') % |
|
230 | self.ui.status(_('notify: sending %d subscribers %d changes\n') % | |
231 | (len(self.subs), count)) |
|
231 | (len(self.subs), count)) | |
232 | mail = self.ui.sendmail() |
|
232 | mail.sendmail(self.ui, templater.email(msg['From']), | |
233 | mail.sendmail(templater.email(msg['From']), self.subs, msgtext) |
|
233 | self.subs, msgtext) | |
234 |
|
234 | |||
235 | def diff(self, node, ref): |
|
235 | def diff(self, node, ref): | |
236 | maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) |
|
236 | maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) | |
@@ -238,7 +238,7 b' class notifier(object):' | |||||
238 | return |
|
238 | return | |
239 | fp = templater.stringio() |
|
239 | fp = templater.stringio() | |
240 | prev = self.repo.changelog.parents(node)[0] |
|
240 | prev = self.repo.changelog.parents(node)[0] | |
241 |
|
|
241 | patch.diff(self.repo, fp, prev, ref) | |
242 | difflines = fp.getvalue().splitlines(1) |
|
242 | difflines = fp.getvalue().splitlines(1) | |
243 | if maxdiff > 0 and len(difflines) > maxdiff: |
|
243 | if maxdiff > 0 and len(difflines) > maxdiff: | |
244 | self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % |
|
244 | self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % | |
@@ -255,7 +255,7 b' def hook(ui, repo, hooktype, node=None, ' | |||||
255 | changegroup. else send one email per changeset.''' |
|
255 | changegroup. else send one email per changeset.''' | |
256 | n = notifier(ui, repo, hooktype) |
|
256 | n = notifier(ui, repo, hooktype) | |
257 | if not n.subs: |
|
257 | if not n.subs: | |
258 |
ui.debug(_('notify: no subscribers to |
|
258 | ui.debug(_('notify: no subscribers to repo %s\n' % n.root)) | |
259 | return |
|
259 | return | |
260 | if n.skipsource(source): |
|
260 | if n.skipsource(source): | |
261 | ui.debug(_('notify: changes have source "%s" - skipping\n') % |
|
261 | ui.debug(_('notify: changes have source "%s" - skipping\n') % |
@@ -23,27 +23,52 b'' | |||||
23 | # the changeset summary, so you can be sure you are sending the right |
|
23 | # the changeset summary, so you can be sure you are sending the right | |
24 | # changes. |
|
24 | # changes. | |
25 | # |
|
25 | # | |
26 | # It is best to run this script with the "-n" (test only) flag before |
|
26 | # To enable this extension: | |
27 | # firing it up "for real", in which case it will use your pager to |
|
|||
28 | # display each of the messages that it would send. |
|
|||
29 | # |
|
27 | # | |
30 | # The "-m" (mbox) option will create an mbox file instead of sending |
|
28 | # [extensions] | |
31 | # the messages directly. This can be reviewed e.g. with "mutt -R -f mbox", |
|
29 | # hgext.patchbomb = | |
32 | # and finally sent with "formail -s sendmail -bm -t < mbox". |
|
|||
33 | # |
|
30 | # | |
34 | # To configure other defaults, add a section like this to your hgrc |
|
31 | # To configure other defaults, add a section like this to your hgrc | |
35 | # file: |
|
32 | # file: | |
36 | # |
|
33 | # | |
37 | # [email] |
|
34 | # [email] | |
38 | # from = My Name <my@email> |
|
35 | # from = My Name <my@email> | |
39 | # to = recipient1, recipient2, ... |
|
36 | # to = recipient1, recipient2, ... | |
40 | # cc = cc1, cc2, ... |
|
37 | # cc = cc1, cc2, ... | |
|
38 | # bcc = bcc1, bcc2, ... | |||
|
39 | # | |||
|
40 | # Then you can use the "hg email" command to mail a series of changesets | |||
|
41 | # as a patchbomb. | |||
|
42 | # | |||
|
43 | # To avoid sending patches prematurely, it is a good idea to first run | |||
|
44 | # the "email" command with the "-n" option (test only). You will be | |||
|
45 | # prompted for an email recipient address, a subject an an introductory | |||
|
46 | # message describing the patches of your patchbomb. Then when all is | |||
|
47 | # done, your pager will be fired up once for each patchbomb message, so | |||
|
48 | # you can verify everything is alright. | |||
|
49 | # | |||
|
50 | # The "-m" (mbox) option is also very useful. Instead of previewing | |||
|
51 | # each patchbomb message in a pager or sending the messages directly, | |||
|
52 | # it will create a UNIX mailbox file with the patch emails. This | |||
|
53 | # mailbox file can be previewed with any mail user agent which supports | |||
|
54 | # UNIX mbox files, i.e. with mutt: | |||
|
55 | # | |||
|
56 | # % mutt -R -f mbox | |||
|
57 | # | |||
|
58 | # When you are previewing the patchbomb messages, you can use `formail' | |||
|
59 | # (a utility that is commonly installed as part of the procmail package), | |||
|
60 | # to send each message out: | |||
|
61 | # | |||
|
62 | # % formail -s sendmail -bm -t < mbox | |||
|
63 | # | |||
|
64 | # That should be all. Now your patchbomb is on its way out. | |||
41 |
|
65 | |||
42 | from mercurial.demandload import * |
|
66 | from mercurial.demandload import * | |
43 | demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils |
|
67 | demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils | |
44 | mercurial:commands,hg,ui |
|
68 | mercurial:commands,hg,mail,ui | |
45 | os errno popen2 socket sys tempfile time''') |
|
69 | os errno popen2 socket sys tempfile time''') | |
46 | from mercurial.i18n import gettext as _ |
|
70 | from mercurial.i18n import gettext as _ | |
|
71 | from mercurial.node import * | |||
47 |
|
72 | |||
48 | try: |
|
73 | try: | |
49 | # readline gives raw_input editing capabilities, but is not |
|
74 | # readline gives raw_input editing capabilities, but is not | |
@@ -129,8 +154,26 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
129 | while patch and not patch[0].strip(): patch.pop(0) |
|
154 | while patch and not patch[0].strip(): patch.pop(0) | |
130 | if opts['diffstat']: |
|
155 | if opts['diffstat']: | |
131 | body += cdiffstat('\n'.join(desc), patch) + '\n\n' |
|
156 | body += cdiffstat('\n'.join(desc), patch) + '\n\n' | |
132 | body += '\n'.join(patch) |
|
157 | if opts['attach']: | |
133 |
msg = email.MIME |
|
158 | msg = email.MIMEMultipart.MIMEMultipart() | |
|
159 | if body: msg.attach(email.MIMEText.MIMEText(body, 'plain')) | |||
|
160 | p = email.MIMEText.MIMEText('\n'.join(patch), 'x-patch') | |||
|
161 | binnode = bin(node) | |||
|
162 | # if node is mq patch, it will have patch file name as tag | |||
|
163 | patchname = [t for t in repo.nodetags(binnode) | |||
|
164 | if t.endswith('.patch') or t.endswith('.diff')] | |||
|
165 | if patchname: | |||
|
166 | patchname = patchname[0] | |||
|
167 | elif total > 1: | |||
|
168 | patchname = commands.make_filename(repo, '%b-%n.patch', | |||
|
169 | binnode, idx, total) | |||
|
170 | else: | |||
|
171 | patchname = commands.make_filename(repo, '%b.patch', binnode) | |||
|
172 | p['Content-Disposition'] = 'inline; filename=' + patchname | |||
|
173 | msg.attach(p) | |||
|
174 | else: | |||
|
175 | body += '\n'.join(patch) | |||
|
176 | msg = email.MIMEText.MIMEText(body) | |||
134 | if total == 1: |
|
177 | if total == 1: | |
135 | subj = '[PATCH] ' + desc[0].strip() |
|
178 | subj = '[PATCH] ' + desc[0].strip() | |
136 | else: |
|
179 | else: | |
@@ -185,11 +228,14 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
185 | to = getaddrs('to', 'To') |
|
228 | to = getaddrs('to', 'To') | |
186 | cc = getaddrs('cc', 'Cc', '') |
|
229 | cc = getaddrs('cc', 'Cc', '') | |
187 |
|
230 | |||
|
231 | bcc = opts['bcc'] or (ui.config('email', 'bcc') or | |||
|
232 | ui.config('patchbomb', 'bcc') or '').split(',') | |||
|
233 | bcc = [a.strip() for a in bcc if a.strip()] | |||
|
234 | ||||
188 | if len(patches) > 1: |
|
235 | if len(patches) > 1: | |
189 | ui.write(_('\nWrite the introductory message for the patch series.\n\n')) |
|
236 | ui.write(_('\nWrite the introductory message for the patch series.\n\n')) | |
190 |
|
237 | |||
191 | msg = email.MIMEMultipart.MIMEMultipart() |
|
238 | subj = '[PATCH 0 of %d] %s' % ( | |
192 | msg['Subject'] = '[PATCH 0 of %d] %s' % ( |
|
|||
193 | len(patches), |
|
239 | len(patches), | |
194 | opts['subject'] or |
|
240 | opts['subject'] or | |
195 | prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches))) |
|
241 | prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches))) | |
@@ -204,18 +250,21 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
204 | if l == '.': break |
|
250 | if l == '.': break | |
205 | body.append(l) |
|
251 | body.append(l) | |
206 |
|
252 | |||
207 | msg.attach(email.MIMEText.MIMEText('\n'.join(body) + '\n')) |
|
|||
208 |
|
||||
209 | if opts['diffstat']: |
|
253 | if opts['diffstat']: | |
210 | d = cdiffstat(_('Final summary:\n'), jumbo) |
|
254 | d = cdiffstat(_('Final summary:\n'), jumbo) | |
211 | if d: msg.attach(email.MIMEText.MIMEText(d)) |
|
255 | if d: body.append('\n' + d) | |
|
256 | ||||
|
257 | body = '\n'.join(body) + '\n' | |||
|
258 | ||||
|
259 | msg = email.MIMEText.MIMEText(body) | |||
|
260 | msg['Subject'] = subj | |||
212 |
|
261 | |||
213 | msgs.insert(0, msg) |
|
262 | msgs.insert(0, msg) | |
214 |
|
263 | |||
215 | ui.write('\n') |
|
264 | ui.write('\n') | |
216 |
|
265 | |||
217 | if not opts['test'] and not opts['mbox']: |
|
266 | if not opts['test'] and not opts['mbox']: | |
218 |
mail = ui |
|
267 | mailer = mail.connect(ui) | |
219 | parent = None |
|
268 | parent = None | |
220 |
|
269 | |||
221 | # Calculate UTC offset |
|
270 | # Calculate UTC offset | |
@@ -240,7 +289,8 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
240 | start_time += 1 |
|
289 | start_time += 1 | |
241 | m['From'] = sender |
|
290 | m['From'] = sender | |
242 | m['To'] = ', '.join(to) |
|
291 | m['To'] = ', '.join(to) | |
243 | if cc: m['Cc'] = ', '.join(cc) |
|
292 | if cc: m['Cc'] = ', '.join(cc) | |
|
293 | if bcc: m['Bcc'] = ', '.join(bcc) | |||
244 | if opts['test']: |
|
294 | if opts['test']: | |
245 | ui.status('Displaying ', m['Subject'], ' ...\n') |
|
295 | ui.status('Displaying ', m['Subject'], ' ...\n') | |
246 | fp = os.popen(os.getenv('PAGER', 'more'), 'w') |
|
296 | fp = os.popen(os.getenv('PAGER', 'more'), 'w') | |
@@ -261,12 +311,16 b' def patchbomb(ui, repo, *revs, **opts):' | |||||
261 | fp.close() |
|
311 | fp.close() | |
262 | else: |
|
312 | else: | |
263 | ui.status('Sending ', m['Subject'], ' ...\n') |
|
313 | ui.status('Sending ', m['Subject'], ' ...\n') | |
264 | mail.sendmail(sender, to + cc, m.as_string(0)) |
|
314 | # Exim does not remove the Bcc field | |
|
315 | del m['Bcc'] | |||
|
316 | mailer.sendmail(sender, to + bcc + cc, m.as_string(0)) | |||
265 |
|
317 | |||
266 | cmdtable = { |
|
318 | cmdtable = { | |
267 | 'email': |
|
319 | 'email': | |
268 | (patchbomb, |
|
320 | (patchbomb, | |
269 | [('c', 'cc', [], 'email addresses of copy recipients'), |
|
321 | [('a', 'attach', None, 'send patches as inline attachments'), | |
|
322 | ('', 'bcc', [], 'email addresses of blind copy recipients'), | |||
|
323 | ('c', 'cc', [], 'email addresses of copy recipients'), | |||
270 | ('d', 'diffstat', None, 'add diffstat output to messages'), |
|
324 | ('d', 'diffstat', None, 'add diffstat output to messages'), | |
271 | ('f', 'from', '', 'email address of sender'), |
|
325 | ('f', 'from', '', 'email address of sender'), | |
272 | ('', 'plain', None, 'omit hg patch header'), |
|
326 | ('', 'plain', None, 'omit hg patch header'), |
@@ -163,12 +163,12 b' def archive(repo, dest, node, kind, deco' | |||||
163 | change = repo.changelog.read(node) |
|
163 | change = repo.changelog.read(node) | |
164 | mn = change[0] |
|
164 | mn = change[0] | |
165 | archiver = archivers[kind](dest, prefix, mtime or change[2][0]) |
|
165 | archiver = archivers[kind](dest, prefix, mtime or change[2][0]) | |
166 |
m |
|
166 | m = repo.manifest.read(mn) | |
167 | mff = repo.manifest.readflags(mn) |
|
167 | items = m.items() | |
168 |
|
|
168 | items.sort() | |
169 | write('.hg_archival.txt', 0644, |
|
169 | write('.hg_archival.txt', 0644, | |
170 | 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node))) |
|
170 | 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node))) | |
171 |
for filename, filenode in |
|
171 | for filename, filenode in items: | |
172 |
write(filename, m |
|
172 | write(filename, m.execf(filename) and 0755 or 0644, | |
173 | repo.file(filename).read(filenode)) |
|
173 | repo.file(filename).read(filenode)) | |
174 | archiver.done() |
|
174 | archiver.done() |
@@ -1,7 +1,7 b'' | |||||
1 | /* |
|
1 | /* | |
2 | bdiff.c - efficient binary diff extension for Mercurial |
|
2 | bdiff.c - efficient binary diff extension for Mercurial | |
3 |
|
3 | |||
4 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 |
|
5 | |||
6 | This software may be used and distributed according to the terms of |
|
6 | This software may be used and distributed according to the terms of | |
7 | the GNU General Public License, incorporated herein by reference. |
|
7 | the GNU General Public License, incorporated herein by reference. |
@@ -159,6 +159,10 b' class bundlefilelog(bundlerevlog, filelo' | |||||
159 | class bundlerepository(localrepo.localrepository): |
|
159 | class bundlerepository(localrepo.localrepository): | |
160 | def __init__(self, ui, path, bundlename): |
|
160 | def __init__(self, ui, path, bundlename): | |
161 | localrepo.localrepository.__init__(self, ui, path) |
|
161 | localrepo.localrepository.__init__(self, ui, path) | |
|
162 | ||||
|
163 | self._url = 'bundle:' + bundlename | |||
|
164 | if path: self._url += '+' + path | |||
|
165 | ||||
162 | self.tempfile = None |
|
166 | self.tempfile = None | |
163 | self.bundlefile = open(bundlename, "rb") |
|
167 | self.bundlefile = open(bundlename, "rb") | |
164 | header = self.bundlefile.read(6) |
|
168 | header = self.bundlefile.read(6) | |
@@ -208,6 +212,9 b' class bundlerepository(localrepo.localre' | |||||
208 | for c in changegroup.chunkiter(self.bundlefile): |
|
212 | for c in changegroup.chunkiter(self.bundlefile): | |
209 | pass |
|
213 | pass | |
210 |
|
214 | |||
|
215 | def url(self): | |||
|
216 | return self._url | |||
|
217 | ||||
211 | def dev(self): |
|
218 | def dev(self): | |
212 | return -1 |
|
219 | return -1 | |
213 |
|
220 | |||
@@ -230,3 +237,18 b' class bundlerepository(localrepo.localre' | |||||
230 | self.bundlefile.close() |
|
237 | self.bundlefile.close() | |
231 | if self.tempfile is not None: |
|
238 | if self.tempfile is not None: | |
232 | os.unlink(self.tempfile) |
|
239 | os.unlink(self.tempfile) | |
|
240 | ||||
|
241 | def instance(ui, path, create): | |||
|
242 | if create: | |||
|
243 | raise util.Abort(_('cannot create new bundle repository')) | |||
|
244 | path = util.drop_scheme('file', path) | |||
|
245 | if path.startswith('bundle:'): | |||
|
246 | path = util.drop_scheme('bundle', path) | |||
|
247 | s = path.split("+", 1) | |||
|
248 | if len(s) == 1: | |||
|
249 | repopath, bundlename = "", s[0] | |||
|
250 | else: | |||
|
251 | repopath, bundlename = s | |||
|
252 | else: | |||
|
253 | repopath, bundlename = '', path | |||
|
254 | return bundlerepository(ui, repopath, bundlename) |
@@ -1,6 +1,6 b'' | |||||
1 | # changelog.py - changelog class for mercurial |
|
1 | # changelog.py - changelog class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. |
This diff has been collapsed as it changes many lines, (868 lines changed) Show them Hide them | |||||
@@ -1,6 +1,6 b'' | |||||
1 | # commands.py - command processing for mercurial |
|
1 | # commands.py - command processing for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -10,10 +10,10 b' from node import *' | |||||
10 | from i18n import gettext as _ |
|
10 | from i18n import gettext as _ | |
11 | demandload(globals(), "os re sys signal shutil imp urllib pdb") |
|
11 | demandload(globals(), "os re sys signal shutil imp urllib pdb") | |
12 | demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") |
|
12 | demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") | |
13 |
demandload(globals(), "fnmatch |
|
13 | demandload(globals(), "fnmatch difflib patch random signal tempfile time") | |
14 | demandload(globals(), "traceback errno socket version struct atexit sets bz2") |
|
14 | demandload(globals(), "traceback errno socket version struct atexit sets bz2") | |
15 |
demandload(globals(), "archival cStringIO changegroup |
|
15 | demandload(globals(), "archival cStringIO changegroup") | |
16 | demandload(globals(), "hgweb.server sshserver") |
|
16 | demandload(globals(), "cmdutil hgweb.server sshserver") | |
17 |
|
17 | |||
18 | class UnknownCommand(Exception): |
|
18 | class UnknownCommand(Exception): | |
19 | """Exception raised if command is not in the command table.""" |
|
19 | """Exception raised if command is not in the command table.""" | |
@@ -21,47 +21,34 b' class AmbiguousCommand(Exception):' | |||||
21 | """Exception raised if command shortcut matches more than one command.""" |
|
21 | """Exception raised if command shortcut matches more than one command.""" | |
22 |
|
22 | |||
23 | def bail_if_changed(repo): |
|
23 | def bail_if_changed(repo): | |
24 |
modified, added, removed, deleted |
|
24 | modified, added, removed, deleted = repo.status()[:4] | |
25 | if modified or added or removed or deleted: |
|
25 | if modified or added or removed or deleted: | |
26 | raise util.Abort(_("outstanding uncommitted changes")) |
|
26 | raise util.Abort(_("outstanding uncommitted changes")) | |
27 |
|
27 | |||
28 | def filterfiles(filters, files): |
|
|||
29 | l = [x for x in files if x in filters] |
|
|||
30 |
|
||||
31 | for t in filters: |
|
|||
32 | if t and t[-1] != "/": |
|
|||
33 | t += "/" |
|
|||
34 | l += [x for x in files if x.startswith(t)] |
|
|||
35 | return l |
|
|||
36 |
|
||||
37 | def relpath(repo, args): |
|
28 | def relpath(repo, args): | |
38 | cwd = repo.getcwd() |
|
29 | cwd = repo.getcwd() | |
39 | if cwd: |
|
30 | if cwd: | |
40 | return [util.normpath(os.path.join(cwd, x)) for x in args] |
|
31 | return [util.normpath(os.path.join(cwd, x)) for x in args] | |
41 | return args |
|
32 | return args | |
42 |
|
33 | |||
43 | def matchpats(repo, pats=[], opts={}, head=''): |
|
34 | def logmessage(opts): | |
44 | cwd = repo.getcwd() |
|
35 | """ get the log message according to -m and -l option """ | |
45 | if not pats and cwd: |
|
36 | message = opts['message'] | |
46 | opts['include'] = [os.path.join(cwd, i) for i in opts['include']] |
|
37 | logfile = opts['logfile'] | |
47 | opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] |
|
38 | ||
48 | cwd = '' |
|
39 | if message and logfile: | |
49 | return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), |
|
40 | raise util.Abort(_('options --message and --logfile are mutually ' | |
50 |
|
|
41 | 'exclusive')) | |
51 |
|
42 | if not message and logfile: | ||
52 | def makewalk(repo, pats, opts, node=None, head='', badmatch=None): |
|
43 | try: | |
53 | files, matchfn, anypats = matchpats(repo, pats, opts, head) |
|
44 | if logfile == '-': | |
54 | exact = dict(zip(files, files)) |
|
45 | message = sys.stdin.read() | |
55 | def walk(): |
|
46 | else: | |
56 | for src, fn in repo.walk(node=node, files=files, match=matchfn, |
|
47 | message = open(logfile).read() | |
57 | badmatch=badmatch): |
|
48 | except IOError, inst: | |
58 | yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact |
|
49 | raise util.Abort(_("can't read commit message '%s': %s") % | |
59 | return files, matchfn, walk() |
|
50 | (logfile, inst.strerror)) | |
60 |
|
51 | return message | ||
61 | def walk(repo, pats, opts, node=None, head='', badmatch=None): |
|
|||
62 | files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) |
|
|||
63 | for r in results: |
|
|||
64 | yield r |
|
|||
65 |
|
52 | |||
66 | def walkchangerevs(ui, repo, pats, opts): |
|
53 | def walkchangerevs(ui, repo, pats, opts): | |
67 | '''Iterate over files and the revs they changed in. |
|
54 | '''Iterate over files and the revs they changed in. | |
@@ -105,12 +92,23 b' def walkchangerevs(ui, repo, pats, opts)' | |||||
105 | windowsize *= 2 |
|
92 | windowsize *= 2 | |
106 |
|
93 | |||
107 |
|
94 | |||
108 | files, matchfn, anypats = matchpats(repo, pats, opts) |
|
95 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
96 | follow = opts.get('follow') or opts.get('follow_first') | |||
109 |
|
97 | |||
110 | if repo.changelog.count() == 0: |
|
98 | if repo.changelog.count() == 0: | |
111 | return [], False, matchfn |
|
99 | return [], False, matchfn | |
112 |
|
100 | |||
113 | revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0'])) |
|
101 | if follow: | |
|
102 | p = repo.dirstate.parents()[0] | |||
|
103 | if p == nullid: | |||
|
104 | ui.warn(_('No working directory revision; defaulting to tip\n')) | |||
|
105 | start = 'tip' | |||
|
106 | else: | |||
|
107 | start = repo.changelog.rev(p) | |||
|
108 | defrange = '%s:0' % start | |||
|
109 | else: | |||
|
110 | defrange = 'tip:0' | |||
|
111 | revs = map(int, revrange(ui, repo, opts['rev'] or [defrange])) | |||
114 | wanted = {} |
|
112 | wanted = {} | |
115 | slowpath = anypats |
|
113 | slowpath = anypats | |
116 | fncache = {} |
|
114 | fncache = {} | |
@@ -125,37 +123,54 b' def walkchangerevs(ui, repo, pats, opts)' | |||||
125 | if not slowpath and not files: |
|
123 | if not slowpath and not files: | |
126 | # No files, no patterns. Display all revs. |
|
124 | # No files, no patterns. Display all revs. | |
127 | wanted = dict(zip(revs, revs)) |
|
125 | wanted = dict(zip(revs, revs)) | |
|
126 | copies = [] | |||
128 | if not slowpath: |
|
127 | if not slowpath: | |
129 | # Only files, no patterns. Check the history of each file. |
|
128 | # Only files, no patterns. Check the history of each file. | |
130 | def filerevgen(filelog): |
|
129 | def filerevgen(filelog, node): | |
131 | cl_count = repo.changelog.count() |
|
130 | cl_count = repo.changelog.count() | |
132 | for i, window in increasing_windows(filelog.count()-1, -1): |
|
131 | if node is None: | |
|
132 | last = filelog.count() - 1 | |||
|
133 | else: | |||
|
134 | last = filelog.rev(node) | |||
|
135 | for i, window in increasing_windows(last, -1): | |||
133 | revs = [] |
|
136 | revs = [] | |
134 | for j in xrange(i - window, i + 1): |
|
137 | for j in xrange(i - window, i + 1): | |
135 |
|
|
138 | n = filelog.node(j) | |
|
139 | revs.append((filelog.linkrev(n), | |||
|
140 | follow and filelog.renamed(n))) | |||
136 | revs.reverse() |
|
141 | revs.reverse() | |
137 | for rev in revs: |
|
142 | for rev in revs: | |
138 | # only yield rev for which we have the changelog, it can |
|
143 | # only yield rev for which we have the changelog, it can | |
139 | # happen while doing "hg log" during a pull or commit |
|
144 | # happen while doing "hg log" during a pull or commit | |
140 | if rev < cl_count: |
|
145 | if rev[0] < cl_count: | |
141 | yield rev |
|
146 | yield rev | |
142 |
|
147 | def iterfiles(): | ||
|
148 | for filename in files: | |||
|
149 | yield filename, None | |||
|
150 | for filename_node in copies: | |||
|
151 | yield filename_node | |||
143 | minrev, maxrev = min(revs), max(revs) |
|
152 | minrev, maxrev = min(revs), max(revs) | |
144 | for file_ in files: |
|
153 | for file_, node in iterfiles(): | |
145 | filelog = repo.file(file_) |
|
154 | filelog = repo.file(file_) | |
146 | # A zero count may be a directory or deleted file, so |
|
155 | # A zero count may be a directory or deleted file, so | |
147 | # try to find matching entries on the slow path. |
|
156 | # try to find matching entries on the slow path. | |
148 | if filelog.count() == 0: |
|
157 | if filelog.count() == 0: | |
149 | slowpath = True |
|
158 | slowpath = True | |
150 | break |
|
159 | break | |
151 | for rev in filerevgen(filelog): |
|
160 | for rev, copied in filerevgen(filelog, node): | |
152 | if rev <= maxrev: |
|
161 | if rev <= maxrev: | |
153 | if rev < minrev: |
|
162 | if rev < minrev: | |
154 | break |
|
163 | break | |
155 | fncache.setdefault(rev, []) |
|
164 | fncache.setdefault(rev, []) | |
156 | fncache[rev].append(file_) |
|
165 | fncache[rev].append(file_) | |
157 | wanted[rev] = 1 |
|
166 | wanted[rev] = 1 | |
|
167 | if follow and copied: | |||
|
168 | copies.append(copied) | |||
158 | if slowpath: |
|
169 | if slowpath: | |
|
170 | if follow: | |||
|
171 | raise util.Abort(_('can only follow copies/renames for explicit ' | |||
|
172 | 'file names')) | |||
|
173 | ||||
159 | # The slow path checks files modified in every changeset. |
|
174 | # The slow path checks files modified in every changeset. | |
160 | def changerevgen(): |
|
175 | def changerevgen(): | |
161 | for i, window in increasing_windows(repo.changelog.count()-1, -1): |
|
176 | for i, window in increasing_windows(repo.changelog.count()-1, -1): | |
@@ -168,11 +183,66 b' def walkchangerevs(ui, repo, pats, opts)' | |||||
168 | fncache[rev] = matches |
|
183 | fncache[rev] = matches | |
169 | wanted[rev] = 1 |
|
184 | wanted[rev] = 1 | |
170 |
|
185 | |||
|
186 | class followfilter: | |||
|
187 | def __init__(self, onlyfirst=False): | |||
|
188 | self.startrev = -1 | |||
|
189 | self.roots = [] | |||
|
190 | self.onlyfirst = onlyfirst | |||
|
191 | ||||
|
192 | def match(self, rev): | |||
|
193 | def realparents(rev): | |||
|
194 | if self.onlyfirst: | |||
|
195 | return repo.changelog.parentrevs(rev)[0:1] | |||
|
196 | else: | |||
|
197 | return filter(lambda x: x != -1, repo.changelog.parentrevs(rev)) | |||
|
198 | ||||
|
199 | if self.startrev == -1: | |||
|
200 | self.startrev = rev | |||
|
201 | return True | |||
|
202 | ||||
|
203 | if rev > self.startrev: | |||
|
204 | # forward: all descendants | |||
|
205 | if not self.roots: | |||
|
206 | self.roots.append(self.startrev) | |||
|
207 | for parent in realparents(rev): | |||
|
208 | if parent in self.roots: | |||
|
209 | self.roots.append(rev) | |||
|
210 | return True | |||
|
211 | else: | |||
|
212 | # backwards: all parents | |||
|
213 | if not self.roots: | |||
|
214 | self.roots.extend(realparents(self.startrev)) | |||
|
215 | if rev in self.roots: | |||
|
216 | self.roots.remove(rev) | |||
|
217 | self.roots.extend(realparents(rev)) | |||
|
218 | return True | |||
|
219 | ||||
|
220 | return False | |||
|
221 | ||||
|
222 | # it might be worthwhile to do this in the iterator if the rev range | |||
|
223 | # is descending and the prune args are all within that range | |||
|
224 | for rev in opts.get('prune', ()): | |||
|
225 | rev = repo.changelog.rev(repo.lookup(rev)) | |||
|
226 | ff = followfilter() | |||
|
227 | stop = min(revs[0], revs[-1]) | |||
|
228 | for x in range(rev, stop-1, -1): | |||
|
229 | if ff.match(x) and wanted.has_key(x): | |||
|
230 | del wanted[x] | |||
|
231 | ||||
171 | def iterate(): |
|
232 | def iterate(): | |
|
233 | if follow and not files: | |||
|
234 | ff = followfilter(onlyfirst=opts.get('follow_first')) | |||
|
235 | def want(rev): | |||
|
236 | if ff.match(rev) and rev in wanted: | |||
|
237 | return True | |||
|
238 | return False | |||
|
239 | else: | |||
|
240 | def want(rev): | |||
|
241 | return rev in wanted | |||
|
242 | ||||
172 | for i, window in increasing_windows(0, len(revs)): |
|
243 | for i, window in increasing_windows(0, len(revs)): | |
173 | yield 'window', revs[0] < revs[-1], revs[-1] |
|
244 | yield 'window', revs[0] < revs[-1], revs[-1] | |
174 | nrevs = [rev for rev in revs[i:i+window] |
|
245 | nrevs = [rev for rev in revs[i:i+window] if want(rev)] | |
175 | if rev in wanted] |
|
|||
176 | srevs = list(nrevs) |
|
246 | srevs = list(nrevs) | |
177 | srevs.sort() |
|
247 | srevs.sort() | |
178 | for rev in srevs: |
|
248 | for rev in srevs: | |
@@ -252,62 +322,6 b' def revrange(ui, repo, revs):' | |||||
252 | seen[rev] = 1 |
|
322 | seen[rev] = 1 | |
253 | yield str(rev) |
|
323 | yield str(rev) | |
254 |
|
324 | |||
255 | def make_filename(repo, pat, node, |
|
|||
256 | total=None, seqno=None, revwidth=None, pathname=None): |
|
|||
257 | node_expander = { |
|
|||
258 | 'H': lambda: hex(node), |
|
|||
259 | 'R': lambda: str(repo.changelog.rev(node)), |
|
|||
260 | 'h': lambda: short(node), |
|
|||
261 | } |
|
|||
262 | expander = { |
|
|||
263 | '%': lambda: '%', |
|
|||
264 | 'b': lambda: os.path.basename(repo.root), |
|
|||
265 | } |
|
|||
266 |
|
||||
267 | try: |
|
|||
268 | if node: |
|
|||
269 | expander.update(node_expander) |
|
|||
270 | if node and revwidth is not None: |
|
|||
271 | expander['r'] = lambda: str(r.rev(node)).zfill(revwidth) |
|
|||
272 | if total is not None: |
|
|||
273 | expander['N'] = lambda: str(total) |
|
|||
274 | if seqno is not None: |
|
|||
275 | expander['n'] = lambda: str(seqno) |
|
|||
276 | if total is not None and seqno is not None: |
|
|||
277 | expander['n'] = lambda:str(seqno).zfill(len(str(total))) |
|
|||
278 | if pathname is not None: |
|
|||
279 | expander['s'] = lambda: os.path.basename(pathname) |
|
|||
280 | expander['d'] = lambda: os.path.dirname(pathname) or '.' |
|
|||
281 | expander['p'] = lambda: pathname |
|
|||
282 |
|
||||
283 | newname = [] |
|
|||
284 | patlen = len(pat) |
|
|||
285 | i = 0 |
|
|||
286 | while i < patlen: |
|
|||
287 | c = pat[i] |
|
|||
288 | if c == '%': |
|
|||
289 | i += 1 |
|
|||
290 | c = pat[i] |
|
|||
291 | c = expander[c]() |
|
|||
292 | newname.append(c) |
|
|||
293 | i += 1 |
|
|||
294 | return ''.join(newname) |
|
|||
295 | except KeyError, inst: |
|
|||
296 | raise util.Abort(_("invalid format spec '%%%s' in output file name"), |
|
|||
297 | inst.args[0]) |
|
|||
298 |
|
||||
299 | def make_file(repo, pat, node=None, |
|
|||
300 | total=None, seqno=None, revwidth=None, mode='wb', pathname=None): |
|
|||
301 | if not pat or pat == '-': |
|
|||
302 | return 'w' in mode and sys.stdout or sys.stdin |
|
|||
303 | if hasattr(pat, 'write') and 'w' in mode: |
|
|||
304 | return pat |
|
|||
305 | if hasattr(pat, 'read') and 'r' in mode: |
|
|||
306 | return pat |
|
|||
307 | return open(make_filename(repo, pat, node, total, seqno, revwidth, |
|
|||
308 | pathname), |
|
|||
309 | mode) |
|
|||
310 |
|
||||
311 | def write_bundle(cg, filename=None, compress=True): |
|
325 | def write_bundle(cg, filename=None, compress=True): | |
312 | """Write a bundle file and return its filename. |
|
326 | """Write a bundle file and return its filename. | |
313 |
|
327 | |||
@@ -360,83 +374,6 b' def write_bundle(cg, filename=None, comp' | |||||
360 | if cleanup is not None: |
|
374 | if cleanup is not None: | |
361 | os.unlink(cleanup) |
|
375 | os.unlink(cleanup) | |
362 |
|
376 | |||
363 | def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, |
|
|||
364 | changes=None, text=False, opts={}): |
|
|||
365 | if not node1: |
|
|||
366 | node1 = repo.dirstate.parents()[0] |
|
|||
367 | # reading the data for node1 early allows it to play nicely |
|
|||
368 | # with repo.changes and the revlog cache. |
|
|||
369 | change = repo.changelog.read(node1) |
|
|||
370 | mmap = repo.manifest.read(change[0]) |
|
|||
371 | date1 = util.datestr(change[2]) |
|
|||
372 |
|
||||
373 | if not changes: |
|
|||
374 | changes = repo.changes(node1, node2, files, match=match) |
|
|||
375 | modified, added, removed, deleted, unknown = changes |
|
|||
376 | if files: |
|
|||
377 | modified, added, removed = map(lambda x: filterfiles(files, x), |
|
|||
378 | (modified, added, removed)) |
|
|||
379 |
|
||||
380 | if not modified and not added and not removed: |
|
|||
381 | return |
|
|||
382 |
|
||||
383 | if node2: |
|
|||
384 | change = repo.changelog.read(node2) |
|
|||
385 | mmap2 = repo.manifest.read(change[0]) |
|
|||
386 | _date2 = util.datestr(change[2]) |
|
|||
387 | def date2(f): |
|
|||
388 | return _date2 |
|
|||
389 | def read(f): |
|
|||
390 | return repo.file(f).read(mmap2[f]) |
|
|||
391 | else: |
|
|||
392 | tz = util.makedate()[1] |
|
|||
393 | _date2 = util.datestr() |
|
|||
394 | def date2(f): |
|
|||
395 | try: |
|
|||
396 | return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) |
|
|||
397 | except OSError, err: |
|
|||
398 | if err.errno != errno.ENOENT: raise |
|
|||
399 | return _date2 |
|
|||
400 | def read(f): |
|
|||
401 | return repo.wread(f) |
|
|||
402 |
|
||||
403 | if ui.quiet: |
|
|||
404 | r = None |
|
|||
405 | else: |
|
|||
406 | hexfunc = ui.verbose and hex or short |
|
|||
407 | r = [hexfunc(node) for node in [node1, node2] if node] |
|
|||
408 |
|
||||
409 | diffopts = ui.diffopts() |
|
|||
410 | showfunc = opts.get('show_function') or diffopts['showfunc'] |
|
|||
411 | ignorews = opts.get('ignore_all_space') or diffopts['ignorews'] |
|
|||
412 | ignorewsamount = opts.get('ignore_space_change') or \ |
|
|||
413 | diffopts['ignorewsamount'] |
|
|||
414 | ignoreblanklines = opts.get('ignore_blank_lines') or \ |
|
|||
415 | diffopts['ignoreblanklines'] |
|
|||
416 | for f in modified: |
|
|||
417 | to = None |
|
|||
418 | if f in mmap: |
|
|||
419 | to = repo.file(f).read(mmap[f]) |
|
|||
420 | tn = read(f) |
|
|||
421 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, |
|
|||
422 | showfunc=showfunc, ignorews=ignorews, |
|
|||
423 | ignorewsamount=ignorewsamount, |
|
|||
424 | ignoreblanklines=ignoreblanklines)) |
|
|||
425 | for f in added: |
|
|||
426 | to = None |
|
|||
427 | tn = read(f) |
|
|||
428 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, |
|
|||
429 | showfunc=showfunc, ignorews=ignorews, |
|
|||
430 | ignorewsamount=ignorewsamount, |
|
|||
431 | ignoreblanklines=ignoreblanklines)) |
|
|||
432 | for f in removed: |
|
|||
433 | to = repo.file(f).read(mmap[f]) |
|
|||
434 | tn = None |
|
|||
435 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, |
|
|||
436 | showfunc=showfunc, ignorews=ignorews, |
|
|||
437 | ignorewsamount=ignorewsamount, |
|
|||
438 | ignoreblanklines=ignoreblanklines)) |
|
|||
439 |
|
||||
440 | def trimuser(ui, name, rev, revcache): |
|
377 | def trimuser(ui, name, rev, revcache): | |
441 | """trim the name of the user who committed a change""" |
|
378 | """trim the name of the user who committed a change""" | |
442 | user = revcache.get(rev) |
|
379 | user = revcache.get(rev) | |
@@ -493,7 +430,7 b' class changeset_printer(object):' | |||||
493 | self.ui.status(_("date: %s\n") % date) |
|
430 | self.ui.status(_("date: %s\n") % date) | |
494 |
|
431 | |||
495 | if self.ui.debugflag: |
|
432 | if self.ui.debugflag: | |
496 |
files = self.repo. |
|
433 | files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
497 | for key, value in zip([_("files:"), _("files+:"), _("files-:")], |
|
434 | for key, value in zip([_("files:"), _("files+:"), _("files-:")], | |
498 | files): |
|
435 | files): | |
499 | if value: |
|
436 | if value: | |
@@ -537,12 +474,19 b' def show_changeset(ui, repo, opts):' | |||||
537 | return t |
|
474 | return t | |
538 | return changeset_printer(ui, repo) |
|
475 | return changeset_printer(ui, repo) | |
539 |
|
476 | |||
|
477 | def setremoteconfig(ui, opts): | |||
|
478 | "copy remote options to ui tree" | |||
|
479 | if opts.get('ssh'): | |||
|
480 | ui.setconfig("ui", "ssh", opts['ssh']) | |||
|
481 | if opts.get('remotecmd'): | |||
|
482 | ui.setconfig("ui", "remotecmd", opts['remotecmd']) | |||
|
483 | ||||
540 | def show_version(ui): |
|
484 | def show_version(ui): | |
541 | """output version and copyright information""" |
|
485 | """output version and copyright information""" | |
542 | ui.write(_("Mercurial Distributed SCM (version %s)\n") |
|
486 | ui.write(_("Mercurial Distributed SCM (version %s)\n") | |
543 | % version.get_version()) |
|
487 | % version.get_version()) | |
544 | ui.status(_( |
|
488 | ui.status(_( | |
545 | "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n" |
|
489 | "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n" | |
546 | "This is free software; see the source for copying conditions. " |
|
490 | "This is free software; see the source for copying conditions. " | |
547 | "There is NO\nwarranty; " |
|
491 | "There is NO\nwarranty; " | |
548 | "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" |
|
492 | "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" | |
@@ -696,7 +640,7 b' def add(ui, repo, *pats, **opts):' | |||||
696 | """ |
|
640 | """ | |
697 |
|
641 | |||
698 | names = [] |
|
642 | names = [] | |
699 | for src, abs, rel, exact in walk(repo, pats, opts): |
|
643 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): | |
700 | if exact: |
|
644 | if exact: | |
701 | if ui.verbose: |
|
645 | if ui.verbose: | |
702 | ui.status(_('adding %s\n') % rel) |
|
646 | ui.status(_('adding %s\n') % rel) | |
@@ -715,22 +659,7 b' def addremove(ui, repo, *pats, **opts):' | |||||
715 | New files are ignored if they match any of the patterns in .hgignore. As |
|
659 | New files are ignored if they match any of the patterns in .hgignore. As | |
716 | with add, these changes take effect at the next commit. |
|
660 | with add, these changes take effect at the next commit. | |
717 | """ |
|
661 | """ | |
718 |
return addremove |
|
662 | return cmdutil.addremove(repo, pats, opts) | |
719 |
|
||||
720 | def addremove_lock(ui, repo, pats, opts, wlock=None): |
|
|||
721 | add, remove = [], [] |
|
|||
722 | for src, abs, rel, exact in walk(repo, pats, opts): |
|
|||
723 | if src == 'f' and repo.dirstate.state(abs) == '?': |
|
|||
724 | add.append(abs) |
|
|||
725 | if ui.verbose or not exact: |
|
|||
726 | ui.status(_('adding %s\n') % ((pats and rel) or abs)) |
|
|||
727 | if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): |
|
|||
728 | remove.append(abs) |
|
|||
729 | if ui.verbose or not exact: |
|
|||
730 | ui.status(_('removing %s\n') % ((pats and rel) or abs)) |
|
|||
731 | if not opts.get('dry_run'): |
|
|||
732 | repo.add(add, wlock=wlock) |
|
|||
733 | repo.remove(remove, wlock=wlock) |
|
|||
734 |
|
663 | |||
735 | def annotate(ui, repo, *pats, **opts): |
|
664 | def annotate(ui, repo, *pats, **opts): | |
736 | """show changeset information per file line |
|
665 | """show changeset information per file line | |
@@ -773,7 +702,8 b' def annotate(ui, repo, *pats, **opts):' | |||||
773 |
|
702 | |||
774 | ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) |
|
703 | ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) | |
775 |
|
704 | |||
776 |
for src, abs, rel, exact in walk(repo, pats, opts, |
|
705 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, | |
|
706 | node=ctx.node()): | |||
777 | fctx = ctx.filectx(abs) |
|
707 | fctx = ctx.filectx(abs) | |
778 | if not opts['text'] and util.binary(fctx.data()): |
|
708 | if not opts['text'] and util.binary(fctx.data()): | |
779 | ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) |
|
709 | ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) | |
@@ -825,10 +755,10 b' def archive(ui, repo, dest, **opts):' | |||||
825 | raise util.Abort(_('uncommitted merge - please provide a ' |
|
755 | raise util.Abort(_('uncommitted merge - please provide a ' | |
826 | 'specific revision')) |
|
756 | 'specific revision')) | |
827 |
|
757 | |||
828 | dest = make_filename(repo, dest, node) |
|
758 | dest = cmdutil.make_filename(repo, dest, node) | |
829 | if os.path.realpath(dest) == repo.root: |
|
759 | if os.path.realpath(dest) == repo.root: | |
830 | raise util.Abort(_('repository root cannot be destination')) |
|
760 | raise util.Abort(_('repository root cannot be destination')) | |
831 | dummy, matchfn, dummy = matchpats(repo, [], opts) |
|
761 | dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts) | |
832 | kind = opts.get('type') or 'files' |
|
762 | kind = opts.get('type') or 'files' | |
833 | prefix = opts['prefix'] |
|
763 | prefix = opts['prefix'] | |
834 | if dest == '-': |
|
764 | if dest == '-': | |
@@ -836,7 +766,7 b' def archive(ui, repo, dest, **opts):' | |||||
836 | raise util.Abort(_('cannot archive plain files to stdout')) |
|
766 | raise util.Abort(_('cannot archive plain files to stdout')) | |
837 | dest = sys.stdout |
|
767 | dest = sys.stdout | |
838 | if not prefix: prefix = os.path.basename(repo.root) + '-%h' |
|
768 | if not prefix: prefix = os.path.basename(repo.root) + '-%h' | |
839 | prefix = make_filename(repo, prefix, node) |
|
769 | prefix = cmdutil.make_filename(repo, prefix, node) | |
840 | archival.archive(repo, dest, node, kind, not opts['no_decode'], |
|
770 | archival.archive(repo, dest, node, kind, not opts['no_decode'], | |
841 | matchfn, prefix) |
|
771 | matchfn, prefix) | |
842 |
|
772 | |||
@@ -879,7 +809,7 b' def backout(ui, repo, rev, **opts):' | |||||
879 | if opts['parent']: |
|
809 | if opts['parent']: | |
880 | raise util.Abort(_('cannot use --parent on non-merge changeset')) |
|
810 | raise util.Abort(_('cannot use --parent on non-merge changeset')) | |
881 | parent = p1 |
|
811 | parent = p1 | |
882 |
repo |
|
812 | hg.clean(repo, node, show_stats=False) | |
883 | revert_opts = opts.copy() |
|
813 | revert_opts = opts.copy() | |
884 | revert_opts['rev'] = hex(parent) |
|
814 | revert_opts['rev'] = hex(parent) | |
885 | revert(ui, repo, **revert_opts) |
|
815 | revert(ui, repo, **revert_opts) | |
@@ -896,11 +826,13 b' def backout(ui, repo, rev, **opts):' | |||||
896 | if op1 != node: |
|
826 | if op1 != node: | |
897 | if opts['merge']: |
|
827 | if opts['merge']: | |
898 | ui.status(_('merging with changeset %s\n') % nice(op1)) |
|
828 | ui.status(_('merging with changeset %s\n') % nice(op1)) | |
899 |
|
|
829 | n = _lookup(repo, hex(op1)) | |
|
830 | hg.merge(repo, n) | |||
900 | else: |
|
831 | else: | |
901 | ui.status(_('the backout changeset is a new head - ' |
|
832 | ui.status(_('the backout changeset is a new head - ' | |
902 | 'do not forget to merge\n')) |
|
833 | 'do not forget to merge\n')) | |
903 |
ui.status(_('(use "backout -m" |
|
834 | ui.status(_('(use "backout --merge" ' | |
|
835 | 'if you want to auto-merge)\n')) | |||
904 |
|
836 | |||
905 | def bundle(ui, repo, fname, dest=None, **opts): |
|
837 | def bundle(ui, repo, fname, dest=None, **opts): | |
906 | """create a changegroup file |
|
838 | """create a changegroup file | |
@@ -937,9 +869,10 b' def cat(ui, repo, file1, *pats, **opts):' | |||||
937 | %d dirname of file being printed, or '.' if in repo root |
|
869 | %d dirname of file being printed, or '.' if in repo root | |
938 | %p root-relative path name of file being printed |
|
870 | %p root-relative path name of file being printed | |
939 | """ |
|
871 | """ | |
940 | ctx = repo.changectx(opts['rev'] or -1) |
|
872 | ctx = repo.changectx(opts['rev'] or "-1") | |
941 |
for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, |
|
873 | for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, | |
942 | fp = make_file(repo, opts['output'], ctx.node(), pathname=abs) |
|
874 | ctx.node()): | |
|
875 | fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) | |||
943 | fp.write(ctx.filectx(abs).data()) |
|
876 | fp.write(ctx.filectx(abs).data()) | |
944 |
|
877 | |||
945 | def clone(ui, source, dest=None, **opts): |
|
878 | def clone(ui, source, dest=None, **opts): | |
@@ -954,10 +887,25 b' def clone(ui, source, dest=None, **opts)' | |||||
954 | .hg/hgrc file, as the default to be used for future pulls. |
|
887 | .hg/hgrc file, as the default to be used for future pulls. | |
955 |
|
888 | |||
956 | For efficiency, hardlinks are used for cloning whenever the source |
|
889 | For efficiency, hardlinks are used for cloning whenever the source | |
957 |
and destination are on the same filesystem |
|
890 | and destination are on the same filesystem (note this applies only | |
958 | such as AFS, implement hardlinking incorrectly, but do not report |
|
891 | to the repository data, not to the checked out files). Some | |
959 | errors. In these cases, use the --pull option to avoid |
|
892 | filesystems, such as AFS, implement hardlinking incorrectly, but | |
960 | hardlinking. |
|
893 | do not report errors. In these cases, use the --pull option to | |
|
894 | avoid hardlinking. | |||
|
895 | ||||
|
896 | You can safely clone repositories and checked out files using full | |||
|
897 | hardlinks with | |||
|
898 | ||||
|
899 | $ cp -al REPO REPOCLONE | |||
|
900 | ||||
|
901 | which is the fastest way to clone. However, the operation is not | |||
|
902 | atomic (making sure REPO is not modified during the operation is | |||
|
903 | up to you) and you have to make sure your editor breaks hardlinks | |||
|
904 | (Emacs and most Linux Kernel tools do so). | |||
|
905 | ||||
|
906 | If you use the -r option to clone up to a specific revision, no | |||
|
907 | subsequent revisions will be present in the cloned repository. | |||
|
908 | This option implies --pull, even on local repositories. | |||
961 |
|
909 | |||
962 | See pull for valid source format details. |
|
910 | See pull for valid source format details. | |
963 |
|
911 | |||
@@ -965,7 +913,7 b' def clone(ui, source, dest=None, **opts)' | |||||
965 | .hg/hgrc will be created on the remote side. Look at the help text |
|
913 | .hg/hgrc will be created on the remote side. Look at the help text | |
966 | for the pull command for important details about ssh:// URLs. |
|
914 | for the pull command for important details about ssh:// URLs. | |
967 | """ |
|
915 | """ | |
968 | ui.setconfig_remoteopts(**opts) |
|
916 | setremoteconfig(ui, opts) | |
969 | hg.clone(ui, ui.expandpath(source), dest, |
|
917 | hg.clone(ui, ui.expandpath(source), dest, | |
970 | pull=opts['pull'], |
|
918 | pull=opts['pull'], | |
971 | stream=opts['uncompressed'], |
|
919 | stream=opts['uncompressed'], | |
@@ -983,28 +931,13 b' def commit(ui, repo, *pats, **opts):' | |||||
983 | If no commit message is specified, the editor configured in your hgrc |
|
931 | If no commit message is specified, the editor configured in your hgrc | |
984 | or in the EDITOR environment variable is started to enter a message. |
|
932 | or in the EDITOR environment variable is started to enter a message. | |
985 | """ |
|
933 | """ | |
986 |
message = opts |
|
934 | message = logmessage(opts) | |
987 | logfile = opts['logfile'] |
|
|||
988 |
|
||||
989 | if message and logfile: |
|
|||
990 | raise util.Abort(_('options --message and --logfile are mutually ' |
|
|||
991 | 'exclusive')) |
|
|||
992 | if not message and logfile: |
|
|||
993 | try: |
|
|||
994 | if logfile == '-': |
|
|||
995 | message = sys.stdin.read() |
|
|||
996 | else: |
|
|||
997 | message = open(logfile).read() |
|
|||
998 | except IOError, inst: |
|
|||
999 | raise util.Abort(_("can't read commit message '%s': %s") % |
|
|||
1000 | (logfile, inst.strerror)) |
|
|||
1001 |
|
935 | |||
1002 | if opts['addremove']: |
|
936 | if opts['addremove']: | |
1003 |
addremove |
|
937 | cmdutil.addremove(repo, pats, opts) | |
1004 | fns, match, anypats = matchpats(repo, pats, opts) |
|
938 | fns, match, anypats = cmdutil.matchpats(repo, pats, opts) | |
1005 | if pats: |
|
939 | if pats: | |
1006 | modified, added, removed, deleted, unknown = ( |
|
940 | modified, added, removed = repo.status(files=fns, match=match)[:3] | |
1007 | repo.changes(files=fns, match=match)) |
|
|||
1008 | files = modified + added + removed |
|
941 | files = modified + added + removed | |
1009 | else: |
|
942 | else: | |
1010 | files = [] |
|
943 | files = [] | |
@@ -1159,7 +1092,7 b' def docopy(ui, repo, pats, opts, wlock):' | |||||
1159 | copylist = [] |
|
1092 | copylist = [] | |
1160 | for pat in pats: |
|
1093 | for pat in pats: | |
1161 | srcs = [] |
|
1094 | srcs = [] | |
1162 | for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): |
|
1095 | for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts): | |
1163 | origsrc = okaytocopy(abssrc, relsrc, exact) |
|
1096 | origsrc = okaytocopy(abssrc, relsrc, exact) | |
1164 | if origsrc: |
|
1097 | if origsrc: | |
1165 | srcs.append((origsrc, abssrc, relsrc, exact)) |
|
1098 | srcs.append((origsrc, abssrc, relsrc, exact)) | |
@@ -1233,9 +1166,9 b' def debugrebuildstate(ui, repo, rev=None' | |||||
1233 | rev = repo.lookup(rev) |
|
1166 | rev = repo.lookup(rev) | |
1234 | change = repo.changelog.read(rev) |
|
1167 | change = repo.changelog.read(rev) | |
1235 | n = change[0] |
|
1168 | n = change[0] | |
1236 |
files = repo.manifest.read |
|
1169 | files = repo.manifest.read(n) | |
1237 | wlock = repo.wlock() |
|
1170 | wlock = repo.wlock() | |
1238 |
repo.dirstate.rebuild(rev, files |
|
1171 | repo.dirstate.rebuild(rev, files) | |
1239 |
|
1172 | |||
1240 | def debugcheckstate(ui, repo): |
|
1173 | def debugcheckstate(ui, repo): | |
1241 | """validate the correctness of the current dirstate""" |
|
1174 | """validate the correctness of the current dirstate""" | |
@@ -1376,7 +1309,7 b' def debugrename(ui, repo, file, rev=None' | |||||
1376 |
|
1309 | |||
1377 | def debugwalk(ui, repo, *pats, **opts): |
|
1310 | def debugwalk(ui, repo, *pats, **opts): | |
1378 | """show how files match on given patterns""" |
|
1311 | """show how files match on given patterns""" | |
1379 | items = list(walk(repo, pats, opts)) |
|
1312 | items = list(cmdutil.walk(repo, pats, opts)) | |
1380 | if not items: |
|
1313 | if not items: | |
1381 | return |
|
1314 | return | |
1382 | fmt = '%%s %%-%ds %%-%ds %%s' % ( |
|
1315 | fmt = '%%s %%-%ds %%-%ds %%s' % ( | |
@@ -1405,37 +1338,10 b' def diff(ui, repo, *pats, **opts):' | |||||
1405 | """ |
|
1338 | """ | |
1406 | node1, node2 = revpair(ui, repo, opts['rev']) |
|
1339 | node1, node2 = revpair(ui, repo, opts['rev']) | |
1407 |
|
1340 | |||
1408 | fns, matchfn, anypats = matchpats(repo, pats, opts) |
|
1341 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
1409 |
|
1342 | |||
1410 |
|
|
1343 | patch.diff(repo, node1, node2, fns, match=matchfn, | |
1411 | text=opts['text'], opts=opts) |
|
1344 | opts=patch.diffopts(ui, opts)) | |
1412 |
|
||||
1413 | def doexport(ui, repo, changeset, seqno, total, revwidth, opts): |
|
|||
1414 | node = repo.lookup(changeset) |
|
|||
1415 | parents = [p for p in repo.changelog.parents(node) if p != nullid] |
|
|||
1416 | if opts['switch_parent']: |
|
|||
1417 | parents.reverse() |
|
|||
1418 | prev = (parents and parents[0]) or nullid |
|
|||
1419 | change = repo.changelog.read(node) |
|
|||
1420 |
|
||||
1421 | fp = make_file(repo, opts['output'], node, total=total, seqno=seqno, |
|
|||
1422 | revwidth=revwidth) |
|
|||
1423 | if fp != sys.stdout: |
|
|||
1424 | ui.note("%s\n" % fp.name) |
|
|||
1425 |
|
||||
1426 | fp.write("# HG changeset patch\n") |
|
|||
1427 | fp.write("# User %s\n" % change[1]) |
|
|||
1428 | fp.write("# Date %d %d\n" % change[2]) |
|
|||
1429 | fp.write("# Node ID %s\n" % hex(node)) |
|
|||
1430 | fp.write("# Parent %s\n" % hex(prev)) |
|
|||
1431 | if len(parents) > 1: |
|
|||
1432 | fp.write("# Parent %s\n" % hex(parents[1])) |
|
|||
1433 | fp.write(change[4].rstrip()) |
|
|||
1434 | fp.write("\n\n") |
|
|||
1435 |
|
||||
1436 | dodiff(fp, ui, repo, prev, node, text=opts['text']) |
|
|||
1437 | if fp != sys.stdout: |
|
|||
1438 | fp.close() |
|
|||
1439 |
|
1345 | |||
1440 | def export(ui, repo, *changesets, **opts): |
|
1346 | def export(ui, repo, *changesets, **opts): | |
1441 | """dump the header and diffs for one or more changesets |
|
1347 | """dump the header and diffs for one or more changesets | |
@@ -1466,15 +1372,14 b' def export(ui, repo, *changesets, **opts' | |||||
1466 | """ |
|
1372 | """ | |
1467 | if not changesets: |
|
1373 | if not changesets: | |
1468 | raise util.Abort(_("export requires at least one changeset")) |
|
1374 | raise util.Abort(_("export requires at least one changeset")) | |
1469 | seqno = 0 |
|
|||
1470 | revs = list(revrange(ui, repo, changesets)) |
|
1375 | revs = list(revrange(ui, repo, changesets)) | |
1471 |
|
|
1376 | if len(revs) > 1: | |
1472 | revwidth = max(map(len, revs)) |
|
1377 | ui.note(_('exporting patches:\n')) | |
1473 | msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n") |
|
1378 | else: | |
1474 | ui.note(msg) |
|
1379 | ui.note(_('exporting patch:\n')) | |
1475 | for cset in revs: |
|
1380 | patch.export(repo, map(repo.lookup, revs), template=opts['output'], | |
1476 | seqno += 1 |
|
1381 | switch_parent=opts['switch_parent'], | |
1477 | doexport(ui, repo, cset, seqno, total, revwidth, opts) |
|
1382 | opts=patch.diffopts(ui, opts)) | |
1478 |
|
1383 | |||
1479 | def forget(ui, repo, *pats, **opts): |
|
1384 | def forget(ui, repo, *pats, **opts): | |
1480 | """don't add the specified files on the next commit (DEPRECATED) |
|
1385 | """don't add the specified files on the next commit (DEPRECATED) | |
@@ -1487,7 +1392,7 b' def forget(ui, repo, *pats, **opts):' | |||||
1487 | """ |
|
1392 | """ | |
1488 | ui.warn(_("(the forget command is deprecated; use revert instead)\n")) |
|
1393 | ui.warn(_("(the forget command is deprecated; use revert instead)\n")) | |
1489 | forget = [] |
|
1394 | forget = [] | |
1490 | for src, abs, rel, exact in walk(repo, pats, opts): |
|
1395 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): | |
1491 | if repo.dirstate.state(abs) == 'a': |
|
1396 | if repo.dirstate.state(abs) == 'a': | |
1492 | forget.append(abs) |
|
1397 | forget.append(abs) | |
1493 | if ui.verbose or not exact: |
|
1398 | if ui.verbose or not exact: | |
@@ -1544,42 +1449,56 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1544 | self.linenum = linenum |
|
1449 | self.linenum = linenum | |
1545 | self.colstart = colstart |
|
1450 | self.colstart = colstart | |
1546 | self.colend = colend |
|
1451 | self.colend = colend | |
|
1452 | ||||
1547 | def __eq__(self, other): |
|
1453 | def __eq__(self, other): | |
1548 | return self.line == other.line |
|
1454 | return self.line == other.line | |
1549 | def __hash__(self): |
|
|||
1550 | return hash(self.line) |
|
|||
1551 |
|
1455 | |||
1552 | matches = {} |
|
1456 | matches = {} | |
|
1457 | copies = {} | |||
1553 | def grepbody(fn, rev, body): |
|
1458 | def grepbody(fn, rev, body): | |
1554 |
matches[rev].setdefault(fn, |
|
1459 | matches[rev].setdefault(fn, []) | |
1555 | m = matches[rev][fn] |
|
1460 | m = matches[rev][fn] | |
1556 | for lnum, cstart, cend, line in matchlines(body): |
|
1461 | for lnum, cstart, cend, line in matchlines(body): | |
1557 | s = linestate(line, lnum, cstart, cend) |
|
1462 | s = linestate(line, lnum, cstart, cend) | |
1558 |
m |
|
1463 | m.append(s) | |
1559 |
|
1464 | |||
1560 | # FIXME: prev isn't used, why ? |
|
1465 | def difflinestates(a, b): | |
|
1466 | sm = difflib.SequenceMatcher(None, a, b) | |||
|
1467 | for tag, alo, ahi, blo, bhi in sm.get_opcodes(): | |||
|
1468 | if tag == 'insert': | |||
|
1469 | for i in range(blo, bhi): | |||
|
1470 | yield ('+', b[i]) | |||
|
1471 | elif tag == 'delete': | |||
|
1472 | for i in range(alo, ahi): | |||
|
1473 | yield ('-', a[i]) | |||
|
1474 | elif tag == 'replace': | |||
|
1475 | for i in range(alo, ahi): | |||
|
1476 | yield ('-', a[i]) | |||
|
1477 | for i in range(blo, bhi): | |||
|
1478 | yield ('+', b[i]) | |||
|
1479 | ||||
1561 | prev = {} |
|
1480 | prev = {} | |
1562 | ucache = {} |
|
1481 | ucache = {} | |
1563 | def display(fn, rev, states, prevstates): |
|
1482 | def display(fn, rev, states, prevstates): | |
1564 | diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates))) |
|
|||
1565 | diff.sort(lambda x, y: cmp(x.linenum, y.linenum)) |
|
|||
1566 | counts = {'-': 0, '+': 0} |
|
1483 | counts = {'-': 0, '+': 0} | |
1567 | filerevmatches = {} |
|
1484 | filerevmatches = {} | |
1568 | for l in diff: |
|
1485 | if incrementing or not opts['all']: | |
|
1486 | a, b = prevstates, states | |||
|
1487 | else: | |||
|
1488 | a, b = states, prevstates | |||
|
1489 | for change, l in difflinestates(a, b): | |||
1569 | if incrementing or not opts['all']: |
|
1490 | if incrementing or not opts['all']: | |
1570 | change = ((l in prevstates) and '-') or '+' |
|
|||
1571 | r = rev |
|
1491 | r = rev | |
1572 | else: |
|
1492 | else: | |
1573 | change = ((l in states) and '-') or '+' |
|
|||
1574 | r = prev[fn] |
|
1493 | r = prev[fn] | |
1575 |
cols = [fn, str(r |
|
1494 | cols = [fn, str(r)] | |
1576 | if opts['line_number']: |
|
1495 | if opts['line_number']: | |
1577 | cols.append(str(l.linenum)) |
|
1496 | cols.append(str(l.linenum)) | |
1578 | if opts['all']: |
|
1497 | if opts['all']: | |
1579 | cols.append(change) |
|
1498 | cols.append(change) | |
1580 | if opts['user']: |
|
1499 | if opts['user']: | |
1581 |
cols.append(trimuser(ui, getchange(r |
|
1500 | cols.append(trimuser(ui, getchange(r)[1], rev, | |
1582 |
|
|
1501 | ucache)) | |
1583 | if opts['files_with_matches']: |
|
1502 | if opts['files_with_matches']: | |
1584 | c = (fn, rev) |
|
1503 | c = (fn, rev) | |
1585 | if c in filerevmatches: |
|
1504 | if c in filerevmatches: | |
@@ -1596,6 +1515,7 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1596 | changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) |
|
1515 | changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) | |
1597 | count = 0 |
|
1516 | count = 0 | |
1598 | incrementing = False |
|
1517 | incrementing = False | |
|
1518 | follow = opts.get('follow') | |||
1599 | for st, rev, fns in changeiter: |
|
1519 | for st, rev, fns in changeiter: | |
1600 | if st == 'window': |
|
1520 | if st == 'window': | |
1601 | incrementing = rev |
|
1521 | incrementing = rev | |
@@ -1610,20 +1530,31 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1610 | fstate.setdefault(fn, {}) |
|
1530 | fstate.setdefault(fn, {}) | |
1611 | try: |
|
1531 | try: | |
1612 | grepbody(fn, rev, getfile(fn).read(mf[fn])) |
|
1532 | grepbody(fn, rev, getfile(fn).read(mf[fn])) | |
|
1533 | if follow: | |||
|
1534 | copied = getfile(fn).renamed(mf[fn]) | |||
|
1535 | if copied: | |||
|
1536 | copies.setdefault(rev, {})[fn] = copied[0] | |||
1613 | except KeyError: |
|
1537 | except KeyError: | |
1614 | pass |
|
1538 | pass | |
1615 | elif st == 'iter': |
|
1539 | elif st == 'iter': | |
1616 | states = matches[rev].items() |
|
1540 | states = matches[rev].items() | |
1617 | states.sort() |
|
1541 | states.sort() | |
1618 | for fn, m in states: |
|
1542 | for fn, m in states: | |
|
1543 | copy = copies.get(rev, {}).get(fn) | |||
1619 | if fn in skip: |
|
1544 | if fn in skip: | |
|
1545 | if copy: | |||
|
1546 | skip[copy] = True | |||
1620 | continue |
|
1547 | continue | |
1621 | if incrementing or not opts['all'] or fstate[fn]: |
|
1548 | if incrementing or not opts['all'] or fstate[fn]: | |
1622 | pos, neg = display(fn, rev, m, fstate[fn]) |
|
1549 | pos, neg = display(fn, rev, m, fstate[fn]) | |
1623 | count += pos + neg |
|
1550 | count += pos + neg | |
1624 | if pos and not opts['all']: |
|
1551 | if pos and not opts['all']: | |
1625 | skip[fn] = True |
|
1552 | skip[fn] = True | |
|
1553 | if copy: | |||
|
1554 | skip[copy] = True | |||
1626 | fstate[fn] = m |
|
1555 | fstate[fn] = m | |
|
1556 | if copy: | |||
|
1557 | fstate[copy] = m | |||
1627 | prev[fn] = rev |
|
1558 | prev[fn] = rev | |
1628 |
|
1559 | |||
1629 | if not incrementing: |
|
1560 | if not incrementing: | |
@@ -1632,7 +1563,8 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1632 | for fn, state in fstate: |
|
1563 | for fn, state in fstate: | |
1633 | if fn in skip: |
|
1564 | if fn in skip: | |
1634 | continue |
|
1565 | continue | |
1635 | display(fn, rev, {}, state) |
|
1566 | if fn not in copies.get(prev[fn], {}): | |
|
1567 | display(fn, rev, {}, state) | |||
1636 | return (count == 0 and 1) or 0 |
|
1568 | return (count == 0 and 1) or 0 | |
1637 |
|
1569 | |||
1638 | def heads(ui, repo, **opts): |
|
1570 | def heads(ui, repo, **opts): | |
@@ -1670,7 +1602,7 b' def identify(ui, repo):' | |||||
1670 | return |
|
1602 | return | |
1671 |
|
1603 | |||
1672 | hexfunc = ui.verbose and hex or short |
|
1604 | hexfunc = ui.verbose and hex or short | |
1673 |
modified, added, removed, deleted |
|
1605 | modified, added, removed, deleted = repo.status()[:4] | |
1674 | output = ["%s%s" % |
|
1606 | output = ["%s%s" % | |
1675 | ('+'.join([hexfunc(parent) for parent in parents]), |
|
1607 | ('+'.join([hexfunc(parent) for parent in parents]), | |
1676 | (modified or added or removed or deleted) and "+" or "")] |
|
1608 | (modified or added or removed or deleted) and "+" or "")] | |
@@ -1714,81 +1646,23 b' def import_(ui, repo, patch1, *patches, ' | |||||
1714 | d = opts["base"] |
|
1646 | d = opts["base"] | |
1715 | strip = opts["strip"] |
|
1647 | strip = opts["strip"] | |
1716 |
|
1648 | |||
1717 | mailre = re.compile(r'(?:From |[\w-]+:)') |
|
1649 | wlock = repo.wlock() | |
1718 |
|
1650 | lock = repo.lock() | ||
1719 | # attempt to detect the start of a patch |
|
1651 | ||
1720 | # (this heuristic is borrowed from quilt) |
|
1652 | for p in patches: | |
1721 | diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + |
|
1653 | pf = os.path.join(d, p) | |
1722 | 'retrieving revision [0-9]+(\.[0-9]+)*$|' + |
|
1654 | ||
1723 | '(---|\*\*\*)[ \t])', re.MULTILINE) |
|
|||
1724 |
|
||||
1725 | for patch in patches: |
|
|||
1726 | pf = os.path.join(d, patch) |
|
|||
1727 |
|
||||
1728 | message = None |
|
|||
1729 | user = None |
|
|||
1730 | date = None |
|
|||
1731 | hgpatch = False |
|
|||
1732 |
|
||||
1733 | p = email.Parser.Parser() |
|
|||
1734 | if pf == '-': |
|
1655 | if pf == '-': | |
1735 | msg = p.parse(sys.stdin) |
|
|||
1736 | ui.status(_("applying patch from stdin\n")) |
|
1656 | ui.status(_("applying patch from stdin\n")) | |
|
1657 | tmpname, message, user, date = patch.extract(ui, sys.stdin) | |||
1737 | else: |
|
1658 | else: | |
1738 | msg = p.parse(file(pf)) |
|
1659 | ui.status(_("applying %s\n") % p) | |
1739 | ui.status(_("applying %s\n") % patch) |
|
1660 | tmpname, message, user, date = patch.extract(ui, file(pf)) | |
1740 |
|
1661 | |||
1741 | fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') |
|
1662 | if tmpname is None: | |
1742 | tmpfp = os.fdopen(fd, 'w') |
|
1663 | raise util.Abort(_('no diffs found')) | |
|
1664 | ||||
1743 | try: |
|
1665 | try: | |
1744 | message = msg['Subject'] |
|
|||
1745 | if message: |
|
|||
1746 | message = message.replace('\n\t', ' ') |
|
|||
1747 | ui.debug('Subject: %s\n' % message) |
|
|||
1748 | user = msg['From'] |
|
|||
1749 | if user: |
|
|||
1750 | ui.debug('From: %s\n' % user) |
|
|||
1751 | diffs_seen = 0 |
|
|||
1752 | ok_types = ('text/plain', 'text/x-patch') |
|
|||
1753 | for part in msg.walk(): |
|
|||
1754 | content_type = part.get_content_type() |
|
|||
1755 | ui.debug('Content-Type: %s\n' % content_type) |
|
|||
1756 | if content_type not in ok_types: |
|
|||
1757 | continue |
|
|||
1758 | payload = part.get_payload(decode=True) |
|
|||
1759 | m = diffre.search(payload) |
|
|||
1760 | if m: |
|
|||
1761 | ui.debug(_('found patch at byte %d\n') % m.start(0)) |
|
|||
1762 | diffs_seen += 1 |
|
|||
1763 | hgpatch = False |
|
|||
1764 | fp = cStringIO.StringIO() |
|
|||
1765 | if message: |
|
|||
1766 | fp.write(message) |
|
|||
1767 | fp.write('\n') |
|
|||
1768 | for line in payload[:m.start(0)].splitlines(): |
|
|||
1769 | if line.startswith('# HG changeset patch'): |
|
|||
1770 | ui.debug(_('patch generated by hg export\n')) |
|
|||
1771 | hgpatch = True |
|
|||
1772 | # drop earlier commit message content |
|
|||
1773 | fp.seek(0) |
|
|||
1774 | fp.truncate() |
|
|||
1775 | elif hgpatch: |
|
|||
1776 | if line.startswith('# User '): |
|
|||
1777 | user = line[7:] |
|
|||
1778 | ui.debug('From: %s\n' % user) |
|
|||
1779 | elif line.startswith("# Date "): |
|
|||
1780 | date = line[7:] |
|
|||
1781 | if not line.startswith('# '): |
|
|||
1782 | fp.write(line) |
|
|||
1783 | fp.write('\n') |
|
|||
1784 | message = fp.getvalue() |
|
|||
1785 | if tmpfp: |
|
|||
1786 | tmpfp.write(payload) |
|
|||
1787 | if not payload.endswith('\n'): |
|
|||
1788 | tmpfp.write('\n') |
|
|||
1789 | elif not diffs_seen and message and content_type == 'text/plain': |
|
|||
1790 | message += '\n' + payload |
|
|||
1791 |
|
||||
1792 | if opts['message']: |
|
1666 | if opts['message']: | |
1793 | # pickup the cmdline msg |
|
1667 | # pickup the cmdline msg | |
1794 | message = opts['message'] |
|
1668 | message = opts['message'] | |
@@ -1800,14 +1674,9 b' def import_(ui, repo, patch1, *patches, ' | |||||
1800 | message = None |
|
1674 | message = None | |
1801 | ui.debug(_('message:\n%s\n') % message) |
|
1675 | ui.debug(_('message:\n%s\n') % message) | |
1802 |
|
1676 | |||
1803 | tmpfp.close() |
|
1677 | files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) | |
1804 | if not diffs_seen: |
|
1678 | files = patch.updatedir(ui, repo, files, wlock=wlock) | |
1805 | raise util.Abort(_('no diffs found')) |
|
1679 | repo.commit(files, message, user, date, wlock=wlock, lock=lock) | |
1806 |
|
||||
1807 | files = util.patch(strip, tmpname, ui) |
|
|||
1808 | if len(files) > 0: |
|
|||
1809 | addremove_lock(ui, repo, files, {}) |
|
|||
1810 | repo.commit(files, message, user, date) |
|
|||
1811 | finally: |
|
1680 | finally: | |
1812 | os.unlink(tmpname) |
|
1681 | os.unlink(tmpname) | |
1813 |
|
1682 | |||
@@ -1824,7 +1693,7 b' def incoming(ui, repo, source="default",' | |||||
1824 | See pull for valid source format details. |
|
1693 | See pull for valid source format details. | |
1825 | """ |
|
1694 | """ | |
1826 | source = ui.expandpath(source) |
|
1695 | source = ui.expandpath(source) | |
1827 | ui.setconfig_remoteopts(**opts) |
|
1696 | setremoteconfig(ui, opts) | |
1828 |
|
1697 | |||
1829 | other = hg.repository(ui, source) |
|
1698 | other = hg.repository(ui, source) | |
1830 | incoming = repo.findincoming(other, force=opts["force"]) |
|
1699 | incoming = repo.findincoming(other, force=opts["force"]) | |
@@ -1860,7 +1729,7 b' def incoming(ui, repo, source="default",' | |||||
1860 | displayer.show(changenode=n) |
|
1729 | displayer.show(changenode=n) | |
1861 | if opts['patch']: |
|
1730 | if opts['patch']: | |
1862 | prev = (parents and parents[0]) or nullid |
|
1731 | prev = (parents and parents[0]) or nullid | |
1863 |
|
|
1732 | patch.diff(repo, other, prev, n) | |
1864 | ui.write("\n") |
|
1733 | ui.write("\n") | |
1865 | finally: |
|
1734 | finally: | |
1866 | if hasattr(other, 'close'): |
|
1735 | if hasattr(other, 'close'): | |
@@ -1880,7 +1749,7 b' def init(ui, dest=".", **opts):' | |||||
1880 | Look at the help text for the pull command for important details |
|
1749 | Look at the help text for the pull command for important details | |
1881 | about ssh:// URLs. |
|
1750 | about ssh:// URLs. | |
1882 | """ |
|
1751 | """ | |
1883 | ui.setconfig_remoteopts(**opts) |
|
1752 | setremoteconfig(ui, opts) | |
1884 | hg.repository(ui, dest, create=1) |
|
1753 | hg.repository(ui, dest, create=1) | |
1885 |
|
1754 | |||
1886 | def locate(ui, repo, *pats, **opts): |
|
1755 | def locate(ui, repo, *pats, **opts): | |
@@ -1908,8 +1777,8 b' def locate(ui, repo, *pats, **opts):' | |||||
1908 | else: |
|
1777 | else: | |
1909 | node = None |
|
1778 | node = None | |
1910 |
|
1779 | |||
1911 | for src, abs, rel, exact in walk(repo, pats, opts, node=node, |
|
1780 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, | |
1912 | head='(?:.*/|)'): |
|
1781 | head='(?:.*/|)'): | |
1913 | if not node and repo.dirstate.state(abs) == '?': |
|
1782 | if not node and repo.dirstate.state(abs) == '?': | |
1914 | continue |
|
1783 | continue | |
1915 | if opts['fullpath']: |
|
1784 | if opts['fullpath']: | |
@@ -1920,7 +1789,18 b' def locate(ui, repo, *pats, **opts):' | |||||
1920 | def log(ui, repo, *pats, **opts): |
|
1789 | def log(ui, repo, *pats, **opts): | |
1921 | """show revision history of entire repository or files |
|
1790 | """show revision history of entire repository or files | |
1922 |
|
1791 | |||
1923 |
Print the revision history of the specified files or the entire |
|
1792 | Print the revision history of the specified files or the entire | |
|
1793 | project. | |||
|
1794 | ||||
|
1795 | File history is shown without following rename or copy history of | |||
|
1796 | files. Use -f/--follow with a file name to follow history across | |||
|
1797 | renames and copies. --follow without a file name will only show | |||
|
1798 | ancestors or descendants of the starting revision. --follow-first | |||
|
1799 | only follows the first parent of merge revisions. | |||
|
1800 | ||||
|
1801 | If no revision range is specified, the default is tip:0 unless | |||
|
1802 | --follow is set, in which case the working directory parent is | |||
|
1803 | used as the starting revision. | |||
1924 |
|
1804 | |||
1925 | By default this command outputs: changeset id and hash, tags, |
|
1805 | By default this command outputs: changeset id and hash, tags, | |
1926 | non-trivial parents, user, date and time, and a summary for each |
|
1806 | non-trivial parents, user, date and time, and a summary for each | |
@@ -2000,7 +1880,7 b' def log(ui, repo, *pats, **opts):' | |||||
2000 | displayer.show(rev, brinfo=br) |
|
1880 | displayer.show(rev, brinfo=br) | |
2001 | if opts['patch']: |
|
1881 | if opts['patch']: | |
2002 | prev = (parents and parents[0]) or nullid |
|
1882 | prev = (parents and parents[0]) or nullid | |
2003 |
|
|
1883 | patch.diff(repo, prev, changenode, match=matchfn, fp=du) | |
2004 | du.write("\n\n") |
|
1884 | du.write("\n\n") | |
2005 | elif st == 'iter': |
|
1885 | elif st == 'iter': | |
2006 | if count == limit: break |
|
1886 | if count == limit: break | |
@@ -2031,22 +1911,44 b' def manifest(ui, repo, rev=None):' | |||||
2031 | else: |
|
1911 | else: | |
2032 | n = repo.manifest.tip() |
|
1912 | n = repo.manifest.tip() | |
2033 | m = repo.manifest.read(n) |
|
1913 | m = repo.manifest.read(n) | |
2034 | mf = repo.manifest.readflags(n) |
|
|||
2035 | files = m.keys() |
|
1914 | files = m.keys() | |
2036 | files.sort() |
|
1915 | files.sort() | |
2037 |
|
1916 | |||
2038 | for f in files: |
|
1917 | for f in files: | |
2039 |
ui.write("%40s %3s %s\n" % (hex(m[f]), |
|
1918 | ui.write("%40s %3s %s\n" % (hex(m[f]), | |
2040 |
|
1919 | m.execf(f) and "755" or "644", f)) | ||
2041 | def merge(ui, repo, node=None, **opts): |
|
1920 | ||
|
1921 | def merge(ui, repo, node=None, force=None, branch=None): | |||
2042 | """Merge working directory with another revision |
|
1922 | """Merge working directory with another revision | |
2043 |
|
1923 | |||
2044 | Merge the contents of the current working directory and the |
|
1924 | Merge the contents of the current working directory and the | |
2045 | requested revision. Files that changed between either parent are |
|
1925 | requested revision. Files that changed between either parent are | |
2046 | marked as changed for the next commit and a commit must be |
|
1926 | marked as changed for the next commit and a commit must be | |
2047 | performed before any further updates are allowed. |
|
1927 | performed before any further updates are allowed. | |
|
1928 | ||||
|
1929 | If no revision is specified, the working directory's parent is a | |||
|
1930 | head revision, and the repository contains exactly one other head, | |||
|
1931 | the other head is merged with by default. Otherwise, an explicit | |||
|
1932 | revision to merge with must be provided. | |||
2048 | """ |
|
1933 | """ | |
2049 | return doupdate(ui, repo, node=node, merge=True, **opts) |
|
1934 | ||
|
1935 | if node: | |||
|
1936 | node = _lookup(repo, node, branch) | |||
|
1937 | else: | |||
|
1938 | heads = repo.heads() | |||
|
1939 | if len(heads) > 2: | |||
|
1940 | raise util.Abort(_('repo has %d heads - ' | |||
|
1941 | 'please merge with an explicit rev') % | |||
|
1942 | len(heads)) | |||
|
1943 | if len(heads) == 1: | |||
|
1944 | raise util.Abort(_('there is nothing to merge - ' | |||
|
1945 | 'use "hg update" instead')) | |||
|
1946 | parent = repo.dirstate.parents()[0] | |||
|
1947 | if parent not in heads: | |||
|
1948 | raise util.Abort(_('working dir not at a head rev - ' | |||
|
1949 | 'use "hg update" or merge with an explicit rev')) | |||
|
1950 | node = parent == heads[0] and heads[-1] or heads[0] | |||
|
1951 | return hg.merge(repo, node, force=force) | |||
2050 |
|
1952 | |||
2051 | def outgoing(ui, repo, dest=None, **opts): |
|
1953 | def outgoing(ui, repo, dest=None, **opts): | |
2052 | """show changesets not found in destination |
|
1954 | """show changesets not found in destination | |
@@ -2058,7 +1960,7 b' def outgoing(ui, repo, dest=None, **opts' | |||||
2058 | See pull for valid destination format details. |
|
1960 | See pull for valid destination format details. | |
2059 | """ |
|
1961 | """ | |
2060 | dest = ui.expandpath(dest or 'default-push', dest or 'default') |
|
1962 | dest = ui.expandpath(dest or 'default-push', dest or 'default') | |
2061 | ui.setconfig_remoteopts(**opts) |
|
1963 | setremoteconfig(ui, opts) | |
2062 | revs = None |
|
1964 | revs = None | |
2063 | if opts['rev']: |
|
1965 | if opts['rev']: | |
2064 | revs = [repo.lookup(rev) for rev in opts['rev']] |
|
1966 | revs = [repo.lookup(rev) for rev in opts['rev']] | |
@@ -2079,16 +1981,31 b' def outgoing(ui, repo, dest=None, **opts' | |||||
2079 | displayer.show(changenode=n) |
|
1981 | displayer.show(changenode=n) | |
2080 | if opts['patch']: |
|
1982 | if opts['patch']: | |
2081 | prev = (parents and parents[0]) or nullid |
|
1983 | prev = (parents and parents[0]) or nullid | |
2082 |
|
|
1984 | patch.diff(repo, prev, n) | |
2083 | ui.write("\n") |
|
1985 | ui.write("\n") | |
2084 |
|
1986 | |||
2085 | def parents(ui, repo, rev=None, branches=None, **opts): |
|
1987 | def parents(ui, repo, file_=None, rev=None, branches=None, **opts): | |
2086 | """show the parents of the working dir or revision |
|
1988 | """show the parents of the working dir or revision | |
2087 |
|
1989 | |||
2088 | Print the working directory's parent revisions. |
|
1990 | Print the working directory's parent revisions. | |
2089 | """ |
|
1991 | """ | |
|
1992 | # legacy | |||
|
1993 | if file_ and not rev: | |||
|
1994 | try: | |||
|
1995 | rev = repo.lookup(file_) | |||
|
1996 | file_ = None | |||
|
1997 | except hg.RepoError: | |||
|
1998 | pass | |||
|
1999 | else: | |||
|
2000 | ui.warn(_("'hg parent REV' is deprecated, " | |||
|
2001 | "please use 'hg parents -r REV instead\n")) | |||
|
2002 | ||||
2090 | if rev: |
|
2003 | if rev: | |
2091 | p = repo.changelog.parents(repo.lookup(rev)) |
|
2004 | if file_: | |
|
2005 | ctx = repo.filectx(file_, changeid=rev) | |||
|
2006 | else: | |||
|
2007 | ctx = repo.changectx(rev) | |||
|
2008 | p = [cp.node() for cp in ctx.parents()] | |||
2092 | else: |
|
2009 | else: | |
2093 | p = repo.dirstate.parents() |
|
2010 | p = repo.dirstate.parents() | |
2094 |
|
2011 | |||
@@ -2125,7 +2042,7 b' def postincoming(ui, repo, modheads, opt' | |||||
2125 | return |
|
2042 | return | |
2126 | if optupdate: |
|
2043 | if optupdate: | |
2127 | if modheads == 1: |
|
2044 | if modheads == 1: | |
2128 |
return |
|
2045 | return hg.update(repo, repo.changelog.tip()) # update | |
2129 | else: |
|
2046 | else: | |
2130 | ui.status(_("not updating, since new heads added\n")) |
|
2047 | ui.status(_("not updating, since new heads added\n")) | |
2131 | if modheads > 1: |
|
2048 | if modheads > 1: | |
@@ -2165,7 +2082,7 b' def pull(ui, repo, source="default", **o' | |||||
2165 | with the --ssh command line option. |
|
2082 | with the --ssh command line option. | |
2166 | """ |
|
2083 | """ | |
2167 | source = ui.expandpath(source) |
|
2084 | source = ui.expandpath(source) | |
2168 | ui.setconfig_remoteopts(**opts) |
|
2085 | setremoteconfig(ui, opts) | |
2169 |
|
2086 | |||
2170 | other = hg.repository(ui, source) |
|
2087 | other = hg.repository(ui, source) | |
2171 | ui.status(_('pulling from %s\n') % (source)) |
|
2088 | ui.status(_('pulling from %s\n') % (source)) | |
@@ -2203,7 +2120,7 b' def push(ui, repo, dest=None, **opts):' | |||||
2203 | feature is enabled on the remote Mercurial server. |
|
2120 | feature is enabled on the remote Mercurial server. | |
2204 | """ |
|
2121 | """ | |
2205 | dest = ui.expandpath(dest or 'default-push', dest or 'default') |
|
2122 | dest = ui.expandpath(dest or 'default-push', dest or 'default') | |
2206 | ui.setconfig_remoteopts(**opts) |
|
2123 | setremoteconfig(ui, opts) | |
2207 |
|
2124 | |||
2208 | other = hg.repository(ui, dest) |
|
2125 | other = hg.repository(ui, dest) | |
2209 | ui.status('pushing to %s\n' % (dest)) |
|
2126 | ui.status('pushing to %s\n' % (dest)) | |
@@ -2257,7 +2174,7 b' def recover(ui, repo):' | |||||
2257 | operation. It should only be necessary when Mercurial suggests it. |
|
2174 | operation. It should only be necessary when Mercurial suggests it. | |
2258 | """ |
|
2175 | """ | |
2259 | if repo.recover(): |
|
2176 | if repo.recover(): | |
2260 |
return |
|
2177 | return hg.verify(repo) | |
2261 | return 1 |
|
2178 | return 1 | |
2262 |
|
2179 | |||
2263 | def remove(ui, repo, *pats, **opts): |
|
2180 | def remove(ui, repo, *pats, **opts): | |
@@ -2277,12 +2194,12 b' def remove(ui, repo, *pats, **opts):' | |||||
2277 | names = [] |
|
2194 | names = [] | |
2278 | if not opts['after'] and not pats: |
|
2195 | if not opts['after'] and not pats: | |
2279 | raise util.Abort(_('no files specified')) |
|
2196 | raise util.Abort(_('no files specified')) | |
2280 | files, matchfn, anypats = matchpats(repo, pats, opts) |
|
2197 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
2281 | exact = dict.fromkeys(files) |
|
2198 | exact = dict.fromkeys(files) | |
2282 |
mardu = map(dict.fromkeys, repo. |
|
2199 | mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] | |
2283 | modified, added, removed, deleted, unknown = mardu |
|
2200 | modified, added, removed, deleted, unknown = mardu | |
2284 | remove, forget = [], [] |
|
2201 | remove, forget = [], [] | |
2285 | for src, abs, rel, exact in walk(repo, pats, opts): |
|
2202 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): | |
2286 | reason = None |
|
2203 | reason = None | |
2287 | if abs not in deleted and opts['after']: |
|
2204 | if abs not in deleted and opts['after']: | |
2288 | reason = _('is still present') |
|
2205 | reason = _('is still present') | |
@@ -2389,20 +2306,21 b' def revert(ui, repo, *pats, **opts):' | |||||
2389 |
|
2306 | |||
2390 | # walk dirstate. |
|
2307 | # walk dirstate. | |
2391 |
|
2308 | |||
2392 |
for src, abs, rel, exact in walk(repo, pats, opts, |
|
2309 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, | |
|
2310 | badmatch=mf.has_key): | |||
2393 | names[abs] = (rel, exact) |
|
2311 | names[abs] = (rel, exact) | |
2394 | if src == 'b': |
|
2312 | if src == 'b': | |
2395 | target_only[abs] = True |
|
2313 | target_only[abs] = True | |
2396 |
|
2314 | |||
2397 | # walk target manifest. |
|
2315 | # walk target manifest. | |
2398 |
|
2316 | |||
2399 | for src, abs, rel, exact in walk(repo, pats, opts, node=node, |
|
2317 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, | |
2400 | badmatch=names.has_key): |
|
2318 | badmatch=names.has_key): | |
2401 | if abs in names: continue |
|
2319 | if abs in names: continue | |
2402 | names[abs] = (rel, exact) |
|
2320 | names[abs] = (rel, exact) | |
2403 | target_only[abs] = True |
|
2321 | target_only[abs] = True | |
2404 |
|
2322 | |||
2405 |
changes = repo. |
|
2323 | changes = repo.status(match=names.has_key, wlock=wlock)[:5] | |
2406 | modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) |
|
2324 | modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) | |
2407 |
|
2325 | |||
2408 | revert = ([], _('reverting %s\n')) |
|
2326 | revert = ([], _('reverting %s\n')) | |
@@ -2474,8 +2392,7 b' def revert(ui, repo, *pats, **opts):' | |||||
2474 |
|
2392 | |||
2475 | if not opts.get('dry_run'): |
|
2393 | if not opts.get('dry_run'): | |
2476 | repo.dirstate.forget(forget[0]) |
|
2394 | repo.dirstate.forget(forget[0]) | |
2477 |
r = repo |
|
2395 | r = hg.revert(repo, node, update.has_key, wlock) | |
2478 | show_stats=False) |
|
|||
2479 | repo.dirstate.update(add[0], 'a') |
|
2396 | repo.dirstate.update(add[0], 'a') | |
2480 | repo.dirstate.update(undelete[0], 'n') |
|
2397 | repo.dirstate.update(undelete[0], 'n') | |
2481 | repo.dirstate.update(remove[0], 'r') |
|
2398 | repo.dirstate.update(remove[0], 'r') | |
@@ -2593,37 +2510,44 b' def serve(ui, repo, **opts):' | |||||
2593 | def status(ui, repo, *pats, **opts): |
|
2510 | def status(ui, repo, *pats, **opts): | |
2594 | """show changed files in the working directory |
|
2511 | """show changed files in the working directory | |
2595 |
|
2512 | |||
2596 |
Show |
|
2513 | Show status of files in the repository. If names are given, only | |
2597 | given, only files that match are shown. |
|
2514 | files that match are shown. Files that are clean or ignored, are | |
|
2515 | not listed unless -c (clean), -i (ignored) or -A is given. | |||
2598 |
|
2516 | |||
2599 | The codes used to show the status of files are: |
|
2517 | The codes used to show the status of files are: | |
2600 | M = modified |
|
2518 | M = modified | |
2601 | A = added |
|
2519 | A = added | |
2602 | R = removed |
|
2520 | R = removed | |
|
2521 | C = clean | |||
2603 | ! = deleted, but still tracked |
|
2522 | ! = deleted, but still tracked | |
2604 | ? = not tracked |
|
2523 | ? = not tracked | |
2605 | I = ignored (not shown by default) |
|
2524 | I = ignored (not shown by default) | |
2606 | = the previous added file was copied from here |
|
2525 | = the previous added file was copied from here | |
2607 | """ |
|
2526 | """ | |
2608 |
|
2527 | |||
2609 | show_ignored = opts['ignored'] and True or False |
|
2528 | all = opts['all'] | |
2610 | files, matchfn, anypats = matchpats(repo, pats, opts) |
|
2529 | ||
|
2530 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |||
2611 | cwd = (pats and repo.getcwd()) or '' |
|
2531 | cwd = (pats and repo.getcwd()) or '' | |
2612 | modified, added, removed, deleted, unknown, ignored = [ |
|
2532 | modified, added, removed, deleted, unknown, ignored, clean = [ | |
2613 | [util.pathto(cwd, x) for x in n] |
|
2533 | [util.pathto(cwd, x) for x in n] | |
2614 |
for n in repo. |
|
2534 | for n in repo.status(files=files, match=matchfn, | |
2615 |
|
|
2535 | list_ignored=all or opts['ignored'], | |
2616 |
|
2536 | list_clean=all or opts['clean'])] | ||
2617 | changetypes = [('modified', 'M', modified), |
|
2537 | ||
|
2538 | changetypes = (('modified', 'M', modified), | |||
2618 | ('added', 'A', added), |
|
2539 | ('added', 'A', added), | |
2619 | ('removed', 'R', removed), |
|
2540 | ('removed', 'R', removed), | |
2620 | ('deleted', '!', deleted), |
|
2541 | ('deleted', '!', deleted), | |
2621 | ('unknown', '?', unknown), |
|
2542 | ('unknown', '?', unknown), | |
2622 |
('ignored', 'I', ignored) |
|
2543 | ('ignored', 'I', ignored)) | |
|
2544 | ||||
|
2545 | explicit_changetypes = changetypes + (('clean', 'C', clean),) | |||
2623 |
|
2546 | |||
2624 | end = opts['print0'] and '\0' or '\n' |
|
2547 | end = opts['print0'] and '\0' or '\n' | |
2625 |
|
2548 | |||
2626 |
for opt, char, changes in ([ct for ct in changetypes |
|
2549 | for opt, char, changes in ([ct for ct in explicit_changetypes | |
|
2550 | if all or opts[ct[0]]] | |||
2627 | or changetypes): |
|
2551 | or changetypes): | |
2628 | if opts['no_status']: |
|
2552 | if opts['no_status']: | |
2629 | format = "%%s%s" % end |
|
2553 | format = "%%s%s" % end | |
@@ -2632,7 +2556,7 b' def status(ui, repo, *pats, **opts):' | |||||
2632 |
|
2556 | |||
2633 | for f in changes: |
|
2557 | for f in changes: | |
2634 | ui.write(format % f) |
|
2558 | ui.write(format % f) | |
2635 | if (opts.get('copies') and not opts.get('no_status') |
|
2559 | if ((all or opts.get('copies')) and not opts.get('no_status') | |
2636 | and opt == 'added' and repo.dirstate.copies.has_key(f)): |
|
2560 | and opt == 'added' and repo.dirstate.copies.has_key(f)): | |
2637 | ui.write(' %s%s' % (repo.dirstate.copies[f], end)) |
|
2561 | ui.write(' %s%s' % (repo.dirstate.copies[f], end)) | |
2638 |
|
2562 | |||
@@ -2645,7 +2569,7 b' def tag(ui, repo, name, rev_=None, **opt' | |||||
2645 | very useful to compare different revision, to go back to significant |
|
2569 | very useful to compare different revision, to go back to significant | |
2646 | earlier versions or to mark branch points as releases, etc. |
|
2570 | earlier versions or to mark branch points as releases, etc. | |
2647 |
|
2571 | |||
2648 |
If no revision is given, the |
|
2572 | If no revision is given, the parent of the working directory is used. | |
2649 |
|
2573 | |||
2650 | To facilitate version control, distribution, and merging of tags, |
|
2574 | To facilitate version control, distribution, and merging of tags, | |
2651 | they are stored as a file named ".hgtags" which is managed |
|
2575 | they are stored as a file named ".hgtags" which is managed | |
@@ -2653,8 +2577,8 b' def tag(ui, repo, name, rev_=None, **opt' | |||||
2653 | necessary. The file '.hg/localtags' is used for local tags (not |
|
2577 | necessary. The file '.hg/localtags' is used for local tags (not | |
2654 | shared among repositories). |
|
2578 | shared among repositories). | |
2655 | """ |
|
2579 | """ | |
2656 |
if name |
|
2580 | if name in ['tip', '.']: | |
2657 |
raise util.Abort(_("the name ' |
|
2581 | raise util.Abort(_("the name '%s' is reserved") % name) | |
2658 | if rev_ is not None: |
|
2582 | if rev_ is not None: | |
2659 | ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " |
|
2583 | ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " | |
2660 | "please use 'hg tag [-r REV] NAME' instead\n")) |
|
2584 | "please use 'hg tag [-r REV] NAME' instead\n")) | |
@@ -2665,7 +2589,12 b' def tag(ui, repo, name, rev_=None, **opt' | |||||
2665 | if rev_: |
|
2589 | if rev_: | |
2666 | r = hex(repo.lookup(rev_)) |
|
2590 | r = hex(repo.lookup(rev_)) | |
2667 | else: |
|
2591 | else: | |
2668 | r = hex(repo.changelog.tip()) |
|
2592 | p1, p2 = repo.dirstate.parents() | |
|
2593 | if p1 == nullid: | |||
|
2594 | raise util.Abort(_('no revision to tag')) | |||
|
2595 | if p2 != nullid: | |||
|
2596 | raise util.Abort(_('outstanding uncommitted merges')) | |||
|
2597 | r = hex(p1) | |||
2669 |
|
2598 | |||
2670 | repo.tag(name, r, opts['local'], opts['message'], opts['user'], |
|
2599 | repo.tag(name, r, opts['local'], opts['message'], opts['user'], | |
2671 | opts['date']) |
|
2600 | opts['date']) | |
@@ -2701,7 +2630,7 b' def tip(ui, repo, **opts):' | |||||
2701 | br = repo.branchlookup([n]) |
|
2630 | br = repo.branchlookup([n]) | |
2702 | show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) |
|
2631 | show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) | |
2703 | if opts['patch']: |
|
2632 | if opts['patch']: | |
2704 |
|
|
2633 | patch.diff(repo, repo.changelog.parents(n)[0], n) | |
2705 |
|
2634 | |||
2706 | def unbundle(ui, repo, fname, **opts): |
|
2635 | def unbundle(ui, repo, fname, **opts): | |
2707 | """apply a changegroup file |
|
2636 | """apply a changegroup file | |
@@ -2730,7 +2659,8 b' def unbundle(ui, repo, fname, **opts):' | |||||
2730 | raise util.Abort(_("%s: unknown bundle compression type") |
|
2659 | raise util.Abort(_("%s: unknown bundle compression type") | |
2731 | % fname) |
|
2660 | % fname) | |
2732 | gen = generator(util.filechunkiter(f, 4096)) |
|
2661 | gen = generator(util.filechunkiter(f, 4096)) | |
2733 |
modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle' |
|
2662 | modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle', | |
|
2663 | 'bundle:' + fname) | |||
2734 | return postincoming(ui, repo, modheads, opts['update']) |
|
2664 | return postincoming(ui, repo, modheads, opts['update']) | |
2735 |
|
2665 | |||
2736 | def undo(ui, repo): |
|
2666 | def undo(ui, repo): | |
@@ -2745,7 +2675,7 b' def undo(ui, repo):' | |||||
2745 | repo.rollback() |
|
2675 | repo.rollback() | |
2746 |
|
2676 | |||
2747 | def update(ui, repo, node=None, merge=False, clean=False, force=None, |
|
2677 | def update(ui, repo, node=None, merge=False, clean=False, force=None, | |
2748 |
branch=None |
|
2678 | branch=None): | |
2749 | """update or merge working directory |
|
2679 | """update or merge working directory | |
2750 |
|
2680 | |||
2751 | Update the working directory to the specified revision. |
|
2681 | Update the working directory to the specified revision. | |
@@ -2760,13 +2690,17 b' def update(ui, repo, node=None, merge=Fa' | |||||
2760 | By default, update will refuse to run if doing so would require |
|
2690 | By default, update will refuse to run if doing so would require | |
2761 | merging or discarding local changes. |
|
2691 | merging or discarding local changes. | |
2762 | """ |
|
2692 | """ | |
|
2693 | node = _lookup(repo, node, branch) | |||
2763 | if merge: |
|
2694 | if merge: | |
2764 | ui.warn(_('(the -m/--merge option is deprecated; ' |
|
2695 | ui.warn(_('(the -m/--merge option is deprecated; ' | |
2765 | 'use the merge command instead)\n')) |
|
2696 | 'use the merge command instead)\n')) | |
2766 | return doupdate(ui, repo, node, merge, clean, force, branch, **opts) |
|
2697 | return hg.merge(repo, node, force=force) | |
2767 |
|
2698 | elif clean: | ||
2768 | def doupdate(ui, repo, node=None, merge=False, clean=False, force=None, |
|
2699 | return hg.clean(repo, node) | |
2769 | branch=None, **opts): |
|
2700 | else: | |
|
2701 | return hg.update(repo, node) | |||
|
2702 | ||||
|
2703 | def _lookup(repo, node, branch=None): | |||
2770 | if branch: |
|
2704 | if branch: | |
2771 | br = repo.branchlookup(branch=branch) |
|
2705 | br = repo.branchlookup(branch=branch) | |
2772 | found = [] |
|
2706 | found = [] | |
@@ -2774,19 +2708,19 b' def doupdate(ui, repo, node=None, merge=' | |||||
2774 | if branch in br[x]: |
|
2708 | if branch in br[x]: | |
2775 | found.append(x) |
|
2709 | found.append(x) | |
2776 | if len(found) > 1: |
|
2710 | if len(found) > 1: | |
2777 | ui.warn(_("Found multiple heads for %s\n") % branch) |
|
2711 | repo.ui.warn(_("Found multiple heads for %s\n") % branch) | |
2778 | for x in found: |
|
2712 | for x in found: | |
2779 |
show_changeset(ui, repo, |
|
2713 | show_changeset(ui, repo, {}).show(changenode=x, brinfo=br) | |
2780 |
re |
|
2714 | raise util.Abort("") | |
2781 | if len(found) == 1: |
|
2715 | if len(found) == 1: | |
2782 | node = found[0] |
|
2716 | node = found[0] | |
2783 |
ui.warn(_("Using head %s for branch %s\n") |
|
2717 | repo.ui.warn(_("Using head %s for branch %s\n") | |
|
2718 | % (short(node), branch)) | |||
2784 | else: |
|
2719 | else: | |
2785 |
ui. |
|
2720 | raise util.Abort(_("branch %s not found\n") % (branch)) | |
2786 | return 1 |
|
|||
2787 | else: |
|
2721 | else: | |
2788 | node = node and repo.lookup(node) or repo.changelog.tip() |
|
2722 | node = node and repo.lookup(node) or repo.changelog.tip() | |
2789 | return repo.update(node, allow=merge, force=clean, forcemerge=force) |
|
2723 | return node | |
2790 |
|
2724 | |||
2791 | def verify(ui, repo): |
|
2725 | def verify(ui, repo): | |
2792 | """verify the integrity of the repository |
|
2726 | """verify the integrity of the repository | |
@@ -2798,7 +2732,7 b' def verify(ui, repo):' | |||||
2798 | the changelog, manifest, and tracked files, as well as the |
|
2732 | the changelog, manifest, and tracked files, as well as the | |
2799 | integrity of their crosslinks and indices. |
|
2733 | integrity of their crosslinks and indices. | |
2800 | """ |
|
2734 | """ | |
2801 |
return |
|
2735 | return hg.verify(repo) | |
2802 |
|
2736 | |||
2803 | # Command options and aliases are listed here, alphabetically |
|
2737 | # Command options and aliases are listed here, alphabetically | |
2804 |
|
2738 | |||
@@ -2919,6 +2853,7 b' table = {' | |||||
2919 | ('a', 'text', None, _('treat all files as text')), |
|
2853 | ('a', 'text', None, _('treat all files as text')), | |
2920 | ('p', 'show-function', None, |
|
2854 | ('p', 'show-function', None, | |
2921 | _('show which function each change is in')), |
|
2855 | _('show which function each change is in')), | |
|
2856 | ('g', 'git', None, _('use git extended diff format')), | |||
2922 | ('w', 'ignore-all-space', None, |
|
2857 | ('w', 'ignore-all-space', None, | |
2923 | _('ignore white space when comparing lines')), |
|
2858 | _('ignore white space when comparing lines')), | |
2924 | ('b', 'ignore-space-change', None, |
|
2859 | ('b', 'ignore-space-change', None, | |
@@ -2943,6 +2878,8 b' table = {' | |||||
2943 | (grep, |
|
2878 | (grep, | |
2944 | [('0', 'print0', None, _('end fields with NUL')), |
|
2879 | [('0', 'print0', None, _('end fields with NUL')), | |
2945 | ('', 'all', None, _('print all revisions that match')), |
|
2880 | ('', 'all', None, _('print all revisions that match')), | |
|
2881 | ('f', 'follow', None, | |||
|
2882 | _('follow changeset history, or file history across copies and renames')), | |||
2946 | ('i', 'ignore-case', None, _('ignore case when matching')), |
|
2883 | ('i', 'ignore-case', None, _('ignore case when matching')), | |
2947 | ('l', 'files-with-matches', None, |
|
2884 | ('l', 'files-with-matches', None, | |
2948 | _('print only filenames and revs that match')), |
|
2885 | _('print only filenames and revs that match')), | |
@@ -2979,7 +2916,7 b' table = {' | |||||
2979 | ('n', 'newest-first', None, _('show newest record first')), |
|
2916 | ('n', 'newest-first', None, _('show newest record first')), | |
2980 | ('', 'bundle', '', _('file to store the bundles into')), |
|
2917 | ('', 'bundle', '', _('file to store the bundles into')), | |
2981 | ('p', 'patch', None, _('show patch')), |
|
2918 | ('p', 'patch', None, _('show patch')), | |
2982 | ('r', 'rev', [], _('a specific revision you would like to pull')), |
|
2919 | ('r', 'rev', [], _('a specific revision up to which you would like to pull')), | |
2983 | ('', 'template', '', _('display with template')), |
|
2920 | ('', 'template', '', _('display with template')), | |
2984 | ('e', 'ssh', '', _('specify ssh command to use')), |
|
2921 | ('e', 'ssh', '', _('specify ssh command to use')), | |
2985 | ('', 'remotecmd', '', |
|
2922 | ('', 'remotecmd', '', | |
@@ -3005,6 +2942,10 b' table = {' | |||||
3005 | "^log|history": |
|
2942 | "^log|history": | |
3006 | (log, |
|
2943 | (log, | |
3007 | [('b', 'branches', None, _('show branches')), |
|
2944 | [('b', 'branches', None, _('show branches')), | |
|
2945 | ('f', 'follow', None, | |||
|
2946 | _('follow changeset history, or file history across copies and renames')), | |||
|
2947 | ('', 'follow-first', None, | |||
|
2948 | _('only follow the first parent of merge changesets')), | |||
3008 | ('k', 'keyword', [], _('search for a keyword')), |
|
2949 | ('k', 'keyword', [], _('search for a keyword')), | |
3009 | ('l', 'limit', '', _('limit number of changes displayed')), |
|
2950 | ('l', 'limit', '', _('limit number of changes displayed')), | |
3010 | ('r', 'rev', [], _('show the specified revision or range')), |
|
2951 | ('r', 'rev', [], _('show the specified revision or range')), | |
@@ -3012,6 +2953,7 b' table = {' | |||||
3012 | ('', 'style', '', _('display using template map file')), |
|
2953 | ('', 'style', '', _('display using template map file')), | |
3013 | ('m', 'only-merges', None, _('show only merges')), |
|
2954 | ('m', 'only-merges', None, _('show only merges')), | |
3014 | ('p', 'patch', None, _('show patch')), |
|
2955 | ('p', 'patch', None, _('show patch')), | |
|
2956 | ('P', 'prune', [], _('do not display revision or any of its ancestors')), | |||
3015 | ('', 'template', '', _('display with template')), |
|
2957 | ('', 'template', '', _('display with template')), | |
3016 | ('I', 'include', [], _('include names matching the given patterns')), |
|
2958 | ('I', 'include', [], _('include names matching the given patterns')), | |
3017 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
|
2959 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |
@@ -3038,9 +2980,10 b' table = {' | |||||
3038 | "^parents": |
|
2980 | "^parents": | |
3039 | (parents, |
|
2981 | (parents, | |
3040 | [('b', 'branches', None, _('show branches')), |
|
2982 | [('b', 'branches', None, _('show branches')), | |
|
2983 | ('r', 'rev', '', _('show parents from the specified rev')), | |||
3041 | ('', 'style', '', _('display using template map file')), |
|
2984 | ('', 'style', '', _('display using template map file')), | |
3042 | ('', 'template', '', _('display with template'))], |
|
2985 | ('', 'template', '', _('display with template'))], | |
3043 | _('hg parents [-b] [REV]')), |
|
2986 | _('hg parents [-b] [-r REV] [FILE]')), | |
3044 | "paths": (paths, [], _('hg paths [NAME]')), |
|
2987 | "paths": (paths, [], _('hg paths [NAME]')), | |
3045 | "^pull": |
|
2988 | "^pull": | |
3046 | (pull, |
|
2989 | (pull, | |
@@ -3049,7 +2992,7 b' table = {' | |||||
3049 | ('e', 'ssh', '', _('specify ssh command to use')), |
|
2992 | ('e', 'ssh', '', _('specify ssh command to use')), | |
3050 | ('f', 'force', None, |
|
2993 | ('f', 'force', None, | |
3051 | _('run even when remote repository is unrelated')), |
|
2994 | _('run even when remote repository is unrelated')), | |
3052 | ('r', 'rev', [], _('a specific revision you would like to pull')), |
|
2995 | ('r', 'rev', [], _('a specific revision up to which you would like to pull')), | |
3053 | ('', 'remotecmd', '', |
|
2996 | ('', 'remotecmd', '', | |
3054 | _('specify hg command to run on the remote side'))], |
|
2997 | _('specify hg command to run on the remote side'))], | |
3055 | _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), |
|
2998 | _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), | |
@@ -3117,10 +3060,12 b' table = {' | |||||
3117 | _('hg serve [OPTION]...')), |
|
3060 | _('hg serve [OPTION]...')), | |
3118 | "^status|st": |
|
3061 | "^status|st": | |
3119 | (status, |
|
3062 | (status, | |
3120 |
[(' |
|
3063 | [('A', 'all', None, _('show status of all files')), | |
|
3064 | ('m', 'modified', None, _('show only modified files')), | |||
3121 | ('a', 'added', None, _('show only added files')), |
|
3065 | ('a', 'added', None, _('show only added files')), | |
3122 | ('r', 'removed', None, _('show only removed files')), |
|
3066 | ('r', 'removed', None, _('show only removed files')), | |
3123 | ('d', 'deleted', None, _('show only deleted (but tracked) files')), |
|
3067 | ('d', 'deleted', None, _('show only deleted (but tracked) files')), | |
|
3068 | ('c', 'clean', None, _('show only files without changes')), | |||
3124 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), |
|
3069 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), | |
3125 | ('i', 'ignored', None, _('show ignored files')), |
|
3070 | ('i', 'ignored', None, _('show ignored files')), | |
3126 | ('n', 'no-status', None, _('hide status prefix')), |
|
3071 | ('n', 'no-status', None, _('hide status prefix')), | |
@@ -3286,24 +3231,16 b' def findext(name):' | |||||
3286 | try: |
|
3231 | try: | |
3287 | return sys.modules[external[name]] |
|
3232 | return sys.modules[external[name]] | |
3288 | except KeyError: |
|
3233 | except KeyError: | |
3289 | dotname = '.' + name |
|
|||
3290 | for k, v in external.iteritems(): |
|
3234 | for k, v in external.iteritems(): | |
3291 | if k.endswith('.' + name) or v == name: |
|
3235 | if k.endswith('.' + name) or k.endswith('/' + name) or v == name: | |
3292 | return sys.modules[v] |
|
3236 | return sys.modules[v] | |
3293 | raise KeyError(name) |
|
3237 | raise KeyError(name) | |
3294 |
|
3238 | |||
3295 | def dispatch(args): |
|
3239 | def load_extensions(ui): | |
3296 | for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': |
|
3240 | added = [] | |
3297 | num = getattr(signal, name, None) |
|
3241 | for ext_name, load_from_name in ui.extensions(): | |
3298 | if num: signal.signal(num, catchterm) |
|
3242 | if ext_name in external: | |
3299 |
|
3243 | continue | ||
3300 | try: |
|
|||
3301 | u = ui.ui(traceback='--traceback' in sys.argv[1:]) |
|
|||
3302 | except util.Abort, inst: |
|
|||
3303 | sys.stderr.write(_("abort: %s\n") % inst) |
|
|||
3304 | return -1 |
|
|||
3305 |
|
||||
3306 | for ext_name, load_from_name in u.extensions(): |
|
|||
3307 | try: |
|
3244 | try: | |
3308 | if load_from_name: |
|
3245 | if load_from_name: | |
3309 | # the module will be loaded in sys.modules |
|
3246 | # the module will be loaded in sys.modules | |
@@ -3323,23 +3260,36 b' def dispatch(args):' | |||||
3323 | except ImportError: |
|
3260 | except ImportError: | |
3324 | mod = importh(ext_name) |
|
3261 | mod = importh(ext_name) | |
3325 | external[ext_name] = mod.__name__ |
|
3262 | external[ext_name] = mod.__name__ | |
|
3263 | added.append((mod, ext_name)) | |||
3326 | except (util.SignalInterrupt, KeyboardInterrupt): |
|
3264 | except (util.SignalInterrupt, KeyboardInterrupt): | |
3327 | raise |
|
3265 | raise | |
3328 | except Exception, inst: |
|
3266 | except Exception, inst: | |
3329 |
u.warn(_("*** failed to import extension %s: %s\n") % |
|
3267 | ui.warn(_("*** failed to import extension %s: %s\n") % | |
3330 | if u.print_exc(): |
|
3268 | (ext_name, inst)) | |
|
3269 | if ui.print_exc(): | |||
3331 | return 1 |
|
3270 | return 1 | |
3332 |
|
3271 | |||
3333 | for name in external.itervalues(): |
|
3272 | for mod, name in added: | |
3334 | mod = sys.modules[name] |
|
|||
3335 | uisetup = getattr(mod, 'uisetup', None) |
|
3273 | uisetup = getattr(mod, 'uisetup', None) | |
3336 | if uisetup: |
|
3274 | if uisetup: | |
3337 | uisetup(u) |
|
3275 | uisetup(ui) | |
3338 | cmdtable = getattr(mod, 'cmdtable', {}) |
|
3276 | cmdtable = getattr(mod, 'cmdtable', {}) | |
3339 | for t in cmdtable: |
|
3277 | for t in cmdtable: | |
3340 | if t in table: |
|
3278 | if t in table: | |
3341 | u.warn(_("module %s overrides %s\n") % (name, t)) |
|
3279 | ui.warn(_("module %s overrides %s\n") % (name, t)) | |
3342 | table.update(cmdtable) |
|
3280 | table.update(cmdtable) | |
|
3281 | ||||
|
3282 | def dispatch(args): | |||
|
3283 | for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |||
|
3284 | num = getattr(signal, name, None) | |||
|
3285 | if num: signal.signal(num, catchterm) | |||
|
3286 | ||||
|
3287 | try: | |||
|
3288 | u = ui.ui(traceback='--traceback' in sys.argv[1:], | |||
|
3289 | readhooks=[load_extensions]) | |||
|
3290 | except util.Abort, inst: | |||
|
3291 | sys.stderr.write(_("abort: %s\n") % inst) | |||
|
3292 | return -1 | |||
3343 |
|
3293 | |||
3344 | try: |
|
3294 | try: | |
3345 | cmd, func, args, options, cmdoptions = parse(u, args) |
|
3295 | cmd, func, args, options, cmdoptions = parse(u, args) | |
@@ -3391,6 +3341,7 b' def dispatch(args):' | |||||
3391 | mod = sys.modules[name] |
|
3341 | mod = sys.modules[name] | |
3392 | if hasattr(mod, 'reposetup'): |
|
3342 | if hasattr(mod, 'reposetup'): | |
3393 | mod.reposetup(u, repo) |
|
3343 | mod.reposetup(u, repo) | |
|
3344 | hg.repo_setup_hooks.append(mod.reposetup) | |||
3394 | except hg.RepoError: |
|
3345 | except hg.RepoError: | |
3395 | if cmd not in optionalrepo.split(): |
|
3346 | if cmd not in optionalrepo.split(): | |
3396 | raise |
|
3347 | raise | |
@@ -3398,6 +3349,11 b' def dispatch(args):' | |||||
3398 | else: |
|
3349 | else: | |
3399 | d = lambda: func(u, *args, **cmdoptions) |
|
3350 | d = lambda: func(u, *args, **cmdoptions) | |
3400 |
|
3351 | |||
|
3352 | # reupdate the options, repo/.hg/hgrc may have changed them | |||
|
3353 | u.updateopts(options["verbose"], options["debug"], options["quiet"], | |||
|
3354 | not options["noninteractive"], options["traceback"], | |||
|
3355 | options["config"]) | |||
|
3356 | ||||
3401 | try: |
|
3357 | try: | |
3402 | if options['profile']: |
|
3358 | if options['profile']: | |
3403 | import hotshot, hotshot.stats |
|
3359 | import hotshot, hotshot.stats |
@@ -1,6 +1,6 b'' | |||||
1 | # context.py - changeset and file context objects for mercurial |
|
1 | # context.py - changeset and file context objects for mercurial | |
2 | # |
|
2 | # | |
3 |
# Copyright 200 |
|
3 | # Copyright 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -11,9 +11,8 b' class changectx(object):' | |||||
11 | def __init__(self, repo, changeid): |
|
11 | def __init__(self, repo, changeid): | |
12 | """changeid is a revision number, node, or tag""" |
|
12 | """changeid is a revision number, node, or tag""" | |
13 | self._repo = repo |
|
13 | self._repo = repo | |
14 | self._id = changeid |
|
|||
15 |
|
14 | |||
16 |
self._node = self._repo.lookup( |
|
15 | self._node = self._repo.lookup(changeid) | |
17 | self._rev = self._repo.changelog.rev(self._node) |
|
16 | self._rev = self._repo.changelog.rev(self._node) | |
18 |
|
17 | |||
19 | def changeset(self): |
|
18 | def changeset(self): | |
@@ -74,39 +73,40 b' class filectx(object):' | |||||
74 | fileid can be a file revision or node.""" |
|
73 | fileid can be a file revision or node.""" | |
75 | self._repo = repo |
|
74 | self._repo = repo | |
76 | self._path = path |
|
75 | self._path = path | |
77 | self._id = changeid |
|
|||
78 | self._fileid = fileid |
|
|||
79 |
|
76 | |||
80 | if self._id: |
|
77 | assert changeid or fileid | |
|
78 | ||||
|
79 | if not fileid: | |||
81 | # if given a changeset id, go ahead and look up the file |
|
80 | # if given a changeset id, go ahead and look up the file | |
82 |
self._change |
|
81 | self._changeid = changeid | |
83 | node, flag = self._repo.manifest.find(self._changeset[0], path) |
|
82 | self._changectx = self.changectx() | |
84 | self._filelog = self._repo.file(self._path) |
|
83 | self._filelog = self._repo.file(self._path) | |
85 | self._filenode = node |
|
84 | self._filenode = self._changectx.filenode(self._path) | |
86 |
el |
|
85 | else: | |
87 | # else be lazy |
|
86 | # else be lazy | |
88 | self._filelog = self._repo.file(self._path) |
|
87 | self._filelog = self._repo.file(self._path) | |
89 |
self._filenode = self._filelog.lookup( |
|
88 | self._filenode = self._filelog.lookup(fileid) | |
|
89 | self._changeid = self._filelog.linkrev(self._filenode) | |||
90 | self._filerev = self._filelog.rev(self._filenode) |
|
90 | self._filerev = self._filelog.rev(self._filenode) | |
91 |
|
91 | |||
92 |
def change |
|
92 | def changectx(self): | |
93 | try: |
|
93 | try: | |
94 |
return self._change |
|
94 | return self._changectx | |
95 | except AttributeError: |
|
95 | except AttributeError: | |
96 |
self._change |
|
96 | self._changectx = changectx(self._repo, self._changeid) | |
97 |
return self._change |
|
97 | return self._changectx | |
98 |
|
98 | |||
99 | def filerev(self): return self._filerev |
|
99 | def filerev(self): return self._filerev | |
100 | def filenode(self): return self._filenode |
|
100 | def filenode(self): return self._filenode | |
101 | def filelog(self): return self._filelog |
|
101 | def filelog(self): return self._filelog | |
102 |
|
102 | |||
103 |
def rev(self): return self.change |
|
103 | def rev(self): return self.changectx().rev() | |
104 |
def node(self): return self.change |
|
104 | def node(self): return self.changectx().node() | |
105 |
def user(self): return self.change |
|
105 | def user(self): return self.changectx().user() | |
106 |
def date(self): return self.change |
|
106 | def date(self): return self.changectx().date() | |
107 |
def files(self): return self.change |
|
107 | def files(self): return self.changectx().files() | |
108 |
def description(self): return self.change |
|
108 | def description(self): return self.changectx().description() | |
109 |
def manifest(self): return self.change |
|
109 | def manifest(self): return self.changectx().manifest() | |
110 |
|
110 | |||
111 | def data(self): return self._filelog.read(self._filenode) |
|
111 | def data(self): return self._filelog.read(self._filenode) | |
112 | def metadata(self): return self._filelog.readmeta(self._filenode) |
|
112 | def metadata(self): return self._filelog.readmeta(self._filenode) |
@@ -96,6 +96,7 b' def demandload(scope, modules):' | |||||
96 |
|
96 | |||
97 | foo import foo |
|
97 | foo import foo | |
98 | foo bar import foo, bar |
|
98 | foo bar import foo, bar | |
|
99 | foo@bar import foo as bar | |||
99 | foo.bar import foo.bar |
|
100 | foo.bar import foo.bar | |
100 | foo:bar from foo import bar |
|
101 | foo:bar from foo import bar | |
101 | foo:bar,quux from foo import bar, quux |
|
102 | foo:bar,quux from foo import bar, quux | |
@@ -108,6 +109,9 b' def demandload(scope, modules):' | |||||
108 | mod = mod[:col] |
|
109 | mod = mod[:col] | |
109 | else: |
|
110 | else: | |
110 | fromlist = [] |
|
111 | fromlist = [] | |
|
112 | as = None | |||
|
113 | if '@' in mod: | |||
|
114 | mod, as = mod.split("@") | |||
111 | importer = _importer(scope, mod, fromlist) |
|
115 | importer = _importer(scope, mod, fromlist) | |
112 | if fromlist: |
|
116 | if fromlist: | |
113 | for name in fromlist: |
|
117 | for name in fromlist: | |
@@ -126,4 +130,6 b' def demandload(scope, modules):' | |||||
126 | continue |
|
130 | continue | |
127 | else: |
|
131 | else: | |
128 | basemod = mod |
|
132 | basemod = mod | |
129 | scope[basemod] = _replacer(importer, basemod) |
|
133 | if not as: | |
|
134 | as = basemod | |||
|
135 | scope[as] = _replacer(importer, as) |
@@ -1,7 +1,7 b'' | |||||
1 | """ |
|
1 | """ | |
2 | dirstate.py - working directory tracking for mercurial |
|
2 | dirstate.py - working directory tracking for mercurial | |
3 |
|
3 | |||
4 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 |
|
5 | |||
6 | This software may be used and distributed according to the terms |
|
6 | This software may be used and distributed according to the terms | |
7 | of the GNU General Public License, incorporated herein by reference. |
|
7 | of the GNU General Public License, incorporated herein by reference. | |
@@ -10,7 +10,7 b' of the GNU General Public License, incor' | |||||
10 | from node import * |
|
10 | from node import * | |
11 | from i18n import gettext as _ |
|
11 | from i18n import gettext as _ | |
12 | from demandload import * |
|
12 | from demandload import * | |
13 | demandload(globals(), "struct os time bisect stat util re errno") |
|
13 | demandload(globals(), "struct os time bisect stat strutil util re errno") | |
14 |
|
14 | |||
15 | class dirstate(object): |
|
15 | class dirstate(object): | |
16 | format = ">cllll" |
|
16 | format = ">cllll" | |
@@ -22,6 +22,7 b' class dirstate(object):' | |||||
22 | self.ui = ui |
|
22 | self.ui = ui | |
23 | self.map = None |
|
23 | self.map = None | |
24 | self.pl = None |
|
24 | self.pl = None | |
|
25 | self.dirs = None | |||
25 | self.copies = {} |
|
26 | self.copies = {} | |
26 | self.ignorefunc = None |
|
27 | self.ignorefunc = None | |
27 | self.blockignore = False |
|
28 | self.blockignore = False | |
@@ -197,6 +198,38 b' class dirstate(object):' | |||||
197 | def copied(self, file): |
|
198 | def copied(self, file): | |
198 | return self.copies.get(file, None) |
|
199 | return self.copies.get(file, None) | |
199 |
|
200 | |||
|
201 | def initdirs(self): | |||
|
202 | if self.dirs is None: | |||
|
203 | self.dirs = {} | |||
|
204 | for f in self.map: | |||
|
205 | self.updatedirs(f, 1) | |||
|
206 | ||||
|
207 | def updatedirs(self, path, delta): | |||
|
208 | if self.dirs is not None: | |||
|
209 | for c in strutil.findall(path, '/'): | |||
|
210 | pc = path[:c] | |||
|
211 | self.dirs.setdefault(pc, 0) | |||
|
212 | self.dirs[pc] += delta | |||
|
213 | ||||
|
214 | def checkshadows(self, files): | |||
|
215 | def prefixes(f): | |||
|
216 | for c in strutil.rfindall(f, '/'): | |||
|
217 | yield f[:c] | |||
|
218 | self.lazyread() | |||
|
219 | self.initdirs() | |||
|
220 | seendirs = {} | |||
|
221 | for f in files: | |||
|
222 | if self.dirs.get(f): | |||
|
223 | raise util.Abort(_('directory named %r already in dirstate') % | |||
|
224 | f) | |||
|
225 | for d in prefixes(f): | |||
|
226 | if d in seendirs: | |||
|
227 | break | |||
|
228 | if d in self.map: | |||
|
229 | raise util.Abort(_('file named %r already in dirstate') % | |||
|
230 | d) | |||
|
231 | seendirs[d] = True | |||
|
232 | ||||
200 | def update(self, files, state, **kw): |
|
233 | def update(self, files, state, **kw): | |
201 | ''' current states: |
|
234 | ''' current states: | |
202 | n normal |
|
235 | n normal | |
@@ -207,10 +240,16 b' class dirstate(object):' | |||||
207 | if not files: return |
|
240 | if not files: return | |
208 | self.lazyread() |
|
241 | self.lazyread() | |
209 | self.markdirty() |
|
242 | self.markdirty() | |
|
243 | if state == "a": | |||
|
244 | self.initdirs() | |||
|
245 | self.checkshadows(files) | |||
210 | for f in files: |
|
246 | for f in files: | |
211 | if state == "r": |
|
247 | if state == "r": | |
212 | self.map[f] = ('r', 0, 0, 0) |
|
248 | self.map[f] = ('r', 0, 0, 0) | |
|
249 | self.updatedirs(f, -1) | |||
213 | else: |
|
250 | else: | |
|
251 | if state == "a": | |||
|
252 | self.updatedirs(f, 1) | |||
214 | s = os.lstat(self.wjoin(f)) |
|
253 | s = os.lstat(self.wjoin(f)) | |
215 | st_size = kw.get('st_size', s.st_size) |
|
254 | st_size = kw.get('st_size', s.st_size) | |
216 | st_mtime = kw.get('st_mtime', s.st_mtime) |
|
255 | st_mtime = kw.get('st_mtime', s.st_mtime) | |
@@ -222,9 +261,11 b' class dirstate(object):' | |||||
222 | if not files: return |
|
261 | if not files: return | |
223 | self.lazyread() |
|
262 | self.lazyread() | |
224 | self.markdirty() |
|
263 | self.markdirty() | |
|
264 | self.initdirs() | |||
225 | for f in files: |
|
265 | for f in files: | |
226 | try: |
|
266 | try: | |
227 | del self.map[f] |
|
267 | del self.map[f] | |
|
268 | self.updatedirs(f, -1) | |||
228 | except KeyError: |
|
269 | except KeyError: | |
229 | self.ui.warn(_("not in dirstate: %s!\n") % f) |
|
270 | self.ui.warn(_("not in dirstate: %s!\n") % f) | |
230 | pass |
|
271 | pass | |
@@ -232,14 +273,15 b' class dirstate(object):' | |||||
232 | def clear(self): |
|
273 | def clear(self): | |
233 | self.map = {} |
|
274 | self.map = {} | |
234 | self.copies = {} |
|
275 | self.copies = {} | |
|
276 | self.dirs = None | |||
235 | self.markdirty() |
|
277 | self.markdirty() | |
236 |
|
278 | |||
237 | def rebuild(self, parent, files): |
|
279 | def rebuild(self, parent, files): | |
238 | self.clear() |
|
280 | self.clear() | |
239 | umask = os.umask(0) |
|
281 | umask = os.umask(0) | |
240 | os.umask(umask) |
|
282 | os.umask(umask) | |
241 |
for f |
|
283 | for f in files: | |
242 |
if |
|
284 | if files.execf(f): | |
243 | self.map[f] = ('n', ~umask, -1, 0) |
|
285 | self.map[f] = ('n', ~umask, -1, 0) | |
244 | else: |
|
286 | else: | |
245 | self.map[f] = ('n', ~umask & 0666, -1, 0) |
|
287 | self.map[f] = ('n', ~umask & 0666, -1, 0) | |
@@ -344,6 +386,10 b' class dirstate(object):' | |||||
344 | # directly by this function, but might be modified by your statmatch call. |
|
386 | # directly by this function, but might be modified by your statmatch call. | |
345 | # |
|
387 | # | |
346 | def walkhelper(self, files, statmatch, dc, badmatch=None): |
|
388 | def walkhelper(self, files, statmatch, dc, badmatch=None): | |
|
389 | # self.root may end with a path separator when self.root == '/' | |||
|
390 | common_prefix_len = len(self.root) | |||
|
391 | if not self.root.endswith('/'): | |||
|
392 | common_prefix_len += 1 | |||
347 | # recursion free walker, faster than os.walk. |
|
393 | # recursion free walker, faster than os.walk. | |
348 | def findfiles(s): |
|
394 | def findfiles(s): | |
349 | work = [s] |
|
395 | work = [s] | |
@@ -352,7 +398,7 b' class dirstate(object):' | |||||
352 | names = os.listdir(top) |
|
398 | names = os.listdir(top) | |
353 | names.sort() |
|
399 | names.sort() | |
354 | # nd is the top of the repository dir tree |
|
400 | # nd is the top of the repository dir tree | |
355 |
nd = util.normpath(top[len |
|
401 | nd = util.normpath(top[common_prefix_len:]) | |
356 | if nd == '.': |
|
402 | if nd == '.': | |
357 | nd = '' |
|
403 | nd = '' | |
358 | else: |
|
404 | else: | |
@@ -434,15 +480,16 b' class dirstate(object):' | |||||
434 | if not seen(k) and (statmatch(k, None)): |
|
480 | if not seen(k) and (statmatch(k, None)): | |
435 | yield 'm', k, None |
|
481 | yield 'm', k, None | |
436 |
|
482 | |||
437 |
def |
|
483 | def status(self, files=None, match=util.always, list_ignored=False, | |
|
484 | list_clean=False): | |||
438 | lookup, modified, added, unknown, ignored = [], [], [], [], [] |
|
485 | lookup, modified, added, unknown, ignored = [], [], [], [], [] | |
439 | removed, deleted = [], [] |
|
486 | removed, deleted, clean = [], [], [] | |
440 |
|
487 | |||
441 |
for src, fn, st in self.statwalk(files, match, ignored= |
|
488 | for src, fn, st in self.statwalk(files, match, ignored=list_ignored): | |
442 | try: |
|
489 | try: | |
443 | type_, mode, size, time = self[fn] |
|
490 | type_, mode, size, time = self[fn] | |
444 | except KeyError: |
|
491 | except KeyError: | |
445 |
if |
|
492 | if list_ignored and self.ignore(fn): | |
446 | ignored.append(fn) |
|
493 | ignored.append(fn) | |
447 | else: |
|
494 | else: | |
448 | unknown.append(fn) |
|
495 | unknown.append(fn) | |
@@ -473,6 +520,8 b' class dirstate(object):' | |||||
473 | modified.append(fn) |
|
520 | modified.append(fn) | |
474 | elif time != st.st_mtime: |
|
521 | elif time != st.st_mtime: | |
475 | lookup.append(fn) |
|
522 | lookup.append(fn) | |
|
523 | elif list_clean: | |||
|
524 | clean.append(fn) | |||
476 | elif type_ == 'm': |
|
525 | elif type_ == 'm': | |
477 | modified.append(fn) |
|
526 | modified.append(fn) | |
478 | elif type_ == 'a': |
|
527 | elif type_ == 'a': | |
@@ -480,4 +529,5 b' class dirstate(object):' | |||||
480 | elif type_ == 'r': |
|
529 | elif type_ == 'r': | |
481 | removed.append(fn) |
|
530 | removed.append(fn) | |
482 |
|
531 | |||
483 |
return (lookup, modified, added, removed, deleted, unknown, ignored |
|
532 | return (lookup, modified, added, removed, deleted, unknown, ignored, | |
|
533 | clean) |
@@ -1,6 +1,6 b'' | |||||
1 | # filelog.py - file history class for mercurial |
|
1 | # filelog.py - file history class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -65,6 +65,26 b' class filelog(revlog):' | |||||
65 | return (m["copy"], bin(m["copyrev"])) |
|
65 | return (m["copy"], bin(m["copyrev"])) | |
66 | return False |
|
66 | return False | |
67 |
|
67 | |||
|
68 | def size(self, rev): | |||
|
69 | """return the size of a given revision""" | |||
|
70 | ||||
|
71 | # for revisions with renames, we have to go the slow way | |||
|
72 | node = self.node(rev) | |||
|
73 | if self.renamed(node): | |||
|
74 | return len(self.read(node)) | |||
|
75 | ||||
|
76 | return revlog.size(self, rev) | |||
|
77 | ||||
|
78 | def cmp(self, node, text): | |||
|
79 | """compare text with a given file revision""" | |||
|
80 | ||||
|
81 | # for renames, we have to go the slow way | |||
|
82 | if self.renamed(node): | |||
|
83 | t2 = self.read(node) | |||
|
84 | return t2 != text | |||
|
85 | ||||
|
86 | return revlog.cmp(self, node, text) | |||
|
87 | ||||
68 | def annotate(self, node): |
|
88 | def annotate(self, node): | |
69 |
|
89 | |||
70 | def decorate(text, rev): |
|
90 | def decorate(text, rev): | |
@@ -76,31 +96,59 b' class filelog(revlog):' | |||||
76 | return child |
|
96 | return child | |
77 |
|
97 | |||
78 | # find all ancestors |
|
98 | # find all ancestors | |
79 | needed = {node:1} |
|
99 | needed = {(self, node):1} | |
80 |
|
|
100 | files = [self] | |
|
101 | visit = [(self, node)] | |||
81 | while visit: |
|
102 | while visit: | |
82 | n = visit.pop(0) |
|
103 | f, n = visit.pop(0) | |
83 |
|
|
104 | rn = f.renamed(n) | |
84 |
|
|
105 | if rn: | |
85 |
|
|
106 | f, n = rn | |
86 | visit.append(p) |
|
107 | f = filelog(self.opener, f, self.defversion) | |
|
108 | files.insert(0, f) | |||
|
109 | if (f, n) not in needed: | |||
|
110 | needed[(f, n)] = 1 | |||
|
111 | else: | |||
|
112 | needed[(f, n)] += 1 | |||
|
113 | for p in f.parents(n): | |||
|
114 | if p == nullid: | |||
|
115 | continue | |||
|
116 | if (f, p) not in needed: | |||
|
117 | needed[(f, p)] = 1 | |||
|
118 | visit.append((f, p)) | |||
87 | else: |
|
119 | else: | |
88 | # count how many times we'll use this |
|
120 | # count how many times we'll use this | |
89 | needed[p] += 1 |
|
121 | needed[(f, p)] += 1 | |
90 |
|
122 | |||
91 | # sort by revision which is a topological order |
|
123 | # sort by revision (per file) which is a topological order | |
92 | visit = [ (self.rev(n), n) for n in needed.keys() ] |
|
124 | visit = [] | |
93 | visit.sort() |
|
125 | for f in files: | |
|
126 | fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f] | |||
|
127 | fn.sort() | |||
|
128 | visit.extend(fn) | |||
94 | hist = {} |
|
129 | hist = {} | |
95 |
|
130 | |||
96 |
for |
|
131 | for i in range(len(visit)): | |
97 | curr = decorate(self.read(n), self.linkrev(n)) |
|
132 | r, f, n = visit[i] | |
98 | for p in self.parents(n): |
|
133 | curr = decorate(f.read(n), f.linkrev(n)) | |
|
134 | if r == -1: | |||
|
135 | continue | |||
|
136 | parents = f.parents(n) | |||
|
137 | # follow parents across renames | |||
|
138 | if r < 1 and i > 0: | |||
|
139 | j = i | |||
|
140 | while j > 0 and visit[j][1] == f: | |||
|
141 | j -= 1 | |||
|
142 | parents = (visit[j][2],) | |||
|
143 | f = visit[j][1] | |||
|
144 | else: | |||
|
145 | parents = f.parents(n) | |||
|
146 | for p in parents: | |||
99 | if p != nullid: |
|
147 | if p != nullid: | |
100 | curr = pair(hist[p], curr) |
|
148 | curr = pair(hist[p], curr) | |
101 | # trim the history of unneeded revs |
|
149 | # trim the history of unneeded revs | |
102 | needed[p] -= 1 |
|
150 | needed[(f, p)] -= 1 | |
103 | if not needed[p]: |
|
151 | if not needed[(f, p)]: | |
104 | del hist[p] |
|
152 | del hist[p] | |
105 | hist[n] = curr |
|
153 | hist[n] = curr | |
106 |
|
154 |
@@ -1,6 +1,7 b'' | |||||
1 | # hg.py - repository classes for mercurial |
|
1 | # hg.py - repository classes for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
4 | # |
|
5 | # | |
5 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -10,69 +11,56 b' from repo import *' | |||||
10 | from demandload import * |
|
11 | from demandload import * | |
11 | from i18n import gettext as _ |
|
12 | from i18n import gettext as _ | |
12 | demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") |
|
13 | demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") | |
13 | demandload(globals(), "errno lock os shutil util") |
|
14 | demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify") | |
14 |
|
||||
15 | def bundle(ui, path): |
|
|||
16 | if path.startswith('bundle://'): |
|
|||
17 | path = path[9:] |
|
|||
18 | else: |
|
|||
19 | path = path[7:] |
|
|||
20 | s = path.split("+", 1) |
|
|||
21 | if len(s) == 1: |
|
|||
22 | repopath, bundlename = "", s[0] |
|
|||
23 | else: |
|
|||
24 | repopath, bundlename = s |
|
|||
25 | return bundlerepo.bundlerepository(ui, repopath, bundlename) |
|
|||
26 |
|
||||
27 | def hg(ui, path): |
|
|||
28 | ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n")) |
|
|||
29 | return httprepo.httprepository(ui, path.replace("hg://", "http://")) |
|
|||
30 |
|
15 | |||
31 |
def local |
|
16 | def _local(path): | |
32 | if path.startswith('file:'): |
|
17 | return (os.path.isfile(path and util.drop_scheme('file', path)) and | |
33 | path = path[5:] |
|
18 | bundlerepo or localrepo) | |
34 | return localrepo.localrepository(ui, path, create) |
|
|||
35 |
|
||||
36 | def ssh_(ui, path, create=0): |
|
|||
37 | return sshrepo.sshrepository(ui, path, create) |
|
|||
38 |
|
||||
39 | def old_http(ui, path): |
|
|||
40 | ui.warn(_("old-http:// syntax is deprecated, " |
|
|||
41 | "please use static-http:// instead\n")) |
|
|||
42 | return statichttprepo.statichttprepository( |
|
|||
43 | ui, path.replace("old-http://", "http://")) |
|
|||
44 |
|
||||
45 | def static_http(ui, path): |
|
|||
46 | return statichttprepo.statichttprepository( |
|
|||
47 | ui, path.replace("static-http://", "http://")) |
|
|||
48 |
|
19 | |||
49 | schemes = { |
|
20 | schemes = { | |
50 | 'bundle': bundle, |
|
21 | 'bundle': bundlerepo, | |
51 |
'file': local |
|
22 | 'file': _local, | |
52 |
'hg': h |
|
23 | 'hg': httprepo, | |
53 | 'http': lambda ui, path: httprepo.httprepository(ui, path), |
|
24 | 'http': httprepo, | |
54 | 'https': lambda ui, path: httprepo.httpsrepository(ui, path), |
|
25 | 'https': httprepo, | |
55 |
'old-http': |
|
26 | 'old-http': statichttprepo, | |
56 |
'ssh': ssh |
|
27 | 'ssh': sshrepo, | |
57 |
'static-http': static |
|
28 | 'static-http': statichttprepo, | |
58 | } |
|
29 | } | |
59 |
|
30 | |||
60 | def repository(ui, path=None, create=0): |
|
31 | def _lookup(path): | |
61 |
scheme = |
|
32 | scheme = 'file' | |
62 | if path: |
|
33 | if path: | |
63 | c = path.find(':') |
|
34 | c = path.find(':') | |
64 | if c > 0: |
|
35 | if c > 0: | |
65 |
scheme = |
|
36 | scheme = path[:c] | |
66 | else: |
|
37 | thing = schemes.get(scheme) or schemes['file'] | |
67 | path = '' |
|
38 | try: | |
68 | ctor = scheme or schemes['file'] |
|
39 | return thing(path) | |
69 | if create: |
|
40 | except TypeError: | |
|
41 | return thing | |||
|
42 | ||||
|
43 | def islocal(repo): | |||
|
44 | '''return true if repo or path is local''' | |||
|
45 | if isinstance(repo, str): | |||
70 | try: |
|
46 | try: | |
71 | return ctor(ui, path, create) |
|
47 | return _lookup(repo).islocal(repo) | |
72 |
except |
|
48 | except AttributeError: | |
73 | raise util.Abort(_('cannot create new repository over "%s" protocol') % |
|
49 | return False | |
74 | scheme) |
|
50 | return repo.local() | |
75 | return ctor(ui, path) |
|
51 | ||
|
52 | repo_setup_hooks = [] | |||
|
53 | ||||
|
54 | def repository(ui, path=None, create=False): | |||
|
55 | """return a repository object for the specified path""" | |||
|
56 | repo = _lookup(path).instance(ui, path, create) | |||
|
57 | for hook in repo_setup_hooks: | |||
|
58 | hook(ui, repo) | |||
|
59 | return repo | |||
|
60 | ||||
|
61 | def defaultdest(source): | |||
|
62 | '''return default destination of clone if none is given''' | |||
|
63 | return os.path.basename(os.path.normpath(source)) | |||
76 |
|
64 | |||
77 | def clone(ui, source, dest=None, pull=False, rev=None, update=True, |
|
65 | def clone(ui, source, dest=None, pull=False, rev=None, update=True, | |
78 | stream=False): |
|
66 | stream=False): | |
@@ -90,7 +78,9 b' def clone(ui, source, dest=None, pull=Fa' | |||||
90 | If an exception is raised, the partly cloned/updated destination |
|
78 | If an exception is raised, the partly cloned/updated destination | |
91 | repository will be deleted. |
|
79 | repository will be deleted. | |
92 |
|
80 | |||
93 |
|
|
81 | Arguments: | |
|
82 | ||||
|
83 | source: repository object or URL | |||
94 |
|
84 | |||
95 | dest: URL of destination repository to create (defaults to base |
|
85 | dest: URL of destination repository to create (defaults to base | |
96 | name of source repository) |
|
86 | name of source repository) | |
@@ -105,8 +95,24 b' def clone(ui, source, dest=None, pull=Fa' | |||||
105 | update: update working directory after clone completes, if |
|
95 | update: update working directory after clone completes, if | |
106 | destination is local repository |
|
96 | destination is local repository | |
107 | """ |
|
97 | """ | |
|
98 | if isinstance(source, str): | |||
|
99 | src_repo = repository(ui, source) | |||
|
100 | else: | |||
|
101 | src_repo = source | |||
|
102 | source = src_repo.url() | |||
|
103 | ||||
108 | if dest is None: |
|
104 | if dest is None: | |
109 | dest = os.path.basename(os.path.normpath(source)) |
|
105 | dest = defaultdest(source) | |
|
106 | ||||
|
107 | def localpath(path): | |||
|
108 | if path.startswith('file://'): | |||
|
109 | return path[7:] | |||
|
110 | if path.startswith('file:'): | |||
|
111 | return path[5:] | |||
|
112 | return path | |||
|
113 | ||||
|
114 | dest = localpath(dest) | |||
|
115 | source = localpath(source) | |||
110 |
|
116 | |||
111 | if os.path.exists(dest): |
|
117 | if os.path.exists(dest): | |
112 | raise util.Abort(_("destination '%s' already exists"), dest) |
|
118 | raise util.Abort(_("destination '%s' already exists"), dest) | |
@@ -121,8 +127,6 b' def clone(ui, source, dest=None, pull=Fa' | |||||
121 | if self.dir_: |
|
127 | if self.dir_: | |
122 | self.rmtree(self.dir_, True) |
|
128 | self.rmtree(self.dir_, True) | |
123 |
|
129 | |||
124 | src_repo = repository(ui, source) |
|
|||
125 |
|
||||
126 | dest_repo = None |
|
130 | dest_repo = None | |
127 | try: |
|
131 | try: | |
128 | dest_repo = repository(ui, dest) |
|
132 | dest_repo = repository(ui, dest) | |
@@ -133,7 +137,7 b' def clone(ui, source, dest=None, pull=Fa' | |||||
133 | dest_path = None |
|
137 | dest_path = None | |
134 | dir_cleanup = None |
|
138 | dir_cleanup = None | |
135 | if dest_repo.local(): |
|
139 | if dest_repo.local(): | |
136 | dest_path = os.path.realpath(dest) |
|
140 | dest_path = os.path.realpath(dest_repo.root) | |
137 | dir_cleanup = DirCleanup(dest_path) |
|
141 | dir_cleanup = DirCleanup(dest_path) | |
138 |
|
142 | |||
139 | abspath = source |
|
143 | abspath = source | |
@@ -202,8 +206,31 b' def clone(ui, source, dest=None, pull=Fa' | |||||
202 | dest_lock.release() |
|
206 | dest_lock.release() | |
203 |
|
207 | |||
204 | if update: |
|
208 | if update: | |
205 |
|
|
209 | _merge.update(dest_repo, dest_repo.changelog.tip()) | |
206 | if dir_cleanup: |
|
210 | if dir_cleanup: | |
207 | dir_cleanup.close() |
|
211 | dir_cleanup.close() | |
208 |
|
212 | |||
209 | return src_repo, dest_repo |
|
213 | return src_repo, dest_repo | |
|
214 | ||||
|
215 | def update(repo, node): | |||
|
216 | """update the working directory to node, merging linear changes""" | |||
|
217 | return _merge.update(repo, node) | |||
|
218 | ||||
|
219 | def clean(repo, node, wlock=None, show_stats=True): | |||
|
220 | """forcibly switch the working directory to node, clobbering changes""" | |||
|
221 | return _merge.update(repo, node, force=True, wlock=wlock, | |||
|
222 | show_stats=show_stats) | |||
|
223 | ||||
|
224 | def merge(repo, node, force=None, remind=True, wlock=None): | |||
|
225 | """branch merge with node, resolving changes""" | |||
|
226 | return _merge.update(repo, node, branchmerge=True, force=force, | |||
|
227 | remind=remind, wlock=wlock) | |||
|
228 | ||||
|
229 | def revert(repo, node, choose, wlock): | |||
|
230 | """revert changes to revision in node without updating dirstate""" | |||
|
231 | return _merge.update(repo, node, force=True, partial=choose, | |||
|
232 | show_stats=False, wlock=wlock) | |||
|
233 | ||||
|
234 | def verify(repo): | |||
|
235 | """verify the consistency of a repository""" | |||
|
236 | return _verify.verify(repo) |
@@ -1,7 +1,7 b'' | |||||
1 | # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod |
|
1 | # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod | |
2 | # |
|
2 | # | |
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||||
1 | # hgweb/hgweb_mod.py - Web interface for a repository. |
|
1 | # hgweb/hgweb_mod.py - Web interface for a repository. | |
2 | # |
|
2 | # | |
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -11,7 +11,7 b' import os.path' | |||||
11 | import mimetypes |
|
11 | import mimetypes | |
12 | from mercurial.demandload import demandload |
|
12 | from mercurial.demandload import demandload | |
13 | demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile") |
|
13 | demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile") | |
14 | demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone") |
|
14 | demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch") | |
15 | demandload(globals(), "mercurial:templater") |
|
15 | demandload(globals(), "mercurial:templater") | |
16 | demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") |
|
16 | demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") | |
17 | from mercurial.node import * |
|
17 | from mercurial.node import * | |
@@ -37,6 +37,7 b' class hgweb(object):' | |||||
37 | self.mtime = -1 |
|
37 | self.mtime = -1 | |
38 | self.reponame = name |
|
38 | self.reponame = name | |
39 | self.archives = 'zip', 'gz', 'bz2' |
|
39 | self.archives = 'zip', 'gz', 'bz2' | |
|
40 | self.stripecount = 1 | |||
40 | self.templatepath = self.repo.ui.config("web", "templates", |
|
41 | self.templatepath = self.repo.ui.config("web", "templates", | |
41 | templater.templatepath()) |
|
42 | templater.templatepath()) | |
42 |
|
43 | |||
@@ -46,6 +47,8 b' class hgweb(object):' | |||||
46 | self.mtime = mtime |
|
47 | self.mtime = mtime | |
47 | self.repo = hg.repository(self.repo.ui, self.repo.root) |
|
48 | self.repo = hg.repository(self.repo.ui, self.repo.root) | |
48 | self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10)) |
|
49 | self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10)) | |
|
50 | self.stripecount = int(self.repo.ui.config("web", "stripes", 1)) | |||
|
51 | self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60)) | |||
49 | self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) |
|
52 | self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) | |
50 | self.allowpull = self.repo.ui.configbool("web", "allowpull", True) |
|
53 | self.allowpull = self.repo.ui.configbool("web", "allowpull", True) | |
51 |
|
54 | |||
@@ -126,39 +129,29 b' class hgweb(object):' | |||||
126 | date1 = util.datestr(change1[2]) |
|
129 | date1 = util.datestr(change1[2]) | |
127 | date2 = util.datestr(change2[2]) |
|
130 | date2 = util.datestr(change2[2]) | |
128 |
|
131 | |||
129 |
modified, added, removed, deleted, unknown = r. |
|
132 | modified, added, removed, deleted, unknown = r.status(node1, node2)[:5] | |
130 | if files: |
|
133 | if files: | |
131 | modified, added, removed = map(lambda x: filterfiles(files, x), |
|
134 | modified, added, removed = map(lambda x: filterfiles(files, x), | |
132 | (modified, added, removed)) |
|
135 | (modified, added, removed)) | |
133 |
|
136 | |||
134 |
diffopts = self.repo.ui |
|
137 | diffopts = patch.diffopts(self.repo.ui) | |
135 | showfunc = diffopts['showfunc'] |
|
|||
136 | ignorews = diffopts['ignorews'] |
|
|||
137 | ignorewsamount = diffopts['ignorewsamount'] |
|
|||
138 | ignoreblanklines = diffopts['ignoreblanklines'] |
|
|||
139 | for f in modified: |
|
138 | for f in modified: | |
140 | to = r.file(f).read(mmap1[f]) |
|
139 | to = r.file(f).read(mmap1[f]) | |
141 | tn = r.file(f).read(mmap2[f]) |
|
140 | tn = r.file(f).read(mmap2[f]) | |
142 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
141 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
143 | showfunc=showfunc, ignorews=ignorews, |
|
142 | opts=diffopts), f, tn) | |
144 | ignorewsamount=ignorewsamount, |
|
|||
145 | ignoreblanklines=ignoreblanklines), f, tn) |
|
|||
146 | for f in added: |
|
143 | for f in added: | |
147 | to = None |
|
144 | to = None | |
148 | tn = r.file(f).read(mmap2[f]) |
|
145 | tn = r.file(f).read(mmap2[f]) | |
149 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
146 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
150 | showfunc=showfunc, ignorews=ignorews, |
|
147 | opts=diffopts), f, tn) | |
151 | ignorewsamount=ignorewsamount, |
|
|||
152 | ignoreblanklines=ignoreblanklines), f, tn) |
|
|||
153 | for f in removed: |
|
148 | for f in removed: | |
154 | to = r.file(f).read(mmap1[f]) |
|
149 | to = r.file(f).read(mmap1[f]) | |
155 | tn = None |
|
150 | tn = None | |
156 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
151 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
157 | showfunc=showfunc, ignorews=ignorews, |
|
152 | opts=diffopts), f, tn) | |
158 | ignorewsamount=ignorewsamount, |
|
|||
159 | ignoreblanklines=ignoreblanklines), f, tn) |
|
|||
160 |
|
153 | |||
161 | def changelog(self, pos): |
|
154 | def changelog(self, pos, shortlog=False): | |
162 | def changenav(**map): |
|
155 | def changenav(**map): | |
163 | def seq(factor, maxchanges=None): |
|
156 | def seq(factor, maxchanges=None): | |
164 | if maxchanges: |
|
157 | if maxchanges: | |
@@ -173,8 +166,9 b' class hgweb(object):' | |||||
173 |
|
166 | |||
174 | l = [] |
|
167 | l = [] | |
175 | last = 0 |
|
168 | last = 0 | |
176 | for f in seq(1, self.maxchanges): |
|
169 | maxchanges = shortlog and self.maxshortchanges or self.maxchanges | |
177 |
|
|
170 | for f in seq(1, maxchanges): | |
|
171 | if f < maxchanges or f <= last: | |||
178 | continue |
|
172 | continue | |
179 | if f > count: |
|
173 | if f > count: | |
180 | break |
|
174 | break | |
@@ -219,14 +213,15 b' class hgweb(object):' | |||||
219 | for e in l: |
|
213 | for e in l: | |
220 | yield e |
|
214 | yield e | |
221 |
|
215 | |||
|
216 | maxchanges = shortlog and self.maxshortchanges or self.maxchanges | |||
222 | cl = self.repo.changelog |
|
217 | cl = self.repo.changelog | |
223 | mf = cl.read(cl.tip())[0] |
|
218 | mf = cl.read(cl.tip())[0] | |
224 | count = cl.count() |
|
219 | count = cl.count() | |
225 |
start = max(0, pos - |
|
220 | start = max(0, pos - maxchanges + 1) | |
226 |
end = min(count, start + |
|
221 | end = min(count, start + maxchanges) | |
227 | pos = end - 1 |
|
222 | pos = end - 1 | |
228 |
|
223 | |||
229 | yield self.t('changelog', |
|
224 | yield self.t(shortlog and 'shortlog' or 'changelog', | |
230 | changenav=changenav, |
|
225 | changenav=changenav, | |
231 | manifest=hex(mf), |
|
226 | manifest=hex(mf), | |
232 | rev=pos, changesets=count, entries=changelist, |
|
227 | rev=pos, changesets=count, entries=changelist, | |
@@ -265,7 +260,7 b' class hgweb(object):' | |||||
265 | hn = hex(n) |
|
260 | hn = hex(n) | |
266 |
|
261 | |||
267 | yield self.t('searchentry', |
|
262 | yield self.t('searchentry', | |
268 |
parity=count |
|
263 | parity=self.stripes(count), | |
269 | author=changes[1], |
|
264 | author=changes[1], | |
270 | parent=self.siblings(cl.parents(n), cl.rev), |
|
265 | parent=self.siblings(cl.parents(n), cl.rev), | |
271 | child=self.siblings(cl.children(n), cl.rev), |
|
266 | child=self.siblings(cl.children(n), cl.rev), | |
@@ -376,7 +371,7 b' class hgweb(object):' | |||||
376 | for l, t in enumerate(text.splitlines(1)): |
|
371 | for l, t in enumerate(text.splitlines(1)): | |
377 | yield {"line": t, |
|
372 | yield {"line": t, | |
378 | "linenumber": "% 6d" % (l + 1), |
|
373 | "linenumber": "% 6d" % (l + 1), | |
379 |
"parity": l |
|
374 | "parity": self.stripes(l)} | |
380 |
|
375 | |||
381 | yield self.t("filerevision", |
|
376 | yield self.t("filerevision", | |
382 | file=f, |
|
377 | file=f, | |
@@ -393,7 +388,7 b' class hgweb(object):' | |||||
393 | parent=self.siblings(fl.parents(n), fl.rev, file=f), |
|
388 | parent=self.siblings(fl.parents(n), fl.rev, file=f), | |
394 | child=self.siblings(fl.children(n), fl.rev, file=f), |
|
389 | child=self.siblings(fl.children(n), fl.rev, file=f), | |
395 | rename=self.renamelink(fl, n), |
|
390 | rename=self.renamelink(fl, n), | |
396 |
permissions=self.repo.manifest.read |
|
391 | permissions=self.repo.manifest.read(mfn).execf(f)) | |
397 |
|
392 | |||
398 | def fileannotate(self, f, node): |
|
393 | def fileannotate(self, f, node): | |
399 | bcache = {} |
|
394 | bcache = {} | |
@@ -409,7 +404,7 b' class hgweb(object):' | |||||
409 | mfn = cs[0] |
|
404 | mfn = cs[0] | |
410 |
|
405 | |||
411 | def annotate(**map): |
|
406 | def annotate(**map): | |
412 |
parity = |
|
407 | parity = 0 | |
413 | last = None |
|
408 | last = None | |
414 | for r, l in fl.annotate(n): |
|
409 | for r, l in fl.annotate(n): | |
415 | try: |
|
410 | try: | |
@@ -447,7 +442,7 b' class hgweb(object):' | |||||
447 | rename=self.renamelink(fl, n), |
|
442 | rename=self.renamelink(fl, n), | |
448 | parent=self.siblings(fl.parents(n), fl.rev, file=f), |
|
443 | parent=self.siblings(fl.parents(n), fl.rev, file=f), | |
449 | child=self.siblings(fl.children(n), fl.rev, file=f), |
|
444 | child=self.siblings(fl.children(n), fl.rev, file=f), | |
450 |
permissions=self.repo.manifest.read |
|
445 | permissions=self.repo.manifest.read(mfn).execf(f)) | |
451 |
|
446 | |||
452 | def manifest(self, mnode, path): |
|
447 | def manifest(self, mnode, path): | |
453 | man = self.repo.manifest |
|
448 | man = self.repo.manifest | |
@@ -457,7 +452,6 b' class hgweb(object):' | |||||
457 | rev = man.rev(mn) |
|
452 | rev = man.rev(mn) | |
458 | changerev = man.linkrev(mn) |
|
453 | changerev = man.linkrev(mn) | |
459 | node = self.repo.changelog.node(changerev) |
|
454 | node = self.repo.changelog.node(changerev) | |
460 | mff = man.readflags(mn) |
|
|||
461 |
|
455 | |||
462 | files = {} |
|
456 | files = {} | |
463 |
|
457 | |||
@@ -489,10 +483,10 b' class hgweb(object):' | |||||
489 | yield {"file": full, |
|
483 | yield {"file": full, | |
490 | "manifest": mnode, |
|
484 | "manifest": mnode, | |
491 | "filenode": hex(fnode), |
|
485 | "filenode": hex(fnode), | |
492 | "parity": parity, |
|
486 | "parity": self.stripes(parity), | |
493 | "basename": f, |
|
487 | "basename": f, | |
494 |
"permissions": mf |
|
488 | "permissions": mf.execf(full)} | |
495 |
parity = 1 |
|
489 | parity += 1 | |
496 |
|
490 | |||
497 | def dirlist(**map): |
|
491 | def dirlist(**map): | |
498 | parity = 0 |
|
492 | parity = 0 | |
@@ -503,11 +497,11 b' class hgweb(object):' | |||||
503 | if fnode: |
|
497 | if fnode: | |
504 | continue |
|
498 | continue | |
505 |
|
499 | |||
506 | yield {"parity": parity, |
|
500 | yield {"parity": self.stripes(parity), | |
507 | "path": os.path.join(path, f), |
|
501 | "path": os.path.join(path, f), | |
508 | "manifest": mnode, |
|
502 | "manifest": mnode, | |
509 | "basename": f[:-1]} |
|
503 | "basename": f[:-1]} | |
510 |
parity = 1 |
|
504 | parity += 1 | |
511 |
|
505 | |||
512 | yield self.t("manifest", |
|
506 | yield self.t("manifest", | |
513 | manifest=mnode, |
|
507 | manifest=mnode, | |
@@ -530,12 +524,12 b' class hgweb(object):' | |||||
530 | parity = 0 |
|
524 | parity = 0 | |
531 | for k,n in i: |
|
525 | for k,n in i: | |
532 | if notip and k == "tip": continue |
|
526 | if notip and k == "tip": continue | |
533 | yield {"parity": parity, |
|
527 | yield {"parity": self.stripes(parity), | |
534 | "tag": k, |
|
528 | "tag": k, | |
535 | "tagmanifest": hex(cl.read(n)[0]), |
|
529 | "tagmanifest": hex(cl.read(n)[0]), | |
536 | "date": cl.read(n)[2], |
|
530 | "date": cl.read(n)[2], | |
537 | "node": hex(n)} |
|
531 | "node": hex(n)} | |
538 |
parity = 1 |
|
532 | parity += 1 | |
539 |
|
533 | |||
540 | yield self.t("tags", |
|
534 | yield self.t("tags", | |
541 | manifest=hex(mf), |
|
535 | manifest=hex(mf), | |
@@ -565,12 +559,12 b' class hgweb(object):' | |||||
565 | t = c[2] |
|
559 | t = c[2] | |
566 |
|
560 | |||
567 | yield self.t("tagentry", |
|
561 | yield self.t("tagentry", | |
568 | parity = parity, |
|
562 | parity = self.stripes(parity), | |
569 | tag = k, |
|
563 | tag = k, | |
570 | node = hex(n), |
|
564 | node = hex(n), | |
571 | date = t, |
|
565 | date = t, | |
572 | tagmanifest = hex(m)) |
|
566 | tagmanifest = hex(m)) | |
573 |
parity = 1 |
|
567 | parity += 1 | |
574 |
|
568 | |||
575 | def changelist(**map): |
|
569 | def changelist(**map): | |
576 | parity = 0 |
|
570 | parity = 0 | |
@@ -609,7 +603,8 b' class hgweb(object):' | |||||
609 | lastchange = (0, 0), # FIXME |
|
603 | lastchange = (0, 0), # FIXME | |
610 | manifest = hex(mf), |
|
604 | manifest = hex(mf), | |
611 | tags = tagentries, |
|
605 | tags = tagentries, | |
612 |
shortlog = changelist |
|
606 | shortlog = changelist, | |
|
607 | archives=self.archivelist("tip")) | |||
613 |
|
608 | |||
614 | def filediff(self, file, changeset): |
|
609 | def filediff(self, file, changeset): | |
615 | cl = self.repo.changelog |
|
610 | cl = self.repo.changelog | |
@@ -689,6 +684,7 b' class hgweb(object):' | |||||
689 | def expand_form(form): |
|
684 | def expand_form(form): | |
690 | shortcuts = { |
|
685 | shortcuts = { | |
691 | 'cl': [('cmd', ['changelog']), ('rev', None)], |
|
686 | 'cl': [('cmd', ['changelog']), ('rev', None)], | |
|
687 | 'sl': [('cmd', ['shortlog']), ('rev', None)], | |||
692 | 'cs': [('cmd', ['changeset']), ('node', None)], |
|
688 | 'cs': [('cmd', ['changeset']), ('node', None)], | |
693 | 'f': [('cmd', ['file']), ('filenode', None)], |
|
689 | 'f': [('cmd', ['file']), ('filenode', None)], | |
694 | 'fl': [('cmd', ['filelog']), ('filenode', None)], |
|
690 | 'fl': [('cmd', ['filelog']), ('filenode', None)], | |
@@ -752,6 +748,13 b' class hgweb(object):' | |||||
752 | else: |
|
748 | else: | |
753 | req.write(self.t("error")) |
|
749 | req.write(self.t("error")) | |
754 |
|
750 | |||
|
751 | def stripes(self, parity): | |||
|
752 | "make horizontal stripes for easier reading" | |||
|
753 | if self.stripecount: | |||
|
754 | return (1 + parity / self.stripecount) & 1 | |||
|
755 | else: | |||
|
756 | return 0 | |||
|
757 | ||||
755 | def do_changelog(self, req): |
|
758 | def do_changelog(self, req): | |
756 | hi = self.repo.changelog.count() - 1 |
|
759 | hi = self.repo.changelog.count() - 1 | |
757 | if req.form.has_key('rev'): |
|
760 | if req.form.has_key('rev'): | |
@@ -764,6 +767,18 b' class hgweb(object):' | |||||
764 |
|
767 | |||
765 | req.write(self.changelog(hi)) |
|
768 | req.write(self.changelog(hi)) | |
766 |
|
769 | |||
|
770 | def do_shortlog(self, req): | |||
|
771 | hi = self.repo.changelog.count() - 1 | |||
|
772 | if req.form.has_key('rev'): | |||
|
773 | hi = req.form['rev'][0] | |||
|
774 | try: | |||
|
775 | hi = self.repo.changelog.rev(self.repo.lookup(hi)) | |||
|
776 | except hg.RepoError: | |||
|
777 | req.write(self.search(hi)) # XXX redirect to 404 page? | |||
|
778 | return | |||
|
779 | ||||
|
780 | req.write(self.changelog(hi, shortlog = True)) | |||
|
781 | ||||
767 | def do_changeset(self, req): |
|
782 | def do_changeset(self, req): | |
768 | req.write(self.changeset(req.form['node'][0])) |
|
783 | req.write(self.changeset(req.form['node'][0])) | |
769 |
|
784 | |||
@@ -895,9 +910,13 b' class hgweb(object):' | |||||
895 | # require ssl by default, auth info cannot be sniffed and |
|
910 | # require ssl by default, auth info cannot be sniffed and | |
896 | # replayed |
|
911 | # replayed | |
897 | ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) |
|
912 | ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) | |
898 | if ssl_req and not req.env.get('HTTPS'): |
|
913 | if ssl_req: | |
899 | bail(_('ssl required\n')) |
|
914 | if not req.env.get('HTTPS'): | |
900 | return |
|
915 | bail(_('ssl required\n')) | |
|
916 | return | |||
|
917 | proto = 'https' | |||
|
918 | else: | |||
|
919 | proto = 'http' | |||
901 |
|
920 | |||
902 | # do not allow push unless explicitly allowed |
|
921 | # do not allow push unless explicitly allowed | |
903 | if not self.check_perm(req, 'push', False): |
|
922 | if not self.check_perm(req, 'push', False): | |
@@ -943,7 +962,9 b' class hgweb(object):' | |||||
943 | sys.stdout = cStringIO.StringIO() |
|
962 | sys.stdout = cStringIO.StringIO() | |
944 |
|
963 | |||
945 | try: |
|
964 | try: | |
946 | ret = self.repo.addchangegroup(fp, 'serve') |
|
965 | url = 'remote:%s:%s' % (proto, | |
|
966 | req.env.get('REMOTE_HOST', '')) | |||
|
967 | ret = self.repo.addchangegroup(fp, 'serve', url) | |||
947 | finally: |
|
968 | finally: | |
948 | val = sys.stdout.getvalue() |
|
969 | val = sys.stdout.getvalue() | |
949 | sys.stdout = old_stdout |
|
970 | sys.stdout = old_stdout |
@@ -1,7 +1,7 b'' | |||||
1 | # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories. |
|
1 | # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories. | |
2 | # |
|
2 | # | |
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||||
1 | # hgweb/request.py - An http request from either CGI or the standalone server. |
|
1 | # hgweb/request.py - An http request from either CGI or the standalone server. | |
2 | # |
|
2 | # | |
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||||
1 | # hgweb/server.py - The standalone hg web server. |
|
1 | # hgweb/server.py - The standalone hg web server. | |
2 | # |
|
2 | # | |
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -198,6 +198,7 b' def create_server(ui, repo):' | |||||
198 | self.webdirmaker = hgwebdir |
|
198 | self.webdirmaker = hgwebdir | |
199 | self.repoviewmaker = hgweb |
|
199 | self.repoviewmaker = hgweb | |
200 | self.reqmaker = wsgiapplication(self.make_handler) |
|
200 | self.reqmaker = wsgiapplication(self.make_handler) | |
|
201 | self.daemon_threads = True | |||
201 |
|
202 | |||
202 | def make_handler(self): |
|
203 | def make_handler(self): | |
203 | if self.webdir_conf: |
|
204 | if self.webdir_conf: |
@@ -1,6 +1,6 b'' | |||||
1 | # httprangereader.py - just what it says |
|
1 | # httprangereader.py - just what it says | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,7 b'' | |||||
1 | # httprepo.py - HTTP repository proxy classes for mercurial |
|
1 | # httprepo.py - HTTP repository proxy classes for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
4 | # |
|
5 | # | |
5 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -115,6 +116,7 b' else:' | |||||
115 |
|
116 | |||
116 | class httprepository(remoterepository): |
|
117 | class httprepository(remoterepository): | |
117 | def __init__(self, ui, path): |
|
118 | def __init__(self, ui, path): | |
|
119 | self.path = path | |||
118 | self.caps = None |
|
120 | self.caps = None | |
119 | scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) |
|
121 | scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) | |
120 | if query or frag: |
|
122 | if query or frag: | |
@@ -124,8 +126,8 b' class httprepository(remoterepository):' | |||||
124 | host, port, user, passwd = netlocsplit(netloc) |
|
126 | host, port, user, passwd = netlocsplit(netloc) | |
125 |
|
127 | |||
126 | # urllib cannot handle URLs with embedded user or passwd |
|
128 | # urllib cannot handle URLs with embedded user or passwd | |
127 | self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), |
|
129 | self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), | |
128 | urlpath, '', '')) |
|
130 | urlpath, '', '')) | |
129 | self.ui = ui |
|
131 | self.ui = ui | |
130 |
|
132 | |||
131 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') |
|
133 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') | |
@@ -189,6 +191,9 b' class httprepository(remoterepository):' | |||||
189 | opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] |
|
191 | opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] | |
190 | urllib2.install_opener(opener) |
|
192 | urllib2.install_opener(opener) | |
191 |
|
193 | |||
|
194 | def url(self): | |||
|
195 | return self.path | |||
|
196 | ||||
192 | # look up capabilities only when needed |
|
197 | # look up capabilities only when needed | |
193 |
|
198 | |||
194 | def get_caps(self): |
|
199 | def get_caps(self): | |
@@ -213,7 +218,7 b' class httprepository(remoterepository):' | |||||
213 | q = {"cmd": cmd} |
|
218 | q = {"cmd": cmd} | |
214 | q.update(args) |
|
219 | q.update(args) | |
215 | qs = urllib.urlencode(q) |
|
220 | qs = urllib.urlencode(q) | |
216 | cu = "%s?%s" % (self.url, qs) |
|
221 | cu = "%s?%s" % (self._url, qs) | |
217 | try: |
|
222 | try: | |
218 | resp = urllib2.urlopen(urllib2.Request(cu, data, headers)) |
|
223 | resp = urllib2.urlopen(urllib2.Request(cu, data, headers)) | |
219 | except urllib2.HTTPError, inst: |
|
224 | except urllib2.HTTPError, inst: | |
@@ -234,13 +239,13 b' class httprepository(remoterepository):' | |||||
234 | not proto.startswith('text/plain') and \ |
|
239 | not proto.startswith('text/plain') and \ | |
235 | not proto.startswith('application/hg-changegroup'): |
|
240 | not proto.startswith('application/hg-changegroup'): | |
236 | raise hg.RepoError(_("'%s' does not appear to be an hg repository") % |
|
241 | raise hg.RepoError(_("'%s' does not appear to be an hg repository") % | |
237 | self.url) |
|
242 | self._url) | |
238 |
|
243 | |||
239 | if proto.startswith('application/mercurial'): |
|
244 | if proto.startswith('application/mercurial'): | |
240 | version = proto[22:] |
|
245 | version = proto[22:] | |
241 | if float(version) > 0.1: |
|
246 | if float(version) > 0.1: | |
242 | raise hg.RepoError(_("'%s' uses newer protocol %s") % |
|
247 | raise hg.RepoError(_("'%s' uses newer protocol %s") % | |
243 | (self.url, version)) |
|
248 | (self._url, version)) | |
244 |
|
249 | |||
245 | return resp |
|
250 | return resp | |
246 |
|
251 | |||
@@ -335,3 +340,13 b' class httpsrepository(httprepository):' | |||||
335 | raise util.Abort(_('Python support for SSL and HTTPS ' |
|
340 | raise util.Abort(_('Python support for SSL and HTTPS ' | |
336 | 'is not installed')) |
|
341 | 'is not installed')) | |
337 | httprepository.__init__(self, ui, path) |
|
342 | httprepository.__init__(self, ui, path) | |
|
343 | ||||
|
344 | def instance(ui, path, create): | |||
|
345 | if create: | |||
|
346 | raise util.Abort(_('cannot create new http repository')) | |||
|
347 | if path.startswith('hg:'): | |||
|
348 | ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n")) | |||
|
349 | path = 'http:' + path[3:] | |||
|
350 | if path.startswith('https:'): | |||
|
351 | return httpsrepository(ui, path) | |||
|
352 | return httprepository(ui, path) |
@@ -1,7 +1,7 b'' | |||||
1 | """ |
|
1 | """ | |
2 | i18n.py - internationalization support for mercurial |
|
2 | i18n.py - internationalization support for mercurial | |
3 |
|
3 | |||
4 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 |
|
5 | |||
6 | This software may be used and distributed according to the terms |
|
6 | This software may be used and distributed according to the terms | |
7 | of the GNU General Public License, incorporated herein by reference. |
|
7 | of the GNU General Public License, incorporated herein by reference. |
This diff has been collapsed as it changes many lines, (648 lines changed) Show them Hide them | |||||
@@ -1,6 +1,6 b'' | |||||
1 | # localrepo.py - read/write repository class for mercurial |
|
1 | # localrepo.py - read/write repository class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -83,6 +83,9 b' class localrepository(repo.repository):' | |||||
83 |
|
83 | |||
84 | self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) |
|
84 | self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) | |
85 |
|
85 | |||
|
86 | def url(self): | |||
|
87 | return 'file:' + self.root | |||
|
88 | ||||
86 | def hook(self, name, throw=False, **args): |
|
89 | def hook(self, name, throw=False, **args): | |
87 | def callhook(hname, funcname): |
|
90 | def callhook(hname, funcname): | |
88 | '''call python hook. hook is callable object, looked up as |
|
91 | '''call python hook. hook is callable object, looked up as | |
@@ -195,7 +198,7 b' class localrepository(repo.repository):' | |||||
195 | self.hook('tag', node=node, tag=name, local=local) |
|
198 | self.hook('tag', node=node, tag=name, local=local) | |
196 | return |
|
199 | return | |
197 |
|
200 | |||
198 |
for x in self. |
|
201 | for x in self.status()[:5]: | |
199 | if '.hgtags' in x: |
|
202 | if '.hgtags' in x: | |
200 | raise util.Abort(_('working copy of .hgtags is changed ' |
|
203 | raise util.Abort(_('working copy of .hgtags is changed ' | |
201 | '(please commit .hgtags manually)')) |
|
204 | '(please commit .hgtags manually)')) | |
@@ -289,6 +292,10 b' class localrepository(repo.repository):' | |||||
289 | try: |
|
292 | try: | |
290 | return self.tags()[key] |
|
293 | return self.tags()[key] | |
291 | except KeyError: |
|
294 | except KeyError: | |
|
295 | if key == '.': | |||
|
296 | key = self.dirstate.parents()[0] | |||
|
297 | if key == nullid: | |||
|
298 | raise repo.RepoError(_("no revision checked out")) | |||
292 | try: |
|
299 | try: | |
293 | return self.changelog.lookup(key) |
|
300 | return self.changelog.lookup(key) | |
294 | except: |
|
301 | except: | |
@@ -463,8 +470,7 b' class localrepository(repo.repository):' | |||||
463 | p2 = p2 or self.dirstate.parents()[1] or nullid |
|
470 | p2 = p2 or self.dirstate.parents()[1] or nullid | |
464 | c1 = self.changelog.read(p1) |
|
471 | c1 = self.changelog.read(p1) | |
465 | c2 = self.changelog.read(p2) |
|
472 | c2 = self.changelog.read(p2) | |
466 | m1 = self.manifest.read(c1[0]) |
|
473 | m1 = self.manifest.read(c1[0]).copy() | |
467 | mf1 = self.manifest.readflags(c1[0]) |
|
|||
468 | m2 = self.manifest.read(c2[0]) |
|
474 | m2 = self.manifest.read(c2[0]) | |
469 | changed = [] |
|
475 | changed = [] | |
470 |
|
476 | |||
@@ -477,36 +483,32 b' class localrepository(repo.repository):' | |||||
477 | wlock = self.wlock() |
|
483 | wlock = self.wlock() | |
478 | l = self.lock() |
|
484 | l = self.lock() | |
479 | tr = self.transaction() |
|
485 | tr = self.transaction() | |
480 | mm = m1.copy() |
|
|||
481 | mfm = mf1.copy() |
|
|||
482 | linkrev = self.changelog.count() |
|
486 | linkrev = self.changelog.count() | |
483 | for f in files: |
|
487 | for f in files: | |
484 | try: |
|
488 | try: | |
485 | t = self.wread(f) |
|
489 | t = self.wread(f) | |
486 |
|
|
490 | m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f))) | |
487 | r = self.file(f) |
|
491 | r = self.file(f) | |
488 | mfm[f] = tm |
|
|||
489 |
|
492 | |||
490 | (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) |
|
493 | (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) | |
491 | if entry: |
|
494 | if entry: | |
492 |
m |
|
495 | m1[f] = entry | |
493 | continue |
|
496 | continue | |
494 |
|
497 | |||
495 |
m |
|
498 | m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2) | |
496 | changed.append(f) |
|
499 | changed.append(f) | |
497 | if update_dirstate: |
|
500 | if update_dirstate: | |
498 | self.dirstate.update([f], "n") |
|
501 | self.dirstate.update([f], "n") | |
499 | except IOError: |
|
502 | except IOError: | |
500 | try: |
|
503 | try: | |
501 |
del m |
|
504 | del m1[f] | |
502 | del mfm[f] |
|
|||
503 | if update_dirstate: |
|
505 | if update_dirstate: | |
504 | self.dirstate.forget([f]) |
|
506 | self.dirstate.forget([f]) | |
505 | except: |
|
507 | except: | |
506 | # deleted from p2? |
|
508 | # deleted from p2? | |
507 | pass |
|
509 | pass | |
508 |
|
510 | |||
509 |
mnode = self.manifest.add(m |
|
511 | mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0]) | |
510 | user = user or self.ui.username() |
|
512 | user = user or self.ui.username() | |
511 | n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date) |
|
513 | n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date) | |
512 | tr.close() |
|
514 | tr.close() | |
@@ -530,15 +532,14 b' class localrepository(repo.repository):' | |||||
530 | else: |
|
532 | else: | |
531 | self.ui.warn(_("%s not tracked!\n") % f) |
|
533 | self.ui.warn(_("%s not tracked!\n") % f) | |
532 | else: |
|
534 | else: | |
533 |
modified, added, removed, deleted, unknown = self. |
|
535 | modified, added, removed, deleted, unknown = self.status(match=match)[:5] | |
534 | commit = modified + added |
|
536 | commit = modified + added | |
535 | remove = removed |
|
537 | remove = removed | |
536 |
|
538 | |||
537 | p1, p2 = self.dirstate.parents() |
|
539 | p1, p2 = self.dirstate.parents() | |
538 | c1 = self.changelog.read(p1) |
|
540 | c1 = self.changelog.read(p1) | |
539 | c2 = self.changelog.read(p2) |
|
541 | c2 = self.changelog.read(p2) | |
540 | m1 = self.manifest.read(c1[0]) |
|
542 | m1 = self.manifest.read(c1[0]).copy() | |
541 | mf1 = self.manifest.readflags(c1[0]) |
|
|||
542 | m2 = self.manifest.read(c2[0]) |
|
543 | m2 = self.manifest.read(c2[0]) | |
543 |
|
544 | |||
544 | if not commit and not remove and not force and p2 == nullid: |
|
545 | if not commit and not remove and not force and p2 == nullid: | |
@@ -564,7 +565,7 b' class localrepository(repo.repository):' | |||||
564 | for f in commit: |
|
565 | for f in commit: | |
565 | self.ui.note(f + "\n") |
|
566 | self.ui.note(f + "\n") | |
566 | try: |
|
567 | try: | |
567 |
m |
|
568 | m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f))) | |
568 | t = self.wread(f) |
|
569 | t = self.wread(f) | |
569 | except IOError: |
|
570 | except IOError: | |
570 | self.ui.warn(_("trouble committing %s!\n") % f) |
|
571 | self.ui.warn(_("trouble committing %s!\n") % f) | |
@@ -591,12 +592,11 b' class localrepository(repo.repository):' | |||||
591 | changed.append(f) |
|
592 | changed.append(f) | |
592 |
|
593 | |||
593 | # update manifest |
|
594 | # update manifest | |
594 | m1 = m1.copy() |
|
|||
595 | m1.update(new) |
|
595 | m1.update(new) | |
596 | for f in remove: |
|
596 | for f in remove: | |
597 | if f in m1: |
|
597 | if f in m1: | |
598 | del m1[f] |
|
598 | del m1[f] | |
599 |
mn = self.manifest.add(m1 |
|
599 | mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], | |
600 | (new, remove)) |
|
600 | (new, remove)) | |
601 |
|
601 | |||
602 | # add changeset |
|
602 | # add changeset | |
@@ -658,9 +658,9 b' class localrepository(repo.repository):' | |||||
658 | for src, fn in self.dirstate.walk(files, match, badmatch=badmatch): |
|
658 | for src, fn in self.dirstate.walk(files, match, badmatch=badmatch): | |
659 | yield src, fn |
|
659 | yield src, fn | |
660 |
|
660 | |||
661 |
def |
|
661 | def status(self, node1=None, node2=None, files=[], match=util.always, | |
662 |
wlock=None, |
|
662 | wlock=None, list_ignored=False, list_clean=False): | |
663 |
"""return |
|
663 | """return status of files between two nodes or node and working directory | |
664 |
|
664 | |||
665 | If node1 is None, use the first dirstate parent instead. |
|
665 | If node1 is None, use the first dirstate parent instead. | |
666 | If node2 is None, compare node1 with working directory. |
|
666 | If node2 is None, compare node1 with working directory. | |
@@ -668,8 +668,7 b' class localrepository(repo.repository):' | |||||
668 |
|
668 | |||
669 | def fcmp(fn, mf): |
|
669 | def fcmp(fn, mf): | |
670 | t1 = self.wread(fn) |
|
670 | t1 = self.wread(fn) | |
671 |
|
|
671 | return self.file(fn).cmp(mf.get(fn, nullid), t1) | |
672 | return cmp(t1, t2) |
|
|||
673 |
|
672 | |||
674 | def mfmatches(node): |
|
673 | def mfmatches(node): | |
675 | change = self.changelog.read(node) |
|
674 | change = self.changelog.read(node) | |
@@ -679,7 +678,9 b' class localrepository(repo.repository):' | |||||
679 | del mf[fn] |
|
678 | del mf[fn] | |
680 | return mf |
|
679 | return mf | |
681 |
|
680 | |||
682 |
modified, added, removed, deleted, unknown |
|
681 | modified, added, removed, deleted, unknown = [], [], [], [], [] | |
|
682 | ignored, clean = [], [] | |||
|
683 | ||||
683 | compareworking = False |
|
684 | compareworking = False | |
684 | if not node1 or (not node2 and node1 == self.dirstate.parents()[0]): |
|
685 | if not node1 or (not node2 and node1 == self.dirstate.parents()[0]): | |
685 | compareworking = True |
|
686 | compareworking = True | |
@@ -697,8 +698,9 b' class localrepository(repo.repository):' | |||||
697 | wlock = self.wlock(wait=0) |
|
698 | wlock = self.wlock(wait=0) | |
698 | except lock.LockException: |
|
699 | except lock.LockException: | |
699 | wlock = None |
|
700 | wlock = None | |
700 |
lookup, modified, added, removed, deleted, unknown, |
|
701 | (lookup, modified, added, removed, deleted, unknown, | |
701 |
self.dirstate. |
|
702 | ignored, clean) = self.dirstate.status(files, match, | |
|
703 | list_ignored, list_clean) | |||
702 |
|
704 | |||
703 | # are we comparing working dir against its parent? |
|
705 | # are we comparing working dir against its parent? | |
704 | if compareworking: |
|
706 | if compareworking: | |
@@ -721,12 +723,11 b' class localrepository(repo.repository):' | |||||
721 | del mf2[f] |
|
723 | del mf2[f] | |
722 | else: |
|
724 | else: | |
723 | # we are comparing two revisions |
|
725 | # we are comparing two revisions | |
724 | deleted, unknown, ignored = [], [], [] |
|
|||
725 | mf2 = mfmatches(node2) |
|
726 | mf2 = mfmatches(node2) | |
726 |
|
727 | |||
727 | if not compareworking: |
|
728 | if not compareworking: | |
728 | # flush lists from dirstate before comparing manifests |
|
729 | # flush lists from dirstate before comparing manifests | |
729 | modified, added = [], [] |
|
730 | modified, added, clean = [], [], [] | |
730 |
|
731 | |||
731 | # make sure to sort the files so we talk to the disk in a |
|
732 | # make sure to sort the files so we talk to the disk in a | |
732 | # reasonable order |
|
733 | # reasonable order | |
@@ -736,6 +737,8 b' class localrepository(repo.repository):' | |||||
736 | if mf1.has_key(fn): |
|
737 | if mf1.has_key(fn): | |
737 | if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)): |
|
738 | if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)): | |
738 | modified.append(fn) |
|
739 | modified.append(fn) | |
|
740 | elif list_clean: | |||
|
741 | clean.append(fn) | |||
739 | del mf1[fn] |
|
742 | del mf1[fn] | |
740 | else: |
|
743 | else: | |
741 | added.append(fn) |
|
744 | added.append(fn) | |
@@ -743,12 +746,9 b' class localrepository(repo.repository):' | |||||
743 | removed = mf1.keys() |
|
746 | removed = mf1.keys() | |
744 |
|
747 | |||
745 | # sort and return results: |
|
748 | # sort and return results: | |
746 | for l in modified, added, removed, deleted, unknown, ignored: |
|
749 | for l in modified, added, removed, deleted, unknown, ignored, clean: | |
747 | l.sort() |
|
750 | l.sort() | |
748 | if show_ignored is None: |
|
751 | return (modified, added, removed, deleted, unknown, ignored, clean) | |
749 | return (modified, added, removed, deleted, unknown) |
|
|||
750 | else: |
|
|||
751 | return (modified, added, removed, deleted, unknown, ignored) |
|
|||
752 |
|
752 | |||
753 | def add(self, list, wlock=None): |
|
753 | def add(self, list, wlock=None): | |
754 | if not wlock: |
|
754 | if not wlock: | |
@@ -798,7 +798,6 b' class localrepository(repo.repository):' | |||||
798 | def undelete(self, list, wlock=None): |
|
798 | def undelete(self, list, wlock=None): | |
799 | p = self.dirstate.parents()[0] |
|
799 | p = self.dirstate.parents()[0] | |
800 | mn = self.changelog.read(p)[0] |
|
800 | mn = self.changelog.read(p)[0] | |
801 | mf = self.manifest.readflags(mn) |
|
|||
802 | m = self.manifest.read(mn) |
|
801 | m = self.manifest.read(mn) | |
803 | if not wlock: |
|
802 | if not wlock: | |
804 | wlock = self.wlock() |
|
803 | wlock = self.wlock() | |
@@ -808,7 +807,7 b' class localrepository(repo.repository):' | |||||
808 | else: |
|
807 | else: | |
809 | t = self.file(f).read(m[f]) |
|
808 | t = self.file(f).read(m[f]) | |
810 | self.wwrite(f, t) |
|
809 | self.wwrite(f, t) | |
811 |
util.set_exec(self.wjoin(f), m |
|
810 | util.set_exec(self.wjoin(f), m.execf(f)) | |
812 | self.dirstate.update([f], "n") |
|
811 | self.dirstate.update([f], "n") | |
813 |
|
812 | |||
814 | def copy(self, source, dest, wlock=None): |
|
813 | def copy(self, source, dest, wlock=None): | |
@@ -1159,22 +1158,29 b' class localrepository(repo.repository):' | |||||
1159 | else: |
|
1158 | else: | |
1160 | return subset |
|
1159 | return subset | |
1161 |
|
1160 | |||
1162 | def pull(self, remote, heads=None, force=False): |
|
1161 | def pull(self, remote, heads=None, force=False, lock=None): | |
1163 | l = self.lock() |
|
1162 | mylock = False | |
|
1163 | if not lock: | |||
|
1164 | lock = self.lock() | |||
|
1165 | mylock = True | |||
1164 |
|
1166 | |||
1165 | fetch = self.findincoming(remote, force=force) |
|
1167 | try: | |
1166 | if fetch == [nullid]: |
|
1168 | fetch = self.findincoming(remote, force=force) | |
1167 | self.ui.status(_("requesting all changes\n")) |
|
1169 | if fetch == [nullid]: | |
|
1170 | self.ui.status(_("requesting all changes\n")) | |||
1168 |
|
1171 | |||
1169 | if not fetch: |
|
1172 | if not fetch: | |
1170 | self.ui.status(_("no changes found\n")) |
|
1173 | self.ui.status(_("no changes found\n")) | |
1171 | return 0 |
|
1174 | return 0 | |
1172 |
|
1175 | |||
1173 | if heads is None: |
|
1176 | if heads is None: | |
1174 | cg = remote.changegroup(fetch, 'pull') |
|
1177 | cg = remote.changegroup(fetch, 'pull') | |
1175 | else: |
|
1178 | else: | |
1176 | cg = remote.changegroupsubset(fetch, heads, 'pull') |
|
1179 | cg = remote.changegroupsubset(fetch, heads, 'pull') | |
1177 | return self.addchangegroup(cg, 'pull') |
|
1180 | return self.addchangegroup(cg, 'pull', remote.url()) | |
|
1181 | finally: | |||
|
1182 | if mylock: | |||
|
1183 | lock.release() | |||
1178 |
|
1184 | |||
1179 | def push(self, remote, force=False, revs=None): |
|
1185 | def push(self, remote, force=False, revs=None): | |
1180 | # there are two ways to push to remote repo: |
|
1186 | # there are two ways to push to remote repo: | |
@@ -1230,7 +1236,7 b' class localrepository(repo.repository):' | |||||
1230 | ret = self.prepush(remote, force, revs) |
|
1236 | ret = self.prepush(remote, force, revs) | |
1231 | if ret[0] is not None: |
|
1237 | if ret[0] is not None: | |
1232 | cg, remote_heads = ret |
|
1238 | cg, remote_heads = ret | |
1233 | return remote.addchangegroup(cg, 'push') |
|
1239 | return remote.addchangegroup(cg, 'push', self.url()) | |
1234 | return ret[1] |
|
1240 | return ret[1] | |
1235 |
|
1241 | |||
1236 | def push_unbundle(self, remote, force, revs): |
|
1242 | def push_unbundle(self, remote, force, revs): | |
@@ -1583,7 +1589,7 b' class localrepository(repo.repository):' | |||||
1583 |
|
1589 | |||
1584 | return util.chunkbuffer(gengroup()) |
|
1590 | return util.chunkbuffer(gengroup()) | |
1585 |
|
1591 | |||
1586 | def addchangegroup(self, source, srctype): |
|
1592 | def addchangegroup(self, source, srctype, url): | |
1587 | """add changegroup to repo. |
|
1593 | """add changegroup to repo. | |
1588 | returns number of heads modified or added + 1.""" |
|
1594 | returns number of heads modified or added + 1.""" | |
1589 |
|
1595 | |||
@@ -1597,7 +1603,7 b' class localrepository(repo.repository):' | |||||
1597 | if not source: |
|
1603 | if not source: | |
1598 | return 0 |
|
1604 | return 0 | |
1599 |
|
1605 | |||
1600 | self.hook('prechangegroup', throw=True, source=srctype) |
|
1606 | self.hook('prechangegroup', throw=True, source=srctype, url=url) | |
1601 |
|
1607 | |||
1602 | changesets = files = revisions = 0 |
|
1608 | changesets = files = revisions = 0 | |
1603 |
|
1609 | |||
@@ -1664,544 +1670,21 b' class localrepository(repo.repository):' | |||||
1664 |
|
1670 | |||
1665 | if changesets > 0: |
|
1671 | if changesets > 0: | |
1666 | self.hook('pretxnchangegroup', throw=True, |
|
1672 | self.hook('pretxnchangegroup', throw=True, | |
1667 |
node=hex(self.changelog.node(cor+1)), source=srctype |
|
1673 | node=hex(self.changelog.node(cor+1)), source=srctype, | |
|
1674 | url=url) | |||
1668 |
|
1675 | |||
1669 | tr.close() |
|
1676 | tr.close() | |
1670 |
|
1677 | |||
1671 | if changesets > 0: |
|
1678 | if changesets > 0: | |
1672 | self.hook("changegroup", node=hex(self.changelog.node(cor+1)), |
|
1679 | self.hook("changegroup", node=hex(self.changelog.node(cor+1)), | |
1673 | source=srctype) |
|
1680 | source=srctype, url=url) | |
1674 |
|
1681 | |||
1675 | for i in range(cor + 1, cnr + 1): |
|
1682 | for i in range(cor + 1, cnr + 1): | |
1676 | self.hook("incoming", node=hex(self.changelog.node(i)), |
|
1683 | self.hook("incoming", node=hex(self.changelog.node(i)), | |
1677 | source=srctype) |
|
1684 | source=srctype, url=url) | |
1678 |
|
1685 | |||
1679 | return newheads - oldheads + 1 |
|
1686 | return newheads - oldheads + 1 | |
1680 |
|
1687 | |||
1681 | def update(self, node, allow=False, force=False, choose=None, |
|
|||
1682 | moddirstate=True, forcemerge=False, wlock=None, show_stats=True): |
|
|||
1683 | pl = self.dirstate.parents() |
|
|||
1684 | if not force and pl[1] != nullid: |
|
|||
1685 | raise util.Abort(_("outstanding uncommitted merges")) |
|
|||
1686 |
|
||||
1687 | err = False |
|
|||
1688 |
|
||||
1689 | p1, p2 = pl[0], node |
|
|||
1690 | pa = self.changelog.ancestor(p1, p2) |
|
|||
1691 | m1n = self.changelog.read(p1)[0] |
|
|||
1692 | m2n = self.changelog.read(p2)[0] |
|
|||
1693 | man = self.manifest.ancestor(m1n, m2n) |
|
|||
1694 | m1 = self.manifest.read(m1n) |
|
|||
1695 | mf1 = self.manifest.readflags(m1n) |
|
|||
1696 | m2 = self.manifest.read(m2n).copy() |
|
|||
1697 | mf2 = self.manifest.readflags(m2n) |
|
|||
1698 | ma = self.manifest.read(man) |
|
|||
1699 | mfa = self.manifest.readflags(man) |
|
|||
1700 |
|
||||
1701 | modified, added, removed, deleted, unknown = self.changes() |
|
|||
1702 |
|
||||
1703 | # is this a jump, or a merge? i.e. is there a linear path |
|
|||
1704 | # from p1 to p2? |
|
|||
1705 | linear_path = (pa == p1 or pa == p2) |
|
|||
1706 |
|
||||
1707 | if allow and linear_path: |
|
|||
1708 | raise util.Abort(_("there is nothing to merge, just use " |
|
|||
1709 | "'hg update' or look at 'hg heads'")) |
|
|||
1710 | if allow and not forcemerge: |
|
|||
1711 | if modified or added or removed: |
|
|||
1712 | raise util.Abort(_("outstanding uncommitted changes")) |
|
|||
1713 |
|
||||
1714 | if not forcemerge and not force: |
|
|||
1715 | for f in unknown: |
|
|||
1716 | if f in m2: |
|
|||
1717 | t1 = self.wread(f) |
|
|||
1718 | t2 = self.file(f).read(m2[f]) |
|
|||
1719 | if cmp(t1, t2) != 0: |
|
|||
1720 | raise util.Abort(_("'%s' already exists in the working" |
|
|||
1721 | " dir and differs from remote") % f) |
|
|||
1722 |
|
||||
1723 | # resolve the manifest to determine which files |
|
|||
1724 | # we care about merging |
|
|||
1725 | self.ui.note(_("resolving manifests\n")) |
|
|||
1726 | self.ui.debug(_(" force %s allow %s moddirstate %s linear %s\n") % |
|
|||
1727 | (force, allow, moddirstate, linear_path)) |
|
|||
1728 | self.ui.debug(_(" ancestor %s local %s remote %s\n") % |
|
|||
1729 | (short(man), short(m1n), short(m2n))) |
|
|||
1730 |
|
||||
1731 | merge = {} |
|
|||
1732 | get = {} |
|
|||
1733 | remove = [] |
|
|||
1734 |
|
||||
1735 | # construct a working dir manifest |
|
|||
1736 | mw = m1.copy() |
|
|||
1737 | mfw = mf1.copy() |
|
|||
1738 | umap = dict.fromkeys(unknown) |
|
|||
1739 |
|
||||
1740 | for f in added + modified + unknown: |
|
|||
1741 | mw[f] = "" |
|
|||
1742 | mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) |
|
|||
1743 |
|
||||
1744 | if moddirstate and not wlock: |
|
|||
1745 | wlock = self.wlock() |
|
|||
1746 |
|
||||
1747 | for f in deleted + removed: |
|
|||
1748 | if f in mw: |
|
|||
1749 | del mw[f] |
|
|||
1750 |
|
||||
1751 | # If we're jumping between revisions (as opposed to merging), |
|
|||
1752 | # and if neither the working directory nor the target rev has |
|
|||
1753 | # the file, then we need to remove it from the dirstate, to |
|
|||
1754 | # prevent the dirstate from listing the file when it is no |
|
|||
1755 | # longer in the manifest. |
|
|||
1756 | if moddirstate and linear_path and f not in m2: |
|
|||
1757 | self.dirstate.forget((f,)) |
|
|||
1758 |
|
||||
1759 | # Compare manifests |
|
|||
1760 | for f, n in mw.iteritems(): |
|
|||
1761 | if choose and not choose(f): |
|
|||
1762 | continue |
|
|||
1763 | if f in m2: |
|
|||
1764 | s = 0 |
|
|||
1765 |
|
||||
1766 | # is the wfile new since m1, and match m2? |
|
|||
1767 | if f not in m1: |
|
|||
1768 | t1 = self.wread(f) |
|
|||
1769 | t2 = self.file(f).read(m2[f]) |
|
|||
1770 | if cmp(t1, t2) == 0: |
|
|||
1771 | n = m2[f] |
|
|||
1772 | del t1, t2 |
|
|||
1773 |
|
||||
1774 | # are files different? |
|
|||
1775 | if n != m2[f]: |
|
|||
1776 | a = ma.get(f, nullid) |
|
|||
1777 | # are both different from the ancestor? |
|
|||
1778 | if n != a and m2[f] != a: |
|
|||
1779 | self.ui.debug(_(" %s versions differ, resolve\n") % f) |
|
|||
1780 | # merge executable bits |
|
|||
1781 | # "if we changed or they changed, change in merge" |
|
|||
1782 | a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
|
|||
1783 | mode = ((a^b) | (a^c)) ^ a |
|
|||
1784 | merge[f] = (m1.get(f, nullid), m2[f], mode) |
|
|||
1785 | s = 1 |
|
|||
1786 | # are we clobbering? |
|
|||
1787 | # is remote's version newer? |
|
|||
1788 | # or are we going back in time? |
|
|||
1789 | elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]): |
|
|||
1790 | self.ui.debug(_(" remote %s is newer, get\n") % f) |
|
|||
1791 | get[f] = m2[f] |
|
|||
1792 | s = 1 |
|
|||
1793 | elif f in umap or f in added: |
|
|||
1794 | # this unknown file is the same as the checkout |
|
|||
1795 | # we need to reset the dirstate if the file was added |
|
|||
1796 | get[f] = m2[f] |
|
|||
1797 |
|
||||
1798 | if not s and mfw[f] != mf2[f]: |
|
|||
1799 | if force: |
|
|||
1800 | self.ui.debug(_(" updating permissions for %s\n") % f) |
|
|||
1801 | util.set_exec(self.wjoin(f), mf2[f]) |
|
|||
1802 | else: |
|
|||
1803 | a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
|
|||
1804 | mode = ((a^b) | (a^c)) ^ a |
|
|||
1805 | if mode != b: |
|
|||
1806 | self.ui.debug(_(" updating permissions for %s\n") |
|
|||
1807 | % f) |
|
|||
1808 | util.set_exec(self.wjoin(f), mode) |
|
|||
1809 | del m2[f] |
|
|||
1810 | elif f in ma: |
|
|||
1811 | if n != ma[f]: |
|
|||
1812 | r = _("d") |
|
|||
1813 | if not force and (linear_path or allow): |
|
|||
1814 | r = self.ui.prompt( |
|
|||
1815 | (_(" local changed %s which remote deleted\n") % f) + |
|
|||
1816 | _("(k)eep or (d)elete?"), _("[kd]"), _("k")) |
|
|||
1817 | if r == _("d"): |
|
|||
1818 | remove.append(f) |
|
|||
1819 | else: |
|
|||
1820 | self.ui.debug(_("other deleted %s\n") % f) |
|
|||
1821 | remove.append(f) # other deleted it |
|
|||
1822 | else: |
|
|||
1823 | # file is created on branch or in working directory |
|
|||
1824 | if force and f not in umap: |
|
|||
1825 | self.ui.debug(_("remote deleted %s, clobbering\n") % f) |
|
|||
1826 | remove.append(f) |
|
|||
1827 | elif n == m1.get(f, nullid): # same as parent |
|
|||
1828 | if p2 == pa: # going backwards? |
|
|||
1829 | self.ui.debug(_("remote deleted %s\n") % f) |
|
|||
1830 | remove.append(f) |
|
|||
1831 | else: |
|
|||
1832 | self.ui.debug(_("local modified %s, keeping\n") % f) |
|
|||
1833 | else: |
|
|||
1834 | self.ui.debug(_("working dir created %s, keeping\n") % f) |
|
|||
1835 |
|
||||
1836 | for f, n in m2.iteritems(): |
|
|||
1837 | if choose and not choose(f): |
|
|||
1838 | continue |
|
|||
1839 | if f[0] == "/": |
|
|||
1840 | continue |
|
|||
1841 | if f in ma and n != ma[f]: |
|
|||
1842 | r = _("k") |
|
|||
1843 | if not force and (linear_path or allow): |
|
|||
1844 | r = self.ui.prompt( |
|
|||
1845 | (_("remote changed %s which local deleted\n") % f) + |
|
|||
1846 | _("(k)eep or (d)elete?"), _("[kd]"), _("k")) |
|
|||
1847 | if r == _("k"): |
|
|||
1848 | get[f] = n |
|
|||
1849 | elif f not in ma: |
|
|||
1850 | self.ui.debug(_("remote created %s\n") % f) |
|
|||
1851 | get[f] = n |
|
|||
1852 | else: |
|
|||
1853 | if force or p2 == pa: # going backwards? |
|
|||
1854 | self.ui.debug(_("local deleted %s, recreating\n") % f) |
|
|||
1855 | get[f] = n |
|
|||
1856 | else: |
|
|||
1857 | self.ui.debug(_("local deleted %s\n") % f) |
|
|||
1858 |
|
||||
1859 | del mw, m1, m2, ma |
|
|||
1860 |
|
||||
1861 | if force: |
|
|||
1862 | for f in merge: |
|
|||
1863 | get[f] = merge[f][1] |
|
|||
1864 | merge = {} |
|
|||
1865 |
|
||||
1866 | if linear_path or force: |
|
|||
1867 | # we don't need to do any magic, just jump to the new rev |
|
|||
1868 | branch_merge = False |
|
|||
1869 | p1, p2 = p2, nullid |
|
|||
1870 | else: |
|
|||
1871 | if not allow: |
|
|||
1872 | self.ui.status(_("this update spans a branch" |
|
|||
1873 | " affecting the following files:\n")) |
|
|||
1874 | fl = merge.keys() + get.keys() |
|
|||
1875 | fl.sort() |
|
|||
1876 | for f in fl: |
|
|||
1877 | cf = "" |
|
|||
1878 | if f in merge: |
|
|||
1879 | cf = _(" (resolve)") |
|
|||
1880 | self.ui.status(" %s%s\n" % (f, cf)) |
|
|||
1881 | self.ui.warn(_("aborting update spanning branches!\n")) |
|
|||
1882 | self.ui.status(_("(use 'hg merge' to merge across branches" |
|
|||
1883 | " or 'hg update -C' to lose changes)\n")) |
|
|||
1884 | return 1 |
|
|||
1885 | branch_merge = True |
|
|||
1886 |
|
||||
1887 | xp1 = hex(p1) |
|
|||
1888 | xp2 = hex(p2) |
|
|||
1889 | if p2 == nullid: xxp2 = '' |
|
|||
1890 | else: xxp2 = xp2 |
|
|||
1891 |
|
||||
1892 | self.hook('preupdate', throw=True, parent1=xp1, parent2=xxp2) |
|
|||
1893 |
|
||||
1894 | # get the files we don't need to change |
|
|||
1895 | files = get.keys() |
|
|||
1896 | files.sort() |
|
|||
1897 | for f in files: |
|
|||
1898 | if f[0] == "/": |
|
|||
1899 | continue |
|
|||
1900 | self.ui.note(_("getting %s\n") % f) |
|
|||
1901 | t = self.file(f).read(get[f]) |
|
|||
1902 | self.wwrite(f, t) |
|
|||
1903 | util.set_exec(self.wjoin(f), mf2[f]) |
|
|||
1904 | if moddirstate: |
|
|||
1905 | if branch_merge: |
|
|||
1906 | self.dirstate.update([f], 'n', st_mtime=-1) |
|
|||
1907 | else: |
|
|||
1908 | self.dirstate.update([f], 'n') |
|
|||
1909 |
|
||||
1910 | # merge the tricky bits |
|
|||
1911 | failedmerge = [] |
|
|||
1912 | files = merge.keys() |
|
|||
1913 | files.sort() |
|
|||
1914 | for f in files: |
|
|||
1915 | self.ui.status(_("merging %s\n") % f) |
|
|||
1916 | my, other, flag = merge[f] |
|
|||
1917 | ret = self.merge3(f, my, other, xp1, xp2) |
|
|||
1918 | if ret: |
|
|||
1919 | err = True |
|
|||
1920 | failedmerge.append(f) |
|
|||
1921 | util.set_exec(self.wjoin(f), flag) |
|
|||
1922 | if moddirstate: |
|
|||
1923 | if branch_merge: |
|
|||
1924 | # We've done a branch merge, mark this file as merged |
|
|||
1925 | # so that we properly record the merger later |
|
|||
1926 | self.dirstate.update([f], 'm') |
|
|||
1927 | else: |
|
|||
1928 | # We've update-merged a locally modified file, so |
|
|||
1929 | # we set the dirstate to emulate a normal checkout |
|
|||
1930 | # of that file some time in the past. Thus our |
|
|||
1931 | # merge will appear as a normal local file |
|
|||
1932 | # modification. |
|
|||
1933 | f_len = len(self.file(f).read(other)) |
|
|||
1934 | self.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1) |
|
|||
1935 |
|
||||
1936 | remove.sort() |
|
|||
1937 | for f in remove: |
|
|||
1938 | self.ui.note(_("removing %s\n") % f) |
|
|||
1939 | util.audit_path(f) |
|
|||
1940 | try: |
|
|||
1941 | util.unlink(self.wjoin(f)) |
|
|||
1942 | except OSError, inst: |
|
|||
1943 | if inst.errno != errno.ENOENT: |
|
|||
1944 | self.ui.warn(_("update failed to remove %s: %s!\n") % |
|
|||
1945 | (f, inst.strerror)) |
|
|||
1946 | if moddirstate: |
|
|||
1947 | if branch_merge: |
|
|||
1948 | self.dirstate.update(remove, 'r') |
|
|||
1949 | else: |
|
|||
1950 | self.dirstate.forget(remove) |
|
|||
1951 |
|
||||
1952 | if moddirstate: |
|
|||
1953 | self.dirstate.setparents(p1, p2) |
|
|||
1954 |
|
||||
1955 | if show_stats: |
|
|||
1956 | stats = ((len(get), _("updated")), |
|
|||
1957 | (len(merge) - len(failedmerge), _("merged")), |
|
|||
1958 | (len(remove), _("removed")), |
|
|||
1959 | (len(failedmerge), _("unresolved"))) |
|
|||
1960 | note = ", ".join([_("%d files %s") % s for s in stats]) |
|
|||
1961 | self.ui.status("%s\n" % note) |
|
|||
1962 | if moddirstate: |
|
|||
1963 | if branch_merge: |
|
|||
1964 | if failedmerge: |
|
|||
1965 | self.ui.status(_("There are unresolved merges," |
|
|||
1966 | " you can redo the full merge using:\n" |
|
|||
1967 | " hg update -C %s\n" |
|
|||
1968 | " hg merge %s\n" |
|
|||
1969 | % (self.changelog.rev(p1), |
|
|||
1970 | self.changelog.rev(p2)))) |
|
|||
1971 | else: |
|
|||
1972 | self.ui.status(_("(branch merge, don't forget to commit)\n")) |
|
|||
1973 | elif failedmerge: |
|
|||
1974 | self.ui.status(_("There are unresolved merges with" |
|
|||
1975 | " locally modified files.\n")) |
|
|||
1976 |
|
||||
1977 | self.hook('update', parent1=xp1, parent2=xxp2, error=int(err)) |
|
|||
1978 | return err |
|
|||
1979 |
|
||||
1980 | def merge3(self, fn, my, other, p1, p2): |
|
|||
1981 | """perform a 3-way merge in the working directory""" |
|
|||
1982 |
|
||||
1983 | def temp(prefix, node): |
|
|||
1984 | pre = "%s~%s." % (os.path.basename(fn), prefix) |
|
|||
1985 | (fd, name) = tempfile.mkstemp(prefix=pre) |
|
|||
1986 | f = os.fdopen(fd, "wb") |
|
|||
1987 | self.wwrite(fn, fl.read(node), f) |
|
|||
1988 | f.close() |
|
|||
1989 | return name |
|
|||
1990 |
|
||||
1991 | fl = self.file(fn) |
|
|||
1992 | base = fl.ancestor(my, other) |
|
|||
1993 | a = self.wjoin(fn) |
|
|||
1994 | b = temp("base", base) |
|
|||
1995 | c = temp("other", other) |
|
|||
1996 |
|
||||
1997 | self.ui.note(_("resolving %s\n") % fn) |
|
|||
1998 | self.ui.debug(_("file %s: my %s other %s ancestor %s\n") % |
|
|||
1999 | (fn, short(my), short(other), short(base))) |
|
|||
2000 |
|
||||
2001 | cmd = (os.environ.get("HGMERGE") or self.ui.config("ui", "merge") |
|
|||
2002 | or "hgmerge") |
|
|||
2003 | r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=self.root, |
|
|||
2004 | environ={'HG_FILE': fn, |
|
|||
2005 | 'HG_MY_NODE': p1, |
|
|||
2006 | 'HG_OTHER_NODE': p2, |
|
|||
2007 | 'HG_FILE_MY_NODE': hex(my), |
|
|||
2008 | 'HG_FILE_OTHER_NODE': hex(other), |
|
|||
2009 | 'HG_FILE_BASE_NODE': hex(base)}) |
|
|||
2010 | if r: |
|
|||
2011 | self.ui.warn(_("merging %s failed!\n") % fn) |
|
|||
2012 |
|
||||
2013 | os.unlink(b) |
|
|||
2014 | os.unlink(c) |
|
|||
2015 | return r |
|
|||
2016 |
|
||||
2017 | def verify(self): |
|
|||
2018 | filelinkrevs = {} |
|
|||
2019 | filenodes = {} |
|
|||
2020 | changesets = revisions = files = 0 |
|
|||
2021 | errors = [0] |
|
|||
2022 | warnings = [0] |
|
|||
2023 | neededmanifests = {} |
|
|||
2024 |
|
||||
2025 | def err(msg): |
|
|||
2026 | self.ui.warn(msg + "\n") |
|
|||
2027 | errors[0] += 1 |
|
|||
2028 |
|
||||
2029 | def warn(msg): |
|
|||
2030 | self.ui.warn(msg + "\n") |
|
|||
2031 | warnings[0] += 1 |
|
|||
2032 |
|
||||
2033 | def checksize(obj, name): |
|
|||
2034 | d = obj.checksize() |
|
|||
2035 | if d[0]: |
|
|||
2036 | err(_("%s data length off by %d bytes") % (name, d[0])) |
|
|||
2037 | if d[1]: |
|
|||
2038 | err(_("%s index contains %d extra bytes") % (name, d[1])) |
|
|||
2039 |
|
||||
2040 | def checkversion(obj, name): |
|
|||
2041 | if obj.version != revlog.REVLOGV0: |
|
|||
2042 | if not revlogv1: |
|
|||
2043 | warn(_("warning: `%s' uses revlog format 1") % name) |
|
|||
2044 | elif revlogv1: |
|
|||
2045 | warn(_("warning: `%s' uses revlog format 0") % name) |
|
|||
2046 |
|
||||
2047 | revlogv1 = self.revlogversion != revlog.REVLOGV0 |
|
|||
2048 | if self.ui.verbose or revlogv1 != self.revlogv1: |
|
|||
2049 | self.ui.status(_("repository uses revlog format %d\n") % |
|
|||
2050 | (revlogv1 and 1 or 0)) |
|
|||
2051 |
|
||||
2052 | seen = {} |
|
|||
2053 | self.ui.status(_("checking changesets\n")) |
|
|||
2054 | checksize(self.changelog, "changelog") |
|
|||
2055 |
|
||||
2056 | for i in range(self.changelog.count()): |
|
|||
2057 | changesets += 1 |
|
|||
2058 | n = self.changelog.node(i) |
|
|||
2059 | l = self.changelog.linkrev(n) |
|
|||
2060 | if l != i: |
|
|||
2061 | err(_("incorrect link (%d) for changeset revision %d") %(l, i)) |
|
|||
2062 | if n in seen: |
|
|||
2063 | err(_("duplicate changeset at revision %d") % i) |
|
|||
2064 | seen[n] = 1 |
|
|||
2065 |
|
||||
2066 | for p in self.changelog.parents(n): |
|
|||
2067 | if p not in self.changelog.nodemap: |
|
|||
2068 | err(_("changeset %s has unknown parent %s") % |
|
|||
2069 | (short(n), short(p))) |
|
|||
2070 | try: |
|
|||
2071 | changes = self.changelog.read(n) |
|
|||
2072 | except KeyboardInterrupt: |
|
|||
2073 | self.ui.warn(_("interrupted")) |
|
|||
2074 | raise |
|
|||
2075 | except Exception, inst: |
|
|||
2076 | err(_("unpacking changeset %s: %s") % (short(n), inst)) |
|
|||
2077 | continue |
|
|||
2078 |
|
||||
2079 | neededmanifests[changes[0]] = n |
|
|||
2080 |
|
||||
2081 | for f in changes[3]: |
|
|||
2082 | filelinkrevs.setdefault(f, []).append(i) |
|
|||
2083 |
|
||||
2084 | seen = {} |
|
|||
2085 | self.ui.status(_("checking manifests\n")) |
|
|||
2086 | checkversion(self.manifest, "manifest") |
|
|||
2087 | checksize(self.manifest, "manifest") |
|
|||
2088 |
|
||||
2089 | for i in range(self.manifest.count()): |
|
|||
2090 | n = self.manifest.node(i) |
|
|||
2091 | l = self.manifest.linkrev(n) |
|
|||
2092 |
|
||||
2093 | if l < 0 or l >= self.changelog.count(): |
|
|||
2094 | err(_("bad manifest link (%d) at revision %d") % (l, i)) |
|
|||
2095 |
|
||||
2096 | if n in neededmanifests: |
|
|||
2097 | del neededmanifests[n] |
|
|||
2098 |
|
||||
2099 | if n in seen: |
|
|||
2100 | err(_("duplicate manifest at revision %d") % i) |
|
|||
2101 |
|
||||
2102 | seen[n] = 1 |
|
|||
2103 |
|
||||
2104 | for p in self.manifest.parents(n): |
|
|||
2105 | if p not in self.manifest.nodemap: |
|
|||
2106 | err(_("manifest %s has unknown parent %s") % |
|
|||
2107 | (short(n), short(p))) |
|
|||
2108 |
|
||||
2109 | try: |
|
|||
2110 | delta = mdiff.patchtext(self.manifest.delta(n)) |
|
|||
2111 | except KeyboardInterrupt: |
|
|||
2112 | self.ui.warn(_("interrupted")) |
|
|||
2113 | raise |
|
|||
2114 | except Exception, inst: |
|
|||
2115 | err(_("unpacking manifest %s: %s") % (short(n), inst)) |
|
|||
2116 | continue |
|
|||
2117 |
|
||||
2118 | try: |
|
|||
2119 | ff = [ l.split('\0') for l in delta.splitlines() ] |
|
|||
2120 | for f, fn in ff: |
|
|||
2121 | filenodes.setdefault(f, {})[bin(fn[:40])] = 1 |
|
|||
2122 | except (ValueError, TypeError), inst: |
|
|||
2123 | err(_("broken delta in manifest %s: %s") % (short(n), inst)) |
|
|||
2124 |
|
||||
2125 | self.ui.status(_("crosschecking files in changesets and manifests\n")) |
|
|||
2126 |
|
||||
2127 | for m, c in neededmanifests.items(): |
|
|||
2128 | err(_("Changeset %s refers to unknown manifest %s") % |
|
|||
2129 | (short(m), short(c))) |
|
|||
2130 | del neededmanifests |
|
|||
2131 |
|
||||
2132 | for f in filenodes: |
|
|||
2133 | if f not in filelinkrevs: |
|
|||
2134 | err(_("file %s in manifest but not in changesets") % f) |
|
|||
2135 |
|
||||
2136 | for f in filelinkrevs: |
|
|||
2137 | if f not in filenodes: |
|
|||
2138 | err(_("file %s in changeset but not in manifest") % f) |
|
|||
2139 |
|
||||
2140 | self.ui.status(_("checking files\n")) |
|
|||
2141 | ff = filenodes.keys() |
|
|||
2142 | ff.sort() |
|
|||
2143 | for f in ff: |
|
|||
2144 | if f == "/dev/null": |
|
|||
2145 | continue |
|
|||
2146 | files += 1 |
|
|||
2147 | if not f: |
|
|||
2148 | err(_("file without name in manifest %s") % short(n)) |
|
|||
2149 | continue |
|
|||
2150 | fl = self.file(f) |
|
|||
2151 | checkversion(fl, f) |
|
|||
2152 | checksize(fl, f) |
|
|||
2153 |
|
||||
2154 | nodes = {nullid: 1} |
|
|||
2155 | seen = {} |
|
|||
2156 | for i in range(fl.count()): |
|
|||
2157 | revisions += 1 |
|
|||
2158 | n = fl.node(i) |
|
|||
2159 |
|
||||
2160 | if n in seen: |
|
|||
2161 | err(_("%s: duplicate revision %d") % (f, i)) |
|
|||
2162 | if n not in filenodes[f]: |
|
|||
2163 | err(_("%s: %d:%s not in manifests") % (f, i, short(n))) |
|
|||
2164 | else: |
|
|||
2165 | del filenodes[f][n] |
|
|||
2166 |
|
||||
2167 | flr = fl.linkrev(n) |
|
|||
2168 | if flr not in filelinkrevs.get(f, []): |
|
|||
2169 | err(_("%s:%s points to unexpected changeset %d") |
|
|||
2170 | % (f, short(n), flr)) |
|
|||
2171 | else: |
|
|||
2172 | filelinkrevs[f].remove(flr) |
|
|||
2173 |
|
||||
2174 | # verify contents |
|
|||
2175 | try: |
|
|||
2176 | t = fl.read(n) |
|
|||
2177 | except KeyboardInterrupt: |
|
|||
2178 | self.ui.warn(_("interrupted")) |
|
|||
2179 | raise |
|
|||
2180 | except Exception, inst: |
|
|||
2181 | err(_("unpacking file %s %s: %s") % (f, short(n), inst)) |
|
|||
2182 |
|
||||
2183 | # verify parents |
|
|||
2184 | (p1, p2) = fl.parents(n) |
|
|||
2185 | if p1 not in nodes: |
|
|||
2186 | err(_("file %s:%s unknown parent 1 %s") % |
|
|||
2187 | (f, short(n), short(p1))) |
|
|||
2188 | if p2 not in nodes: |
|
|||
2189 | err(_("file %s:%s unknown parent 2 %s") % |
|
|||
2190 | (f, short(n), short(p1))) |
|
|||
2191 | nodes[n] = 1 |
|
|||
2192 |
|
||||
2193 | # cross-check |
|
|||
2194 | for node in filenodes[f]: |
|
|||
2195 | err(_("node %s in manifests not in %s") % (hex(node), f)) |
|
|||
2196 |
|
||||
2197 | self.ui.status(_("%d files, %d changesets, %d total revisions\n") % |
|
|||
2198 | (files, changesets, revisions)) |
|
|||
2199 |
|
||||
2200 | if warnings[0]: |
|
|||
2201 | self.ui.warn(_("%d warnings encountered!\n") % warnings[0]) |
|
|||
2202 | if errors[0]: |
|
|||
2203 | self.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) |
|
|||
2204 | return 1 |
|
|||
2205 |
|
1688 | |||
2206 | def stream_in(self, remote): |
|
1689 | def stream_in(self, remote): | |
2207 | fp = remote.stream_out() |
|
1690 | fp = remote.stream_out() | |
@@ -2227,7 +1710,7 b' class localrepository(repo.repository):' | |||||
2227 | util.bytecount(total_bytes / elapsed))) |
|
1710 | util.bytecount(total_bytes / elapsed))) | |
2228 | self.reload() |
|
1711 | self.reload() | |
2229 | return len(self.heads()) + 1 |
|
1712 | return len(self.heads()) + 1 | |
2230 |
|
1713 | |||
2231 | def clone(self, remote, heads=[], stream=False): |
|
1714 | def clone(self, remote, heads=[], stream=False): | |
2232 | '''clone remote repository. |
|
1715 | '''clone remote repository. | |
2233 |
|
1716 | |||
@@ -2256,3 +1739,8 b' def aftertrans(base):' | |||||
2256 | os.path.join(p, "undo.dirstate")) |
|
1739 | os.path.join(p, "undo.dirstate")) | |
2257 | return a |
|
1740 | return a | |
2258 |
|
1741 | |||
|
1742 | def instance(ui, path, create): | |||
|
1743 | return localrepository(ui, util.drop_scheme('file', path), create) | |||
|
1744 | ||||
|
1745 | def islocal(path): | |||
|
1746 | return True |
@@ -1,6 +1,6 b'' | |||||
1 | # lock.py - simple locking scheme for mercurial |
|
1 | # lock.py - simple locking scheme for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,6 b'' | |||||
1 | # manifest.py - manifest revision class for mercurial |
|
1 | # manifest.py - manifest revision class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -10,6 +10,31 b' from i18n import gettext as _' | |||||
10 | from demandload import * |
|
10 | from demandload import * | |
11 | demandload(globals(), "array bisect struct") |
|
11 | demandload(globals(), "array bisect struct") | |
12 |
|
12 | |||
|
13 | class manifestdict(dict): | |||
|
14 | def __init__(self, mapping=None, flags=None): | |||
|
15 | if mapping is None: mapping = {} | |||
|
16 | if flags is None: flags = {} | |||
|
17 | dict.__init__(self, mapping) | |||
|
18 | self._flags = flags | |||
|
19 | def flags(self, f): | |||
|
20 | return self._flags.get(f, "") | |||
|
21 | def execf(self, f): | |||
|
22 | "test for executable in manifest flags" | |||
|
23 | return "x" in self.flags(f) | |||
|
24 | def linkf(self, f): | |||
|
25 | "test for symlink in manifest flags" | |||
|
26 | return "l" in self.flags(f) | |||
|
27 | def rawset(self, f, entry): | |||
|
28 | self[f] = bin(entry[:40]) | |||
|
29 | fl = entry[40:-1] | |||
|
30 | if fl: self._flags[f] = fl | |||
|
31 | def set(self, f, execf=False, linkf=False): | |||
|
32 | if linkf: self._flags[f] = "l" | |||
|
33 | elif execf: self._flags[f] = "x" | |||
|
34 | else: self._flags[f] = "" | |||
|
35 | def copy(self): | |||
|
36 | return manifestdict(dict.copy(self), dict.copy(self._flags)) | |||
|
37 | ||||
13 | class manifest(revlog): |
|
38 | class manifest(revlog): | |
14 | def __init__(self, opener, defversion=REVLOGV0): |
|
39 | def __init__(self, opener, defversion=REVLOGV0): | |
15 | self.mapcache = None |
|
40 | self.mapcache = None | |
@@ -18,26 +43,18 b' class manifest(revlog):' | |||||
18 | defversion) |
|
43 | defversion) | |
19 |
|
44 | |||
20 | def read(self, node): |
|
45 | def read(self, node): | |
21 |
if node == nullid: return |
|
46 | if node == nullid: return manifestdict() # don't upset local cache | |
22 | if self.mapcache and self.mapcache[0] == node: |
|
47 | if self.mapcache and self.mapcache[0] == node: | |
23 | return self.mapcache[1] |
|
48 | return self.mapcache[1] | |
24 | text = self.revision(node) |
|
49 | text = self.revision(node) | |
25 | map = {} |
|
|||
26 | flag = {} |
|
|||
27 | self.listcache = array.array('c', text) |
|
50 | self.listcache = array.array('c', text) | |
28 | lines = text.splitlines(1) |
|
51 | lines = text.splitlines(1) | |
|
52 | mapping = manifestdict() | |||
29 | for l in lines: |
|
53 | for l in lines: | |
30 | (f, n) = l.split('\0') |
|
54 | (f, n) = l.split('\0') | |
31 |
map |
|
55 | mapping.rawset(f, n) | |
32 | flag[f] = (n[40:-1] == "x") |
|
56 | self.mapcache = (node, mapping) | |
33 | self.mapcache = (node, map, flag) |
|
57 | return mapping | |
34 | return map |
|
|||
35 |
|
||||
36 | def readflags(self, node): |
|
|||
37 | if node == nullid: return {} # don't upset local cache |
|
|||
38 | if not self.mapcache or self.mapcache[0] != node: |
|
|||
39 | self.read(node) |
|
|||
40 | return self.mapcache[2] |
|
|||
41 |
|
58 | |||
42 | def diff(self, a, b): |
|
59 | def diff(self, a, b): | |
43 | return mdiff.textdiff(str(a), str(b)) |
|
60 | return mdiff.textdiff(str(a), str(b)) | |
@@ -86,7 +103,7 b' class manifest(revlog):' | |||||
86 | '''look up entry for a single file efficiently. |
|
103 | '''look up entry for a single file efficiently. | |
87 | return (node, flag) pair if found, (None, None) if not.''' |
|
104 | return (node, flag) pair if found, (None, None) if not.''' | |
88 | if self.mapcache and node == self.mapcache[0]: |
|
105 | if self.mapcache and node == self.mapcache[0]: | |
89 |
return self.mapcache[1].get(f), self.mapcache[ |
|
106 | return self.mapcache[1].get(f), self.mapcache[1].flags(f) | |
90 | text = self.revision(node) |
|
107 | text = self.revision(node) | |
91 | start, end = self._search(text, f) |
|
108 | start, end = self._search(text, f) | |
92 | if start == end: |
|
109 | if start == end: | |
@@ -95,7 +112,7 b' class manifest(revlog):' | |||||
95 | f, n = l.split('\0') |
|
112 | f, n = l.split('\0') | |
96 | return bin(n[:40]), n[40:-1] == 'x' |
|
113 | return bin(n[:40]), n[40:-1] == 'x' | |
97 |
|
114 | |||
98 |
def add(self, map |
|
115 | def add(self, map, transaction, link, p1=None, p2=None, | |
99 | changed=None): |
|
116 | changed=None): | |
100 | # apply the changes collected during the bisect loop to our addlist |
|
117 | # apply the changes collected during the bisect loop to our addlist | |
101 | # return a delta suitable for addrevision |
|
118 | # return a delta suitable for addrevision | |
@@ -123,9 +140,7 b' class manifest(revlog):' | |||||
123 |
|
140 | |||
124 | # if this is changed to support newlines in filenames, |
|
141 | # if this is changed to support newlines in filenames, | |
125 | # be sure to check the templates/ dir again (especially *-raw.tmpl) |
|
142 | # be sure to check the templates/ dir again (especially *-raw.tmpl) | |
126 | text = ["%s\000%s%s\n" % |
|
143 | text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files] | |
127 | (f, hex(map[f]), flags[f] and "x" or '') |
|
|||
128 | for f in files] |
|
|||
129 | self.listcache = array.array('c', "".join(text)) |
|
144 | self.listcache = array.array('c', "".join(text)) | |
130 | cachedelta = None |
|
145 | cachedelta = None | |
131 | else: |
|
146 | else: | |
@@ -151,8 +166,7 b' class manifest(revlog):' | |||||
151 | # bs will either be the index of the item or the insert point |
|
166 | # bs will either be the index of the item or the insert point | |
152 | start, end = self._search(addbuf, f, start) |
|
167 | start, end = self._search(addbuf, f, start) | |
153 | if w[1] == 0: |
|
168 | if w[1] == 0: | |
154 | l = "%s\000%s%s\n" % (f, hex(map[f]), |
|
169 | l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) | |
155 | flags[f] and "x" or '') |
|
|||
156 | else: |
|
170 | else: | |
157 | l = "" |
|
171 | l = "" | |
158 | if start == end and w[1] == 1: |
|
172 | if start == end and w[1] == 1: | |
@@ -183,6 +197,6 b' class manifest(revlog):' | |||||
183 |
|
197 | |||
184 | n = self.addrevision(buffer(self.listcache), transaction, link, p1, \ |
|
198 | n = self.addrevision(buffer(self.listcache), transaction, link, p1, \ | |
185 | p2, cachedelta) |
|
199 | p2, cachedelta) | |
186 |
self.mapcache = (n, map |
|
200 | self.mapcache = (n, map) | |
187 |
|
201 | |||
188 | return n |
|
202 | return n |
@@ -1,6 +1,6 b'' | |||||
1 | # mdiff.py - diff and patch routines for mercurial |
|
1 | # mdiff.py - diff and patch routines for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -19,14 +19,41 b' def splitnewlines(text):' | |||||
19 | lines[-1] = lines[-1][:-1] |
|
19 | lines[-1] = lines[-1][:-1] | |
20 | return lines |
|
20 | return lines | |
21 |
|
21 | |||
22 | def unidiff(a, ad, b, bd, fn, r=None, text=False, |
|
22 | class diffopts(object): | |
23 | showfunc=False, ignorews=False, ignorewsamount=False, |
|
23 | '''context is the number of context lines | |
24 | ignoreblanklines=False): |
|
24 | text treats all files as text | |
|
25 | showfunc enables diff -p output | |||
|
26 | git enables the git extended patch format | |||
|
27 | ignorews ignores all whitespace changes in the diff | |||
|
28 | ignorewsamount ignores changes in the amount of whitespace | |||
|
29 | ignoreblanklines ignores changes whose lines are all blank''' | |||
25 |
|
30 | |||
|
31 | defaults = { | |||
|
32 | 'context': 3, | |||
|
33 | 'text': False, | |||
|
34 | 'showfunc': True, | |||
|
35 | 'git': False, | |||
|
36 | 'ignorews': False, | |||
|
37 | 'ignorewsamount': False, | |||
|
38 | 'ignoreblanklines': False, | |||
|
39 | } | |||
|
40 | ||||
|
41 | __slots__ = defaults.keys() | |||
|
42 | ||||
|
43 | def __init__(self, **opts): | |||
|
44 | for k in self.__slots__: | |||
|
45 | v = opts.get(k) | |||
|
46 | if v is None: | |||
|
47 | v = self.defaults[k] | |||
|
48 | setattr(self, k, v) | |||
|
49 | ||||
|
50 | defaultopts = diffopts() | |||
|
51 | ||||
|
52 | def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts): | |||
26 | if not a and not b: return "" |
|
53 | if not a and not b: return "" | |
27 | epoch = util.datestr((0, 0)) |
|
54 | epoch = util.datestr((0, 0)) | |
28 |
|
55 | |||
29 | if not text and (util.binary(a) or util.binary(b)): |
|
56 | if not opts.text and (util.binary(a) or util.binary(b)): | |
30 | l = ['Binary file %s has changed\n' % fn] |
|
57 | l = ['Binary file %s has changed\n' % fn] | |
31 | elif not a: |
|
58 | elif not a: | |
32 | b = splitnewlines(b) |
|
59 | b = splitnewlines(b) | |
@@ -49,10 +76,7 b' def unidiff(a, ad, b, bd, fn, r=None, te' | |||||
49 | else: |
|
76 | else: | |
50 | al = splitnewlines(a) |
|
77 | al = splitnewlines(a) | |
51 | bl = splitnewlines(b) |
|
78 | bl = splitnewlines(b) | |
52 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, |
|
79 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts)) | |
53 | showfunc=showfunc, ignorews=ignorews, |
|
|||
54 | ignorewsamount=ignorewsamount, |
|
|||
55 | ignoreblanklines=ignoreblanklines)) |
|
|||
56 | if not l: return "" |
|
80 | if not l: return "" | |
57 | # difflib uses a space, rather than a tab |
|
81 | # difflib uses a space, rather than a tab | |
58 | l[0] = "%s\t%s\n" % (l[0][:-2], ad) |
|
82 | l[0] = "%s\t%s\n" % (l[0][:-2], ad) | |
@@ -72,21 +96,15 b' def unidiff(a, ad, b, bd, fn, r=None, te' | |||||
72 | # t1 and t2 are the text to be diffed |
|
96 | # t1 and t2 are the text to be diffed | |
73 | # l1 and l2 are the text broken up into lines |
|
97 | # l1 and l2 are the text broken up into lines | |
74 | # header1 and header2 are the filenames for the diff output |
|
98 | # header1 and header2 are the filenames for the diff output | |
75 | # context is the number of context lines |
|
99 | def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts): | |
76 | # showfunc enables diff -p output |
|
|||
77 | # ignorews ignores all whitespace changes in the diff |
|
|||
78 | # ignorewsamount ignores changes in the amount of whitespace |
|
|||
79 | # ignoreblanklines ignores changes whose lines are all blank |
|
|||
80 | def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False, |
|
|||
81 | ignorews=False, ignorewsamount=False, ignoreblanklines=False): |
|
|||
82 | def contextend(l, len): |
|
100 | def contextend(l, len): | |
83 | ret = l + context |
|
101 | ret = l + opts.context | |
84 | if ret > len: |
|
102 | if ret > len: | |
85 | ret = len |
|
103 | ret = len | |
86 | return ret |
|
104 | return ret | |
87 |
|
105 | |||
88 | def contextstart(l): |
|
106 | def contextstart(l): | |
89 | ret = l - context |
|
107 | ret = l - opts.context | |
90 | if ret < 0: |
|
108 | if ret < 0: | |
91 | return 0 |
|
109 | return 0 | |
92 | return ret |
|
110 | return ret | |
@@ -101,7 +119,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||||
101 | blen = b2 - bstart + aend - a2 |
|
119 | blen = b2 - bstart + aend - a2 | |
102 |
|
120 | |||
103 | func = "" |
|
121 | func = "" | |
104 | if showfunc: |
|
122 | if opts.showfunc: | |
105 | # walk backwards from the start of the context |
|
123 | # walk backwards from the start of the context | |
106 | # to find a line starting with an alphanumeric char. |
|
124 | # to find a line starting with an alphanumeric char. | |
107 | for x in xrange(astart, -1, -1): |
|
125 | for x in xrange(astart, -1, -1): | |
@@ -119,14 +137,14 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||||
119 |
|
137 | |||
120 | header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] |
|
138 | header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] | |
121 |
|
139 | |||
122 | if showfunc: |
|
140 | if opts.showfunc: | |
123 | funcre = re.compile('\w') |
|
141 | funcre = re.compile('\w') | |
124 | if ignorewsamount: |
|
142 | if opts.ignorewsamount: | |
125 | wsamountre = re.compile('[ \t]+') |
|
143 | wsamountre = re.compile('[ \t]+') | |
126 | wsappendedre = re.compile(' \n') |
|
144 | wsappendedre = re.compile(' \n') | |
127 | if ignoreblanklines: |
|
145 | if opts.ignoreblanklines: | |
128 | wsblanklinesre = re.compile('\n') |
|
146 | wsblanklinesre = re.compile('\n') | |
129 | if ignorews: |
|
147 | if opts.ignorews: | |
130 | wsre = re.compile('[ \t]') |
|
148 | wsre = re.compile('[ \t]') | |
131 |
|
149 | |||
132 | # bdiff.blocks gives us the matching sequences in the files. The loop |
|
150 | # bdiff.blocks gives us the matching sequences in the files. The loop | |
@@ -159,13 +177,13 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||||
159 | if not old and not new: |
|
177 | if not old and not new: | |
160 | continue |
|
178 | continue | |
161 |
|
179 | |||
162 | if ignoreblanklines: |
|
180 | if opts.ignoreblanklines: | |
163 | wsold = wsblanklinesre.sub('', "".join(old)) |
|
181 | wsold = wsblanklinesre.sub('', "".join(old)) | |
164 | wsnew = wsblanklinesre.sub('', "".join(new)) |
|
182 | wsnew = wsblanklinesre.sub('', "".join(new)) | |
165 | if wsold == wsnew: |
|
183 | if wsold == wsnew: | |
166 | continue |
|
184 | continue | |
167 |
|
185 | |||
168 | if ignorewsamount: |
|
186 | if opts.ignorewsamount: | |
169 | wsold = wsamountre.sub(' ', "".join(old)) |
|
187 | wsold = wsamountre.sub(' ', "".join(old)) | |
170 | wsold = wsappendedre.sub('\n', wsold) |
|
188 | wsold = wsappendedre.sub('\n', wsold) | |
171 | wsnew = wsamountre.sub(' ', "".join(new)) |
|
189 | wsnew = wsamountre.sub(' ', "".join(new)) | |
@@ -173,7 +191,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||||
173 | if wsold == wsnew: |
|
191 | if wsold == wsnew: | |
174 | continue |
|
192 | continue | |
175 |
|
193 | |||
176 | if ignorews: |
|
194 | if opts.ignorews: | |
177 | wsold = wsre.sub('', "".join(old)) |
|
195 | wsold = wsre.sub('', "".join(old)) | |
178 | wsnew = wsre.sub('', "".join(new)) |
|
196 | wsnew = wsre.sub('', "".join(new)) | |
179 | if wsold == wsnew: |
|
197 | if wsold == wsnew: | |
@@ -184,7 +202,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||||
184 | prev = None |
|
202 | prev = None | |
185 | if hunk: |
|
203 | if hunk: | |
186 | # join with the previous hunk if it falls inside the context |
|
204 | # join with the previous hunk if it falls inside the context | |
187 | if astart < hunk[1] + context + 1: |
|
205 | if astart < hunk[1] + opts.context + 1: | |
188 | prev = hunk |
|
206 | prev = hunk | |
189 | astart = hunk[1] |
|
207 | astart = hunk[1] | |
190 | bstart = hunk[3] |
|
208 | bstart = hunk[3] |
@@ -14,7 +14,7 b'' | |||||
14 | allocation of intermediate Python objects. Working memory is about 2x |
|
14 | allocation of intermediate Python objects. Working memory is about 2x | |
15 | the total number of hunks. |
|
15 | the total number of hunks. | |
16 |
|
16 | |||
17 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
17 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
18 |
|
18 | |||
19 | This software may be used and distributed according to the terms |
|
19 | This software may be used and distributed according to the terms | |
20 | of the GNU General Public License, incorporated herein by reference. |
|
20 | of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||||
1 | """ |
|
1 | """ | |
2 | node.py - basic nodeid manipulation for mercurial |
|
2 | node.py - basic nodeid manipulation for mercurial | |
3 |
|
3 | |||
4 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
5 |
|
5 | |||
6 | This software may be used and distributed according to the terms |
|
6 | This software may be used and distributed according to the terms | |
7 | of the GNU General Public License, incorporated herein by reference. |
|
7 | of the GNU General Public License, incorporated herein by reference. |
@@ -2,7 +2,7 b'' | |||||
2 | # Used for the py2exe distutil. |
|
2 | # Used for the py2exe distutil. | |
3 | # This module must be the first mercurial module imported in setup.py |
|
3 | # This module must be the first mercurial module imported in setup.py | |
4 | # |
|
4 | # | |
5 | # Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de> |
|
5 | # Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de> | |
6 | # |
|
6 | # | |
7 | # This software may be used and distributed according to the terms |
|
7 | # This software may be used and distributed according to the terms | |
8 | # of the GNU General Public License, incorporated herein by reference. |
|
8 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,6 b'' | |||||
1 |
# remoterepo - remote repositor |
|
1 | # remoterepo - remote repository proxy classes for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,7 b'' | |||||
1 | # repo.py - repository base classes for mercurial |
|
1 | # repo.py - repository base classes for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
4 | # |
|
5 | # | |
5 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -4,7 +4,7 b' revlog.py - storage back-end for mercuri' | |||||
4 | This provides efficient delta storage with O(1) retrieve and append |
|
4 | This provides efficient delta storage with O(1) retrieve and append | |
5 | and O(changes) merge between branches |
|
5 | and O(changes) merge between branches | |
6 |
|
6 | |||
7 | Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
7 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
8 |
|
8 | |||
9 | This software may be used and distributed according to the terms |
|
9 | This software may be used and distributed according to the terms | |
10 | of the GNU General Public License, incorporated herein by reference. |
|
10 | of the GNU General Public License, incorporated herein by reference. | |
@@ -469,7 +469,8 b' class revlog(object):' | |||||
469 | return self.nodemap[node] |
|
469 | return self.nodemap[node] | |
470 | except KeyError: |
|
470 | except KeyError: | |
471 | raise RevlogError(_('%s: no node %s') % (self.indexfile, hex(node))) |
|
471 | raise RevlogError(_('%s: no node %s') % (self.indexfile, hex(node))) | |
472 | def linkrev(self, node): return self.index[self.rev(node)][-4] |
|
472 | def linkrev(self, node): | |
|
473 | return (node == nullid) and -1 or self.index[self.rev(node)][-4] | |||
473 | def parents(self, node): |
|
474 | def parents(self, node): | |
474 | if node == nullid: return (nullid, nullid) |
|
475 | if node == nullid: return (nullid, nullid) | |
475 | r = self.rev(node) |
|
476 | r = self.rev(node) | |
@@ -743,13 +744,8 b' class revlog(object):' | |||||
743 |
|
744 | |||
744 | def lookup(self, id): |
|
745 | def lookup(self, id): | |
745 | """locate a node based on revision number or subset of hex nodeid""" |
|
746 | """locate a node based on revision number or subset of hex nodeid""" | |
746 | if id in self.nodemap: |
|
|||
747 | return id |
|
|||
748 | if type(id) == type(0): |
|
747 | if type(id) == type(0): | |
749 |
re |
|
748 | return self.node(id) | |
750 | if rev < 0: rev = self.count() + rev |
|
|||
751 | if rev < 0 or rev >= self.count(): return None |
|
|||
752 | return self.node(rev) |
|
|||
753 | try: |
|
749 | try: | |
754 | rev = int(id) |
|
750 | rev = int(id) | |
755 | if str(rev) != id: raise ValueError |
|
751 | if str(rev) != id: raise ValueError | |
@@ -762,10 +758,26 b' class revlog(object):' | |||||
762 | if hex(n).startswith(id): |
|
758 | if hex(n).startswith(id): | |
763 | c.append(n) |
|
759 | c.append(n) | |
764 | if len(c) > 1: raise RevlogError(_("Ambiguous identifier")) |
|
760 | if len(c) > 1: raise RevlogError(_("Ambiguous identifier")) | |
765 | if len(c) < 1: raise RevlogError(_("No match found")) |
|
761 | if len(c) == 1: return c[0] | |
766 | return c[0] |
|
762 | ||
|
763 | # might need fixing if we change hash lengths | |||
|
764 | if len(id) == 20 and id in self.nodemap: | |||
|
765 | return id | |||
|
766 | ||||
|
767 | raise RevlogError(_("No match found")) | |||
767 |
|
768 | |||
768 | return None |
|
769 | def cmp(self, node, text): | |
|
770 | """compare text with a given file revision""" | |||
|
771 | p1, p2 = self.parents(node) | |||
|
772 | return hash(text, p1, p2) != node | |||
|
773 | ||||
|
774 | def makenode(self, node, text): | |||
|
775 | """calculate a file nodeid for text, descended or possibly | |||
|
776 | unchanged from node""" | |||
|
777 | ||||
|
778 | if self.cmp(node, text): | |||
|
779 | return hash(text, node, nullid) | |||
|
780 | return node | |||
769 |
|
781 | |||
770 | def diff(self, a, b): |
|
782 | def diff(self, a, b): | |
771 | """return a delta between two revisions""" |
|
783 | """return a delta between two revisions""" |
@@ -1,6 +1,6 b'' | |||||
1 | # sshrepo.py - ssh repository proxy class for mercurial |
|
1 | # sshrepo.py - ssh repository proxy class for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -13,7 +13,7 b' demandload(globals(), "hg os re stat uti' | |||||
13 |
|
13 | |||
14 | class sshrepository(remoterepository): |
|
14 | class sshrepository(remoterepository): | |
15 | def __init__(self, ui, path, create=0): |
|
15 | def __init__(self, ui, path, create=0): | |
16 | self.url = path |
|
16 | self._url = path | |
17 | self.ui = ui |
|
17 | self.ui = ui | |
18 |
|
18 | |||
19 | m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path) |
|
19 | m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path) | |
@@ -48,6 +48,9 b' class sshrepository(remoterepository):' | |||||
48 |
|
48 | |||
49 | self.validate_repo(ui, sshcmd, args, remotecmd) |
|
49 | self.validate_repo(ui, sshcmd, args, remotecmd) | |
50 |
|
50 | |||
|
51 | def url(self): | |||
|
52 | return self._url | |||
|
53 | ||||
51 | def validate_repo(self, ui, sshcmd, args, remotecmd): |
|
54 | def validate_repo(self, ui, sshcmd, args, remotecmd): | |
52 | cmd = '%s %s "%s -R %s serve --stdio"' |
|
55 | cmd = '%s %s "%s -R %s serve --stdio"' | |
53 | cmd = cmd % (sshcmd, args, remotecmd, self.path) |
|
56 | cmd = cmd % (sshcmd, args, remotecmd, self.path) | |
@@ -180,7 +183,7 b' class sshrepository(remoterepository):' | |||||
180 | return 1 |
|
183 | return 1 | |
181 | return int(r) |
|
184 | return int(r) | |
182 |
|
185 | |||
183 | def addchangegroup(self, cg, source): |
|
186 | def addchangegroup(self, cg, source, url): | |
184 | d = self.call("addchangegroup") |
|
187 | d = self.call("addchangegroup") | |
185 | if d: |
|
188 | if d: | |
186 | raise hg.RepoError(_("push refused: %s") % d) |
|
189 | raise hg.RepoError(_("push refused: %s") % d) | |
@@ -201,3 +204,5 b' class sshrepository(remoterepository):' | |||||
201 |
|
204 | |||
202 | def stream_out(self): |
|
205 | def stream_out(self): | |
203 | return self.do_cmd('stream_out') |
|
206 | return self.do_cmd('stream_out') | |
|
207 | ||||
|
208 | instance = sshrepository |
@@ -1,6 +1,7 b'' | |||||
1 | # sshserver.py - ssh protocol server support for mercurial |
|
1 | # sshserver.py - ssh protocol server support for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
4 | # |
|
5 | # | |
5 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
@@ -117,9 +118,13 b' class sshserver(object):' | |||||
117 | return |
|
118 | return | |
118 |
|
119 | |||
119 | self.respond("") |
|
120 | self.respond("") | |
120 | r = self.repo.addchangegroup(self.fin, 'serve') |
|
121 | r = self.repo.addchangegroup(self.fin, 'serve', self.client_url()) | |
121 | self.respond(str(r)) |
|
122 | self.respond(str(r)) | |
122 |
|
123 | |||
|
124 | def client_url(self): | |||
|
125 | client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0] | |||
|
126 | return 'remote:ssh:' + client | |||
|
127 | ||||
123 | def do_unbundle(self): |
|
128 | def do_unbundle(self): | |
124 | their_heads = self.getarg()[1].split() |
|
129 | their_heads = self.getarg()[1].split() | |
125 |
|
130 | |||
@@ -159,7 +164,7 b' class sshserver(object):' | |||||
159 | # push can proceed |
|
164 | # push can proceed | |
160 |
|
165 | |||
161 | fp.seek(0) |
|
166 | fp.seek(0) | |
162 | r = self.repo.addchangegroup(fp, 'serve') |
|
167 | r = self.repo.addchangegroup(fp, 'serve', self.client_url()) | |
163 | self.respond(str(r)) |
|
168 | self.respond(str(r)) | |
164 | finally: |
|
169 | finally: | |
165 | if not was_locked: |
|
170 | if not was_locked: |
@@ -2,14 +2,15 b'' | |||||
2 | # |
|
2 | # | |
3 | # This provides read-only repo access to repositories exported via static http |
|
3 | # This provides read-only repo access to repositories exported via static http | |
4 | # |
|
4 | # | |
5 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
5 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
6 | # |
|
6 | # | |
7 | # This software may be used and distributed according to the terms |
|
7 | # This software may be used and distributed according to the terms | |
8 | # of the GNU General Public License, incorporated herein by reference. |
|
8 | # of the GNU General Public License, incorporated herein by reference. | |
9 |
|
9 | |||
10 |
from demandload import |
|
10 | from demandload import * | |
|
11 | from i18n import gettext as _ | |||
11 | demandload(globals(), "changelog filelog httprangereader") |
|
12 | demandload(globals(), "changelog filelog httprangereader") | |
12 | demandload(globals(), "localrepo manifest os urllib urllib2") |
|
13 | demandload(globals(), "localrepo manifest os urllib urllib2 util") | |
13 |
|
14 | |||
14 | class rangereader(httprangereader.httprangereader): |
|
15 | class rangereader(httprangereader.httprangereader): | |
15 | def read(self, size=None): |
|
16 | def read(self, size=None): | |
@@ -30,6 +31,7 b' def opener(base):' | |||||
30 |
|
31 | |||
31 | class statichttprepository(localrepo.localrepository): |
|
32 | class statichttprepository(localrepo.localrepository): | |
32 | def __init__(self, ui, path): |
|
33 | def __init__(self, ui, path): | |
|
34 | self._url = path | |||
33 | self.path = (path + "/.hg") |
|
35 | self.path = (path + "/.hg") | |
34 | self.ui = ui |
|
36 | self.ui = ui | |
35 | self.revlogversion = 0 |
|
37 | self.revlogversion = 0 | |
@@ -41,8 +43,22 b' class statichttprepository(localrepo.loc' | |||||
41 | self.encodepats = None |
|
43 | self.encodepats = None | |
42 | self.decodepats = None |
|
44 | self.decodepats = None | |
43 |
|
45 | |||
|
46 | def url(self): | |||
|
47 | return 'static-' + self._url | |||
|
48 | ||||
44 | def dev(self): |
|
49 | def dev(self): | |
45 | return -1 |
|
50 | return -1 | |
46 |
|
51 | |||
47 | def local(self): |
|
52 | def local(self): | |
48 | return False |
|
53 | return False | |
|
54 | ||||
|
55 | def instance(ui, path, create): | |||
|
56 | if create: | |||
|
57 | raise util.Abort(_('cannot create new static-http repository')) | |||
|
58 | if path.startswith('old-http:'): | |||
|
59 | ui.warn(_("old-http:// syntax is deprecated, " | |||
|
60 | "please use static-http:// instead\n")) | |||
|
61 | path = path[4:] | |||
|
62 | else: | |||
|
63 | path = path[7:] | |||
|
64 | return statichttprepository(ui, path) |
@@ -241,6 +241,7 b' def nl2br(text):' | |||||
241 | return text.replace('\n', '<br/>\n') |
|
241 | return text.replace('\n', '<br/>\n') | |
242 |
|
242 | |||
243 | def obfuscate(text): |
|
243 | def obfuscate(text): | |
|
244 | text = unicode(text, 'utf-8', 'replace') | |||
244 | return ''.join(['&#%d;' % ord(c) for c in text]) |
|
245 | return ''.join(['&#%d;' % ord(c) for c in text]) | |
245 |
|
246 | |||
246 | def domain(author): |
|
247 | def domain(author): | |
@@ -458,7 +459,7 b' class changeset_templater(object):' | |||||
458 | yield x |
|
459 | yield x | |
459 |
|
460 | |||
460 | if self.ui.debugflag: |
|
461 | if self.ui.debugflag: | |
461 |
files = self.repo. |
|
462 | files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
462 | def showfiles(**args): |
|
463 | def showfiles(**args): | |
463 | for x in showlist('file', files[0], **args): yield x |
|
464 | for x in showlist('file', files[0], **args): yield x | |
464 | def showadds(**args): |
|
465 | def showadds(**args): |
@@ -6,7 +6,7 b'' | |||||
6 | # effectively log-structured, this should amount to simply truncating |
|
6 | # effectively log-structured, this should amount to simply truncating | |
7 | # anything that isn't referenced in the changelog. |
|
7 | # anything that isn't referenced in the changelog. | |
8 | # |
|
8 | # | |
9 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
9 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
10 | # |
|
10 | # | |
11 | # This software may be used and distributed according to the terms |
|
11 | # This software may be used and distributed according to the terms | |
12 | # of the GNU General Public License, incorporated herein by reference. |
|
12 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,22 +1,24 b'' | |||||
1 | # ui.py - user interface bits for mercurial |
|
1 | # ui.py - user interface bits for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms |
|
5 | # This software may be used and distributed according to the terms | |
6 | # of the GNU General Public License, incorporated herein by reference. |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
7 |
|
7 | |||
8 | from i18n import gettext as _ |
|
8 | from i18n import gettext as _ | |
9 | from demandload import * |
|
9 | from demandload import * | |
10 |
demandload(globals(), "errno getpass os re s |
|
10 | demandload(globals(), "errno getpass os re socket sys tempfile") | |
11 | demandload(globals(), "ConfigParser templater traceback util") |
|
11 | demandload(globals(), "ConfigParser mdiff templater traceback util") | |
12 |
|
12 | |||
13 | class ui(object): |
|
13 | class ui(object): | |
14 | def __init__(self, verbose=False, debug=False, quiet=False, |
|
14 | def __init__(self, verbose=False, debug=False, quiet=False, | |
15 |
interactive=True, traceback=False, parentui=None |
|
15 | interactive=True, traceback=False, parentui=None, | |
|
16 | readhooks=[]): | |||
16 | self.overlay = {} |
|
17 | self.overlay = {} | |
17 | if parentui is None: |
|
18 | if parentui is None: | |
18 | # this is the parent of all ui children |
|
19 | # this is the parent of all ui children | |
19 | self.parentui = None |
|
20 | self.parentui = None | |
|
21 | self.readhooks = list(readhooks) | |||
20 | self.cdata = ConfigParser.SafeConfigParser() |
|
22 | self.cdata = ConfigParser.SafeConfigParser() | |
21 | self.readconfig(util.rcpath()) |
|
23 | self.readconfig(util.rcpath()) | |
22 |
|
24 | |||
@@ -34,6 +36,7 b' class ui(object):' | |||||
34 | else: |
|
36 | else: | |
35 | # parentui may point to an ui object which is already a child |
|
37 | # parentui may point to an ui object which is already a child | |
36 | self.parentui = parentui.parentui or parentui |
|
38 | self.parentui = parentui.parentui or parentui | |
|
39 | self.readhooks = list(parentui.readhooks or readhooks) | |||
37 | parent_cdata = self.parentui.cdata |
|
40 | parent_cdata = self.parentui.cdata | |
38 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
41 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) | |
39 | # make interpolation work |
|
42 | # make interpolation work | |
@@ -78,6 +81,8 b' class ui(object):' | |||||
78 | for name, path in self.configitems("paths"): |
|
81 | for name, path in self.configitems("paths"): | |
79 | if path and "://" not in path and not os.path.isabs(path): |
|
82 | if path and "://" not in path and not os.path.isabs(path): | |
80 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
83 | self.cdata.set("paths", name, os.path.join(root, path)) | |
|
84 | for hook in self.readhooks: | |||
|
85 | hook(self) | |||
81 |
|
86 | |||
82 | def setconfig(self, section, name, val): |
|
87 | def setconfig(self, section, name, val): | |
83 | self.overlay[(section, name)] = val |
|
88 | self.overlay[(section, name)] = val | |
@@ -169,17 +174,6 b' class ui(object):' | |||||
169 | result[key.lower()] = value |
|
174 | result[key.lower()] = value | |
170 | return result |
|
175 | return result | |
171 |
|
176 | |||
172 | def diffopts(self): |
|
|||
173 | if self.diffcache: |
|
|||
174 | return self.diffcache |
|
|||
175 | result = {'showfunc': True, 'ignorews': False, |
|
|||
176 | 'ignorewsamount': False, 'ignoreblanklines': False} |
|
|||
177 | for key, value in self.configitems("diff"): |
|
|||
178 | if value: |
|
|||
179 | result[key.lower()] = (value.lower() == 'true') |
|
|||
180 | self.diffcache = result |
|
|||
181 | return result |
|
|||
182 |
|
||||
183 | def username(self): |
|
177 | def username(self): | |
184 | """Return default username to be used in commits. |
|
178 | """Return default username to be used in commits. | |
185 |
|
179 | |||
@@ -197,7 +191,7 b' class ui(object):' | |||||
197 | user = os.environ.get("EMAIL") |
|
191 | user = os.environ.get("EMAIL") | |
198 | if user is None: |
|
192 | if user is None: | |
199 | try: |
|
193 | try: | |
200 |
user = '%s@%s' % ( |
|
194 | user = '%s@%s' % (util.getuser(), socket.getfqdn()) | |
201 | except KeyError: |
|
195 | except KeyError: | |
202 | raise util.Abort(_("Please specify a username.")) |
|
196 | raise util.Abort(_("Please specify a username.")) | |
203 | return user |
|
197 | return user | |
@@ -217,12 +211,6 b' class ui(object):' | |||||
217 | path = self.config("paths", default) |
|
211 | path = self.config("paths", default) | |
218 | return path or loc |
|
212 | return path or loc | |
219 |
|
213 | |||
220 | def setconfig_remoteopts(self, **opts): |
|
|||
221 | if opts.get('ssh'): |
|
|||
222 | self.setconfig("ui", "ssh", opts['ssh']) |
|
|||
223 | if opts.get('remotecmd'): |
|
|||
224 | self.setconfig("ui", "remotecmd", opts['remotecmd']) |
|
|||
225 |
|
||||
226 | def write(self, *args): |
|
214 | def write(self, *args): | |
227 | if self.header: |
|
215 | if self.header: | |
228 | if self.header != self.prev_header: |
|
216 | if self.header != self.prev_header: | |
@@ -298,62 +286,6 b' class ui(object):' | |||||
298 |
|
286 | |||
299 | return t |
|
287 | return t | |
300 |
|
288 | |||
301 | def sendmail(self): |
|
|||
302 | '''send mail message. object returned has one method, sendmail. |
|
|||
303 | call as sendmail(sender, list-of-recipients, msg).''' |
|
|||
304 |
|
||||
305 | def smtp(): |
|
|||
306 | '''send mail using smtp.''' |
|
|||
307 |
|
||||
308 | local_hostname = self.config('smtp', 'local_hostname') |
|
|||
309 | s = smtplib.SMTP(local_hostname=local_hostname) |
|
|||
310 | mailhost = self.config('smtp', 'host') |
|
|||
311 | if not mailhost: |
|
|||
312 | raise util.Abort(_('no [smtp]host in hgrc - cannot send mail')) |
|
|||
313 | mailport = int(self.config('smtp', 'port', 25)) |
|
|||
314 | self.note(_('sending mail: smtp host %s, port %s\n') % |
|
|||
315 | (mailhost, mailport)) |
|
|||
316 | s.connect(host=mailhost, port=mailport) |
|
|||
317 | if self.configbool('smtp', 'tls'): |
|
|||
318 | self.note(_('(using tls)\n')) |
|
|||
319 | s.ehlo() |
|
|||
320 | s.starttls() |
|
|||
321 | s.ehlo() |
|
|||
322 | username = self.config('smtp', 'username') |
|
|||
323 | password = self.config('smtp', 'password') |
|
|||
324 | if username and password: |
|
|||
325 | self.note(_('(authenticating to mail server as %s)\n') % |
|
|||
326 | (username)) |
|
|||
327 | s.login(username, password) |
|
|||
328 | return s |
|
|||
329 |
|
||||
330 | class sendmail(object): |
|
|||
331 | '''send mail using sendmail.''' |
|
|||
332 |
|
||||
333 | def __init__(self, ui, program): |
|
|||
334 | self.ui = ui |
|
|||
335 | self.program = program |
|
|||
336 |
|
||||
337 | def sendmail(self, sender, recipients, msg): |
|
|||
338 | cmdline = '%s -f %s %s' % ( |
|
|||
339 | self.program, templater.email(sender), |
|
|||
340 | ' '.join(map(templater.email, recipients))) |
|
|||
341 | self.ui.note(_('sending mail: %s\n') % cmdline) |
|
|||
342 | fp = os.popen(cmdline, 'w') |
|
|||
343 | fp.write(msg) |
|
|||
344 | ret = fp.close() |
|
|||
345 | if ret: |
|
|||
346 | raise util.Abort('%s %s' % ( |
|
|||
347 | os.path.basename(self.program.split(None, 1)[0]), |
|
|||
348 | util.explain_exit(ret)[0])) |
|
|||
349 |
|
||||
350 | method = self.config('email', 'method', 'smtp') |
|
|||
351 | if method == 'smtp': |
|
|||
352 | mail = smtp() |
|
|||
353 | else: |
|
|||
354 | mail = sendmail(self, method) |
|
|||
355 | return mail |
|
|||
356 |
|
||||
357 | def print_exc(self): |
|
289 | def print_exc(self): | |
358 | '''print exception traceback if traceback printing enabled. |
|
290 | '''print exception traceback if traceback printing enabled. | |
359 | only to call in exception handler. returns true if traceback |
|
291 | only to call in exception handler. returns true if traceback |
@@ -2,6 +2,8 b'' | |||||
2 | util.py - Mercurial utility functions and platform specfic implementations |
|
2 | util.py - Mercurial utility functions and platform specfic implementations | |
3 |
|
3 | |||
4 | Copyright 2005 K. Thananchayan <thananck@yahoo.com> |
|
4 | Copyright 2005 K. Thananchayan <thananck@yahoo.com> | |
|
5 | Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |||
|
6 | Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |||
5 |
|
7 | |||
6 | This software may be used and distributed according to the terms |
|
8 | This software may be used and distributed according to the terms | |
7 | of the GNU General Public License, incorporated herein by reference. |
|
9 | of the GNU General Public License, incorporated herein by reference. | |
@@ -12,7 +14,7 b' platform-specific details from the core.' | |||||
12 |
|
14 | |||
13 | from i18n import gettext as _ |
|
15 | from i18n import gettext as _ | |
14 | from demandload import * |
|
16 | from demandload import * | |
15 | demandload(globals(), "cStringIO errno popen2 re shutil sys tempfile") |
|
17 | demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile") | |
16 | demandload(globals(), "os threading time") |
|
18 | demandload(globals(), "os threading time") | |
17 |
|
19 | |||
18 | # used by parsedate |
|
20 | # used by parsedate | |
@@ -93,23 +95,6 b' def find_in_path(name, path, default=Non' | |||||
93 | return p_name |
|
95 | return p_name | |
94 | return default |
|
96 | return default | |
95 |
|
97 | |||
96 | def patch(strip, patchname, ui): |
|
|||
97 | """apply the patch <patchname> to the working directory. |
|
|||
98 | a list of patched files is returned""" |
|
|||
99 | patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
|
|||
100 | fp = os.popen('%s -p%d < "%s"' % (patcher, strip, patchname)) |
|
|||
101 | files = {} |
|
|||
102 | for line in fp: |
|
|||
103 | line = line.rstrip() |
|
|||
104 | ui.status("%s\n" % line) |
|
|||
105 | if line.startswith('patching file '): |
|
|||
106 | pf = parse_patch_output(line) |
|
|||
107 | files.setdefault(pf, 1) |
|
|||
108 | code = fp.close() |
|
|||
109 | if code: |
|
|||
110 | raise Abort(_("patch command failed: %s") % explain_exit(code)[0]) |
|
|||
111 | return files.keys() |
|
|||
112 |
|
||||
113 | def binary(s): |
|
98 | def binary(s): | |
114 | """return true if a string is binary data using diff's heuristic""" |
|
99 | """return true if a string is binary data using diff's heuristic""" | |
115 | if s and '\0' in s[:4096]: |
|
100 | if s and '\0' in s[:4096]: | |
@@ -510,6 +495,20 b' def is_win_9x():' | |||||
510 | except AttributeError: |
|
495 | except AttributeError: | |
511 | return os.name == 'nt' and 'command' in os.environ.get('comspec', '') |
|
496 | return os.name == 'nt' and 'command' in os.environ.get('comspec', '') | |
512 |
|
497 | |||
|
498 | getuser_fallback = None | |||
|
499 | ||||
|
500 | def getuser(): | |||
|
501 | '''return name of current user''' | |||
|
502 | try: | |||
|
503 | return getpass.getuser() | |||
|
504 | except ImportError: | |||
|
505 | # import of pwd will fail on windows - try fallback | |||
|
506 | if getuser_fallback: | |||
|
507 | return getuser_fallback() | |||
|
508 | # raised if win32api not available | |||
|
509 | raise Abort(_('user name not available - set USERNAME ' | |||
|
510 | 'environment variable')) | |||
|
511 | ||||
513 | # Platform specific variants |
|
512 | # Platform specific variants | |
514 | if os.name == 'nt': |
|
513 | if os.name == 'nt': | |
515 | demandload(globals(), "msvcrt") |
|
514 | demandload(globals(), "msvcrt") | |
@@ -593,6 +592,9 b" if os.name == 'nt':" | |||||
593 | def samestat(s1, s2): |
|
592 | def samestat(s1, s2): | |
594 | return False |
|
593 | return False | |
595 |
|
594 | |||
|
595 | def shellquote(s): | |||
|
596 | return '"%s"' % s.replace('"', '\\"') | |||
|
597 | ||||
596 | def explain_exit(code): |
|
598 | def explain_exit(code): | |
597 | return _("exited with status %d") % code, code |
|
599 | return _("exited with status %d") % code, code | |
598 |
|
600 | |||
@@ -682,6 +684,9 b' else:' | |||||
682 | else: |
|
684 | else: | |
683 | raise |
|
685 | raise | |
684 |
|
686 | |||
|
687 | def shellquote(s): | |||
|
688 | return "'%s'" % s.replace("'", "'\\''") | |||
|
689 | ||||
685 | def testpid(pid): |
|
690 | def testpid(pid): | |
686 | '''return False if pid dead, True if running or not sure''' |
|
691 | '''return False if pid dead, True if running or not sure''' | |
687 | try: |
|
692 | try: | |
@@ -982,3 +987,11 b' def bytecount(nbytes):' | |||||
982 | if nbytes >= divisor * multiplier: |
|
987 | if nbytes >= divisor * multiplier: | |
983 | return format % (nbytes / float(divisor)) |
|
988 | return format % (nbytes / float(divisor)) | |
984 | return units[-1][2] % nbytes |
|
989 | return units[-1][2] % nbytes | |
|
990 | ||||
|
991 | def drop_scheme(scheme, path): | |||
|
992 | sc = scheme + ':' | |||
|
993 | if path.startswith(sc): | |||
|
994 | path = path[len(sc):] | |||
|
995 | if path.startswith('//'): | |||
|
996 | path = path[2:] | |||
|
997 | return path |
@@ -297,3 +297,5 b' class posixfile_nt(object):' | |||||
297 | win32file.SetEndOfFile(self.handle) |
|
297 | win32file.SetEndOfFile(self.handle) | |
298 | except pywintypes.error, err: |
|
298 | except pywintypes.error, err: | |
299 | raise WinIOError(err) |
|
299 | raise WinIOError(err) | |
|
300 | ||||
|
301 | getuser_fallback = win32api.GetUserName |
@@ -1,4 +1,4 b'' | |||||
1 | # Copyright (C) 2005 by Intevation GmbH |
|
1 | # Copyright (C) 2005, 2006 by Intevation GmbH | |
2 | # Author(s): |
|
2 | # Author(s): | |
3 | # Thomas Arendsen Hein <thomas@intevation.de> |
|
3 | # Thomas Arendsen Hein <thomas@intevation.de> | |
4 | # |
|
4 | # |
@@ -20,7 +20,7 b'' | |||||
20 | </div> |
|
20 | </div> | |
21 |
|
21 | |||
22 | <div class="page_nav"> |
|
22 | <div class="page_nav"> | |
23 | <a href="?cmd=summary;style=gitweb">summary</a> | changelog | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> |
|
23 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</a> | changelog | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#<br/> | |
24 | <br/> |
|
24 | <br/> | |
25 | #changenav%naventry#<br/> |
|
25 | #changenav%naventry#<br/> | |
26 | </div> |
|
26 | </div> |
@@ -6,6 +6,7 b'' | |||||
6 | <body> |
|
6 | <body> | |
7 |
|
7 | |||
8 | <div class="buttons"> |
|
8 | <div class="buttons"> | |
|
9 | <a href="?sl=#rev#">shortlog</a> | |||
9 | <a href="?cmd=tags">tags</a> |
|
10 | <a href="?cmd=tags">tags</a> | |
10 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
11 | <a href="?mf=#manifest|short#;path=/">manifest</a> | |
11 | #archives%archiveentry# |
|
12 | #archives%archiveentry# |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a> #archives%archiveentry#<br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a> #archives%archiveentry#<br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div> |
|
16 | <div> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=#rev#">changelog</a> |
|
7 | <a href="?cl=#rev#">changelog</a> | |
|
8 | <a href="?sl=#rev#">shortlog</a> | |||
8 | <a href="?cmd=tags">tags</a> |
|
9 | <a href="?cmd=tags">tags</a> | |
9 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
10 | <a href="?mf=#manifest|short#;path=/">manifest</a> | |
10 | <a href="?cs=#node|short#;style=raw">raw</a> |
|
11 | <a href="?cs=#node|short#;style=raw">raw</a> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div> |
|
16 | <div> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div class="title">#file|escape#</div> |
|
16 | <div class="title">#file|escape#</div> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=#rev#">changelog</a> |
|
7 | <a href="?cl=#rev#">changelog</a> | |
|
8 | <a href="?sl=#rev#">shortlog</a> | |||
8 | <a href="?tags=">tags</a> |
|
9 | <a href="?tags=">tags</a> | |
9 | <a href="?cs=#node|short#">changeset</a> |
|
10 | <a href="?cs=#node|short#">changeset</a> | |
10 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
|
11 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=#rev#">changelog</a> |
|
7 | <a href="?cl=#rev#">changelog</a> | |
|
8 | <a href="?sl=#rev#">shortlog</a> | |||
8 | <a href="?tags=">tags</a> |
|
9 | <a href="?tags=">tags</a> | |
9 | <a href="?cs=#node|short#">changeset</a> |
|
10 | <a href="?cs=#node|short#">changeset</a> | |
10 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> |
|
11 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=rss">rss</a><br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=rss">rss</a><br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div class="title" >#file|urlescape#</div> |
|
16 | <div class="title" >#file|urlescape#</div> |
@@ -8,6 +8,7 b'' | |||||
8 |
|
8 | |||
9 | <div class="buttons"> |
|
9 | <div class="buttons"> | |
10 | <a href="?cl=tip">changelog</a> |
|
10 | <a href="?cl=tip">changelog</a> | |
|
11 | <a href="?sl=tip">shortlog</a> | |||
11 | <a href="?tags=">tags</a> |
|
12 | <a href="?tags=">tags</a> | |
12 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> |
|
13 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> | |
13 | <a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a> |
|
14 | <a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div class="title">#file|escape#</div> |
|
16 | <div class="title">#file|escape#</div> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=#rev#">changelog</a> |
|
7 | <a href="?cl=#rev#">changelog</a> | |
|
8 | <a href="?sl=#rev#">shortlog</a> | |||
8 | <a href="?tags=">tags</a> |
|
9 | <a href="?tags=">tags</a> | |
9 | <a href="?cs=#node|short#">changeset</a> |
|
10 | <a href="?cs=#node|short#">changeset</a> | |
10 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
|
11 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a> #archives%archiveentry#<br/> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a> #archives%archiveentry#<br/> | |
14 | </div> |
|
14 | </div> | |
15 |
|
15 | |||
16 | <div class="title" >#path|escape#</div> |
|
16 | <div class="title" >#path|escape#</div> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=#rev#">changelog</a> |
|
7 | <a href="?cl=#rev#">changelog</a> | |
|
8 | <a href="?sl=#rev#">shortlog</a> | |||
8 | <a href="?tags=">tags</a> |
|
9 | <a href="?tags=">tags</a> | |
9 | <a href="?cs=#node|short#">changeset</a> |
|
10 | <a href="?cs=#node|short#">changeset</a> | |
10 | #archives%archiveentry# |
|
11 | #archives%archiveentry# |
@@ -3,7 +3,10 b' header = header.tmpl' | |||||
3 | footer = footer.tmpl |
|
3 | footer = footer.tmpl | |
4 | search = search.tmpl |
|
4 | search = search.tmpl | |
5 | changelog = changelog.tmpl |
|
5 | changelog = changelog.tmpl | |
|
6 | shortlog = shortlog.tmpl | |||
|
7 | shortlogentry = shortlogentry.tmpl | |||
6 | naventry = '<a href="?cl=#rev#">#label|escape#</a> ' |
|
8 | naventry = '<a href="?cl=#rev#">#label|escape#</a> ' | |
|
9 | navshortentry = '<a href="?sl=#rev#">#label|escape#</a> ' | |||
7 | filedifflink = '<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> ' |
|
10 | filedifflink = '<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> ' | |
8 | filenodelink = '<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> ' |
|
11 | filenodelink = '<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> ' | |
9 | fileellipses = '...' |
|
12 | fileellipses = '...' |
@@ -1,6 +1,6 b'' | |||||
1 | #header# |
|
1 | #header# | |
2 | <div class="page_nav"> |
|
2 | <div class="page_nav"> | |
3 | <a href="?cmd=summary;style=gitweb">summary</a> | log | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> |
|
3 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> | |
4 | </div> |
|
4 | </div> | |
5 |
|
5 | |||
6 | <h2>searching for #query|escape#</h2> |
|
6 | <h2>searching for #query|escape#</h2> |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | <div class="buttons"> |
|
6 | <div class="buttons"> | |
7 | <a href="?cl=tip">changelog</a> |
|
7 | <a href="?cl=tip">changelog</a> | |
|
8 | <a href="?sl=tip">shortlog</a> | |||
8 | <a href="?tags=">tags</a> |
|
9 | <a href="?tags=">tags</a> | |
9 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
10 | <a href="?mf=#manifest|short#;path=/">manifest</a> | |
10 | </div> |
|
11 | </div> |
@@ -1,13 +1,32 b'' | |||||
1 | #header# |
|
1 | #header# | |
|
2 | <title>#repo|escape#: Shortlog</title> | |||
|
3 | <link rel="alternate" type="application/rss+xml" | |||
|
4 | href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#"> | |||
|
5 | </head> | |||
|
6 | <body> | |||
2 |
|
7 | |||
|
8 | <div class="page_header"> | |||
|
9 | <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / shortlog | |||
|
10 | </div> | |||
|
11 | ||||
|
12 | <form action="#"> | |||
|
13 | <div class="search"> | |||
|
14 | <input type="hidden" name="repo" value="#repo|escape#" /> | |||
|
15 | <input type="hidden" name="style" value="gitweb" /> | |||
|
16 | <input type="hidden" name="cmd" value="changelog" /> | |||
|
17 | <input type="text" name="rev" /> | |||
|
18 | </div> | |||
|
19 | </form> | |||
|
20 | </div> | |||
3 | <div class="page_nav"> |
|
21 | <div class="page_nav"> | |
4 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">log</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/> |
|
22 | <a href="?cmd=summary;style=gitweb">summary</a> | shortlog | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#<br/> | |
|
23 | <br/> | |||
5 |
|
24 | |||
6 | #changenav%naventry#<br/> |
|
25 | #changenav%navshortentry#<br/> | |
7 | </div> |
|
26 | </div> | |
8 |
|
27 | |||
9 | <table cellspacing="0"> |
|
28 | <table cellspacing="0"> | |
10 | #entries# |
|
29 | #entries%shortlogentry# | |
11 | </table> |
|
30 | </table> | |
12 |
|
31 | |||
13 | #footer# |
|
32 | #footer# |
@@ -57,6 +57,12 b' pre { margin: 0; }' | |||||
57 | .logEntry th.age, .logEntry th.firstline { font-weight: bold; } |
|
57 | .logEntry th.age, .logEntry th.firstline { font-weight: bold; } | |
58 | .logEntry th.firstline { text-align: left; width: inherit; } |
|
58 | .logEntry th.firstline { text-align: left; width: inherit; } | |
59 |
|
59 | |||
|
60 | /* Shortlog entries */ | |||
|
61 | .slogEntry { width: 100%; font-size: smaller; } | |||
|
62 | .slogEntry .age { width: 7%; } | |||
|
63 | .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; } | |||
|
64 | .slogEntry td.author { width: 35%; } | |||
|
65 | ||||
60 | /* Tag entries */ |
|
66 | /* Tag entries */ | |
61 | #tagEntries { list-style: none; margin: 0; padding: 0; } |
|
67 | #tagEntries { list-style: none; margin: 0; padding: 0; } | |
62 | #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; } |
|
68 | #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; } |
@@ -9,7 +9,8 b'' | |||||
9 | <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / summary |
|
9 | <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / summary | |
10 | </div> |
|
10 | </div> | |
11 | <div class="page_nav"> |
|
11 | <div class="page_nav"> | |
12 |
summary | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> |
|
12 | summary | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry# | |
|
13 | <br/> | |||
13 | </div> |
|
14 | </div> | |
14 |
|
15 | |||
15 | <div class="title"> </div> |
|
16 | <div class="title"> </div> |
@@ -10,7 +10,7 b'' | |||||
10 | </div> |
|
10 | </div> | |
11 |
|
11 | |||
12 | <div class="page_nav"> |
|
12 | <div class="page_nav"> | |
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | tags | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> |
|
13 | <a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | tags | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | |
14 | <br/> |
|
14 | <br/> | |
15 | </div> |
|
15 | </div> | |
16 |
|
16 |
@@ -7,6 +7,7 b'' | |||||
7 |
|
7 | |||
8 | <div class="buttons"> |
|
8 | <div class="buttons"> | |
9 | <a href="?cl=tip">changelog</a> |
|
9 | <a href="?cl=tip">changelog</a> | |
|
10 | <a href="?sl=tip">shortlog</a> | |||
10 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
11 | <a href="?mf=#manifest|short#;path=/">manifest</a> | |
11 | <a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a> |
|
12 | <a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a> | |
12 | </div> |
|
13 | </div> |
@@ -28,6 +28,6 b' writing tests:' | |||||
28 |
|
28 | |||
29 | - diff will show the current time |
|
29 | - diff will show the current time | |
30 |
|
30 | |||
31 |
use hg diff | sed "s/\( |
|
31 | use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
32 | dates |
|
32 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |
33 |
|
33 | to strip dates |
@@ -25,7 +25,7 b' parser = optparse.OptionParser("%prog [o' | |||||
25 | parser.add_option("-v", "--verbose", action="store_true", |
|
25 | parser.add_option("-v", "--verbose", action="store_true", | |
26 | help="output verbose messages") |
|
26 | help="output verbose messages") | |
27 | parser.add_option("-t", "--timeout", type="int", |
|
27 | parser.add_option("-t", "--timeout", type="int", | |
28 | help="output verbose messages") |
|
28 | help="kill errant tests after TIMEOUT seconds") | |
29 | parser.add_option("-c", "--cover", action="store_true", |
|
29 | parser.add_option("-c", "--cover", action="store_true", | |
30 | help="print a test coverage report") |
|
30 | help="print a test coverage report") | |
31 | parser.add_option("-s", "--cover_stdlib", action="store_true", |
|
31 | parser.add_option("-s", "--cover_stdlib", action="store_true", | |
@@ -201,6 +201,11 b' def run(cmd):' | |||||
201 | return ret, splitnewlines(output) |
|
201 | return ret, splitnewlines(output) | |
202 |
|
202 | |||
203 | def run_one(test): |
|
203 | def run_one(test): | |
|
204 | '''tristate output: | |||
|
205 | None -> skipped | |||
|
206 | True -> passed | |||
|
207 | False -> failed''' | |||
|
208 | ||||
204 | vlog("# Test", test) |
|
209 | vlog("# Test", test) | |
205 | if not verbose: |
|
210 | if not verbose: | |
206 | sys.stdout.write('.') |
|
211 | sys.stdout.write('.') | |
@@ -217,15 +222,28 b' def run_one(test):' | |||||
217 | os.mkdir(tmpd) |
|
222 | os.mkdir(tmpd) | |
218 | os.chdir(tmpd) |
|
223 | os.chdir(tmpd) | |
219 |
|
224 | |||
220 | if test.endswith(".py"): |
|
225 | lctest = test.lower() | |
221 | cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test)) |
|
|||
222 | else: |
|
|||
223 | cmd = '"%s"' % (os.path.join(TESTDIR, test)) |
|
|||
224 |
|
226 | |||
225 | # To reliably get the error code from batch files on WinXP, |
|
227 | if lctest.endswith('.py'): | |
226 | # the "cmd /c call" prefix is needed. Grrr |
|
228 | cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test)) | |
227 |
if |
|
229 | elif lctest.endswith('.bat'): | |
|
230 | # do not run batch scripts on non-windows | |||
|
231 | if os.name != 'nt': | |||
|
232 | print '\nSkipping %s: batch script' % test | |||
|
233 | return None | |||
|
234 | # To reliably get the error code from batch files on WinXP, | |||
|
235 | # the "cmd /c call" prefix is needed. Grrr | |||
228 | cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test)) |
|
236 | cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test)) | |
|
237 | else: | |||
|
238 | # do not run shell scripts on windows | |||
|
239 | if os.name == 'nt': | |||
|
240 | print '\nSkipping %s: shell script' % test | |||
|
241 | return None | |||
|
242 | # do not try to run non-executable programs | |||
|
243 | if not os.access(os.path.join(TESTDIR, test), os.X_OK): | |||
|
244 | print '\nSkipping %s: not executable' % test | |||
|
245 | return None | |||
|
246 | cmd = '"%s"' % (os.path.join(TESTDIR, test)) | |||
229 |
|
247 | |||
230 | if options.timeout > 0: |
|
248 | if options.timeout > 0: | |
231 | signal.alarm(options.timeout) |
|
249 | signal.alarm(options.timeout) | |
@@ -244,7 +262,7 b' def run_one(test):' | |||||
244 | ref_out = splitnewlines(f.read()) |
|
262 | ref_out = splitnewlines(f.read()) | |
245 | f.close() |
|
263 | f.close() | |
246 | else: |
|
264 | else: | |
247 |
ref_out = [ |
|
265 | ref_out = [] | |
248 | if out != ref_out: |
|
266 | if out != ref_out: | |
249 | diffret = 1 |
|
267 | diffret = 1 | |
250 | print "\nERROR: %s output changed" % (test) |
|
268 | print "\nERROR: %s output changed" % (test) | |
@@ -330,16 +348,23 b' try:' | |||||
330 |
|
348 | |||
331 | tests = 0 |
|
349 | tests = 0 | |
332 | failed = 0 |
|
350 | failed = 0 | |
|
351 | skipped = 0 | |||
333 |
|
352 | |||
334 | if len(args) == 0: |
|
353 | if len(args) == 0: | |
335 | args = os.listdir(".") |
|
354 | args = os.listdir(".") | |
336 | for test in args: |
|
355 | for test in args: | |
337 |
if test.startswith("test-") and |
|
356 | if (test.startswith("test-") and '~' not in test and | |
338 | if not run_one(test): |
|
357 | ('.' not in test or test.endswith('.py') or | |
|
358 | test.endswith('.bat'))): | |||
|
359 | ret = run_one(test) | |||
|
360 | if ret is None: | |||
|
361 | skipped += 1 | |||
|
362 | elif not ret: | |||
339 | failed += 1 |
|
363 | failed += 1 | |
340 | tests += 1 |
|
364 | tests += 1 | |
341 |
|
365 | |||
342 |
print "\n# Ran %d tests, %d failed." % (tests, |
|
366 | print "\n# Ran %d tests, %d skipped, %d failed." % (tests, skipped, | |
|
367 | failed) | |||
343 | if coverage: |
|
368 | if coverage: | |
344 | output_coverage() |
|
369 | output_coverage() | |
345 | except KeyboardInterrupt: |
|
370 | except KeyboardInterrupt: |
@@ -27,7 +27,7 b' adding b' | |||||
27 | reverting a |
|
27 | reverting a | |
28 | changeset 3:4cbb1e70196a backs out changeset 1:22bca4c721e5 |
|
28 | changeset 3:4cbb1e70196a backs out changeset 1:22bca4c721e5 | |
29 | the backout changeset is a new head - do not forget to merge |
|
29 | the backout changeset is a new head - do not forget to merge | |
30 | (use "backout -m" if you want to auto-merge) |
|
30 | (use "backout --merge" if you want to auto-merge) | |
31 | b: No such file or directory |
|
31 | b: No such file or directory | |
32 | adding a |
|
32 | adding a | |
33 | adding b |
|
33 | adding b |
@@ -30,14 +30,20 b' cd ..' | |||||
30 | hg init empty |
|
30 | hg init empty | |
31 | hg -R test bundle full.hg empty |
|
31 | hg -R test bundle full.hg empty | |
32 | hg -R test unbundle full.hg |
|
32 | hg -R test unbundle full.hg | |
33 | hg -R empty unbundle full.hg |
|
|||
34 | hg -R empty heads |
|
33 | hg -R empty heads | |
35 | hg -R empty verify |
|
34 | hg -R empty verify | |
36 |
|
35 | |||
|
36 | hg --cwd test pull ../full.hg | |||
|
37 | hg --cwd empty pull ../full.hg | |||
|
38 | hg -R empty rollback | |||
|
39 | hg --cwd empty pull ../full.hg | |||
|
40 | ||||
37 | rm -rf empty |
|
41 | rm -rf empty | |
38 | hg init empty |
|
42 | hg init empty | |
39 | cd empty |
|
43 | cd empty | |
40 | hg -R bundle://../full.hg log |
|
44 | hg -R bundle://../full.hg log | |
|
45 | echo '[hooks]' >> .hg/hgrc | |||
|
46 | echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc | |||
41 | #doesn't work (yet ?) |
|
47 | #doesn't work (yet ?) | |
42 | #hg -R bundle://../full.hg verify |
|
48 | #hg -R bundle://../full.hg verify | |
43 | hg pull bundle://../full.hg |
|
49 | hg pull bundle://../full.hg |
@@ -11,28 +11,34 b' adding manifests' | |||||
11 | adding file changes |
|
11 | adding file changes | |
12 | added 0 changesets with 0 changes to 4 files |
|
12 | added 0 changesets with 0 changes to 4 files | |
13 | (run 'hg update' to get a working copy) |
|
13 | (run 'hg update' to get a working copy) | |
|
14 | changeset: -1:000000000000 | |||
|
15 | tag: tip | |||
|
16 | user: | |||
|
17 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
18 | ||||
|
19 | checking changesets | |||
|
20 | checking manifests | |||
|
21 | crosschecking files in changesets and manifests | |||
|
22 | checking files | |||
|
23 | 0 files, 0 changesets, 0 total revisions | |||
|
24 | pulling from ../full.hg | |||
|
25 | searching for changes | |||
|
26 | no changes found | |||
|
27 | pulling from ../full.hg | |||
|
28 | requesting all changes | |||
14 | adding changesets |
|
29 | adding changesets | |
15 | adding manifests |
|
30 | adding manifests | |
16 | adding file changes |
|
31 | adding file changes | |
17 | added 9 changesets with 7 changes to 4 files (+1 heads) |
|
32 | added 9 changesets with 7 changes to 4 files (+1 heads) | |
18 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
33 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
19 | changeset: 8:836ac62537ab |
|
34 | rolling back last transaction | |
20 | tag: tip |
|
35 | pulling from ../full.hg | |
21 | parent: 3:ac69c658229d |
|
36 | requesting all changes | |
22 | user: test |
|
37 | adding changesets | |
23 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
38 | adding manifests | |
24 | summary: 0.3m |
|
39 | adding file changes | |
25 |
|
40 | added 9 changesets with 7 changes to 4 files (+1 heads) | ||
26 | changeset: 7:80fe151401c2 |
|
41 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
27 | user: test |
|
|||
28 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
|||
29 | summary: 1.3m |
|
|||
30 |
|
||||
31 | checking changesets |
|
|||
32 | checking manifests |
|
|||
33 | crosschecking files in changesets and manifests |
|
|||
34 | checking files |
|
|||
35 | 4 files, 9 changesets, 7 total revisions |
|
|||
36 | changeset: 8:836ac62537ab |
|
42 | changeset: 8:836ac62537ab | |
37 | tag: tip |
|
43 | tag: tip | |
38 | parent: 3:ac69c658229d |
|
44 | parent: 3:ac69c658229d | |
@@ -81,6 +87,7 b' user: test' | |||||
81 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
87 | date: Mon Jan 12 13:46:40 1970 +0000 | |
82 | summary: 0.0 |
|
88 | summary: 0.0 | |
83 |
|
89 | |||
|
90 | changegroup: u=bundle:../full.hg | |||
84 | pulling from bundle://../full.hg |
|
91 | pulling from bundle://../full.hg | |
85 | requesting all changes |
|
92 | requesting all changes | |
86 | adding changesets |
|
93 | adding changesets |
@@ -45,7 +45,7 b' hg --cwd c head -v' | |||||
45 | hg --cwd b tip --verbose |
|
45 | hg --cwd b tip --verbose | |
46 |
|
46 | |||
47 | echo %% --config |
|
47 | echo %% --config | |
48 |
hg --cwd c --config paths.quuxfoo=bar paths | grep |
|
48 | hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo | |
49 | hg --cwd c --config '' tip -q |
|
49 | hg --cwd c --config '' tip -q | |
50 | hg --cwd c --config a.b tip -q |
|
50 | hg --cwd c --config a.b tip -q | |
51 | hg --cwd c --config a tip -q |
|
51 | hg --cwd c --config a tip -q |
@@ -18,6 +18,13 b' head -n 3 port > port1' | |||||
18 | mv port1 port |
|
18 | mv port1 port | |
19 | hg commit -m 4 -u spam -d '4 0' |
|
19 | hg commit -m 4 -u spam -d '4 0' | |
20 | hg grep port port |
|
20 | hg grep port port | |
21 | echo 'FIXME: history is wrong here' |
|
|||
22 | hg grep --all -nu port port |
|
21 | hg grep --all -nu port port | |
23 | hg grep import port |
|
22 | hg grep import port | |
|
23 | ||||
|
24 | hg cp port port2 | |||
|
25 | hg commit -m 4 -u spam -d '5 0' | |||
|
26 | echo '% follow' | |||
|
27 | hg grep -f 'import$' port2 | |||
|
28 | echo deport >> port2 | |||
|
29 | hg commit -m 5 -u eggs -d '6 0' | |||
|
30 | hg grep -f --all -nu port port2 |
@@ -1,10 +1,25 b'' | |||||
1 | port:4:export |
|
1 | port:4:export | |
2 | port:4:vaportight |
|
2 | port:4:vaportight | |
3 | port:4:import/export |
|
3 | port:4:import/export | |
4 | FIXME: history is wrong here |
|
4 | port:4:4:-:spam:import/export | |
5 |
port: |
|
5 | port:3:4:+:eggs:import/export | |
6 | port:1:2:+:eggs:vaportight |
|
6 | port:2:1:-:spam:import | |
7 |
port: |
|
7 | port:2:2:-:spam:export | |
8 |
port: |
|
8 | port:2:1:+:spam:export | |
9 |
port: |
|
9 | port:2:2:+:spam:vaportight | |
|
10 | port:2:3:+:spam:import/export | |||
|
11 | port:1:2:+:eggs:export | |||
|
12 | port:0:1:+:eggs:import | |||
10 | port:4:import/export |
|
13 | port:4:import/export | |
|
14 | % follow | |||
|
15 | port:0:import | |||
|
16 | port2:6:4:+:eggs:deport | |||
|
17 | port:4:4:-:spam:import/export | |||
|
18 | port:3:4:+:eggs:import/export | |||
|
19 | port:2:1:-:spam:import | |||
|
20 | port:2:2:-:spam:export | |||
|
21 | port:2:1:+:spam:export | |||
|
22 | port:2:2:+:spam:vaportight | |||
|
23 | port:2:3:+:spam:import/export | |||
|
24 | port:1:2:+:eggs:export | |||
|
25 | port:0:1:+:eggs:import |
@@ -178,6 +178,7 b' options:' | |||||
178 | -r --rev revision |
|
178 | -r --rev revision | |
179 | -a --text treat all files as text |
|
179 | -a --text treat all files as text | |
180 | -p --show-function show which function each change is in |
|
180 | -p --show-function show which function each change is in | |
|
181 | -g --git use git extended diff format | |||
181 | -w --ignore-all-space ignore white space when comparing lines |
|
182 | -w --ignore-all-space ignore white space when comparing lines | |
182 | -b --ignore-space-change ignore changes in the amount of white space |
|
183 | -b --ignore-space-change ignore changes in the amount of white space | |
183 | -B --ignore-blank-lines ignore changes whose lines are all blank |
|
184 | -B --ignore-blank-lines ignore changes whose lines are all blank | |
@@ -187,13 +188,15 b' hg status [OPTION]... [FILE]...' | |||||
187 |
|
188 | |||
188 | show changed files in the working directory |
|
189 | show changed files in the working directory | |
189 |
|
190 | |||
190 |
Show |
|
191 | Show status of files in the repository. If names are given, only | |
191 | given, only files that match are shown. |
|
192 | files that match are shown. Files that are clean or ignored, are | |
|
193 | not listed unless -c (clean), -i (ignored) or -A is given. | |||
192 |
|
194 | |||
193 | The codes used to show the status of files are: |
|
195 | The codes used to show the status of files are: | |
194 | M = modified |
|
196 | M = modified | |
195 | A = added |
|
197 | A = added | |
196 | R = removed |
|
198 | R = removed | |
|
199 | C = clean | |||
197 | ! = deleted, but still tracked |
|
200 | ! = deleted, but still tracked | |
198 | ? = not tracked |
|
201 | ? = not tracked | |
199 | I = ignored (not shown by default) |
|
202 | I = ignored (not shown by default) | |
@@ -203,10 +206,12 b' aliases: st' | |||||
203 |
|
206 | |||
204 | options: |
|
207 | options: | |
205 |
|
208 | |||
|
209 | -A --all show status of all files | |||
206 | -m --modified show only modified files |
|
210 | -m --modified show only modified files | |
207 | -a --added show only added files |
|
211 | -a --added show only added files | |
208 | -r --removed show only removed files |
|
212 | -r --removed show only removed files | |
209 | -d --deleted show only deleted (but tracked) files |
|
213 | -d --deleted show only deleted (but tracked) files | |
|
214 | -c --clean show only files without changes | |||
210 | -u --unknown show only unknown (not tracked) files |
|
215 | -u --unknown show only unknown (not tracked) files | |
211 | -i --ignored show ignored files |
|
216 | -i --ignored show ignored files | |
212 | -n --no-status hide status prefix |
|
217 | -n --no-status hide status prefix |
@@ -17,9 +17,9 b' cd ../b' | |||||
17 |
|
17 | |||
18 | # changegroup hooks can see env vars |
|
18 | # changegroup hooks can see env vars | |
19 | echo '[hooks]' > .hg/hgrc |
|
19 | echo '[hooks]' > .hg/hgrc | |
20 | echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc |
|
20 | echo 'prechangegroup = echo prechangegroup hook: u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc | |
21 | echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc |
|
21 | echo 'changegroup = echo changegroup hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc | |
22 | echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc |
|
22 | echo 'incoming = echo incoming hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc | |
23 |
|
23 | |||
24 | # pretxncommit and commit hooks can see both parents of merge |
|
24 | # pretxncommit and commit hooks can see both parents of merge | |
25 | cd ../a |
|
25 | cd ../a |
@@ -22,11 +22,11 b' pretxncommit hook: n=4c52fb2e402287dd5dc' | |||||
22 | 3:4c52fb2e4022 |
|
22 | 3:4c52fb2e4022 | |
23 | commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2 |
|
23 | commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2 | |
24 | commit hook b |
|
24 | commit hook b | |
25 | prechangegroup hook |
|
25 | prechangegroup hook: u=file: | |
26 | changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 |
|
26 | changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: | |
27 | incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 |
|
27 | incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: | |
28 | incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb |
|
28 | incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file: | |
29 | incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 |
|
29 | incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file: | |
30 | pulling from ../a |
|
30 | pulling from ../a | |
31 | searching for changes |
|
31 | searching for changes | |
32 | adding changesets |
|
32 | adding changesets |
@@ -4,22 +4,31 b' hg init test' | |||||
4 | cd test |
|
4 | cd test | |
5 | echo foo>foo |
|
5 | echo foo>foo | |
6 | hg commit -A -d '0 0' -m 1 |
|
6 | hg commit -A -d '0 0' -m 1 | |
7 | hg --config server.uncompressed=True serve -p 20059 -d --pid-file=hg1.pid |
|
7 | hg --config server.uncompressed=True serve -p 20059 -d --pid-file=../hg1.pid | |
8 | cat hg1.pid >> $DAEMON_PIDS |
|
8 | hg serve -p 20060 -d --pid-file=../hg2.pid | |
9 | hg serve -p 20060 -d --pid-file=hg2.pid |
|
|||
10 | cat hg2.pid >> $DAEMON_PIDS |
|
|||
11 | cd .. |
|
9 | cd .. | |
|
10 | cat hg1.pid hg2.pid >> $DAEMON_PIDS | |||
12 |
|
11 | |||
13 | echo % clone via stream |
|
12 | echo % clone via stream | |
14 | http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ |
|
13 | http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ | |
15 | sed -e 's/[0-9][0-9.]*/XXX/g' |
|
14 | sed -e 's/[0-9][0-9.]*/XXX/g' | |
16 | cd copy |
|
15 | hg verify -R copy | |
17 | hg verify |
|
|||
18 |
|
16 | |||
19 | echo % try to clone via stream, should use pull instead |
|
17 | echo % try to clone via stream, should use pull instead | |
20 | http_proxy= hg clone --uncompressed http://localhost:20060/ copy2 |
|
18 | http_proxy= hg clone --uncompressed http://localhost:20060/ copy2 | |
21 |
|
19 | |||
22 | echo % clone via pull |
|
20 | echo % clone via pull | |
23 | http_proxy= hg clone http://localhost:20059/ copy-pull |
|
21 | http_proxy= hg clone http://localhost:20059/ copy-pull | |
|
22 | hg verify -R copy-pull | |||
|
23 | ||||
|
24 | cd test | |||
|
25 | echo bar > bar | |||
|
26 | hg commit -A -d '1 0' -m 2 | |||
|
27 | cd .. | |||
|
28 | ||||
|
29 | echo % pull | |||
24 | cd copy-pull |
|
30 | cd copy-pull | |
25 | hg verify |
|
31 | echo '[hooks]' >> .hg/hgrc | |
|
32 | echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc | |||
|
33 | hg pull | |||
|
34 | cd .. |
@@ -28,3 +28,13 b' checking manifests' | |||||
28 | crosschecking files in changesets and manifests |
|
28 | crosschecking files in changesets and manifests | |
29 | checking files |
|
29 | checking files | |
30 | 1 files, 1 changesets, 1 total revisions |
|
30 | 1 files, 1 changesets, 1 total revisions | |
|
31 | adding bar | |||
|
32 | % pull | |||
|
33 | changegroup: u=http://localhost:20059/ | |||
|
34 | pulling from http://localhost:20059/ | |||
|
35 | searching for changes | |||
|
36 | adding changesets | |||
|
37 | adding manifests | |||
|
38 | adding file changes | |||
|
39 | added 1 changesets with 1 changes to 1 files | |||
|
40 | (run 'hg update' to get a working copy) |
@@ -1,7 +1,10 b'' | |||||
1 | #!/bin/sh |
|
1 | #!/bin/sh | |
2 |
|
2 | |||
3 | hg init a |
|
3 | hg init a | |
|
4 | mkdir a/d1 | |||
|
5 | mkdir a/d1/d2 | |||
4 | echo line 1 > a/a |
|
6 | echo line 1 > a/a | |
|
7 | echo line 1 > a/d1/d2/a | |||
5 | hg --cwd a ci -d '0 0' -Ama |
|
8 | hg --cwd a ci -d '0 0' -Ama | |
6 |
|
9 | |||
7 | echo line 2 >> a/a |
|
10 | echo line 2 >> a/a | |
@@ -69,7 +72,7 b' rm -rf b' | |||||
69 |
|
72 | |||
70 | echo % plain diff in email, no subject, no message body, should fail |
|
73 | echo % plain diff in email, no subject, no message body, should fail | |
71 | hg clone -r0 a b |
|
74 | hg clone -r0 a b | |
72 |
grep -v '^ |
|
75 | egrep -v '^(Subject|email)' msg.patch | hg --cwd b import - | |
73 | rm -rf b |
|
76 | rm -rf b | |
74 |
|
77 | |||
75 | echo % hg export in email, should use patch header |
|
78 | echo % hg export in email, should use patch header | |
@@ -79,3 +82,20 b' python mkmsg.py | hg --cwd b import -' | |||||
79 | hg --cwd b tip | grep second |
|
82 | hg --cwd b tip | grep second | |
80 | rm -rf b |
|
83 | rm -rf b | |
81 |
|
84 | |||
|
85 | # bug non regression test | |||
|
86 | # importing a patch in a subdirectory failed at the commit stage | |||
|
87 | echo line 2 >> a/d1/d2/a | |||
|
88 | hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change' | |||
|
89 | echo % hg import in a subdirectory | |||
|
90 | hg clone -r0 a b | |||
|
91 | hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch | |||
|
92 | dir=`pwd` | |||
|
93 | cd b/d1/d2 2>&1 > /dev/null | |||
|
94 | hg import ../../../tip.patch | |||
|
95 | cd $dir | |||
|
96 | echo "% message should be 'subdir change'" | |||
|
97 | hg --cwd b tip | grep 'subdir change' | |||
|
98 | echo "% committer should be 'someoneelse'" | |||
|
99 | hg --cwd b tip | grep someoneelse | |||
|
100 | echo "% should be empty" | |||
|
101 | hg --cwd b status |
@@ -1,13 +1,13 b'' | |||||
1 | adding a |
|
1 | adding a | |
|
2 | adding d1/d2/a | |||
2 | % import exported patch |
|
3 | % import exported patch | |
3 | requesting all changes |
|
4 | requesting all changes | |
4 | adding changesets |
|
5 | adding changesets | |
5 | adding manifests |
|
6 | adding manifests | |
6 | adding file changes |
|
7 | adding file changes | |
7 |
added 1 changesets with |
|
8 | added 1 changesets with 2 changes to 2 files | |
8 |
|
|
9 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
9 | applying ../tip.patch |
|
10 | applying ../tip.patch | |
10 | patching file a |
|
|||
11 | % message should be same |
|
11 | % message should be same | |
12 | summary: second change |
|
12 | summary: second change | |
13 | % committer should be same |
|
13 | % committer should be same | |
@@ -17,10 +17,9 b' requesting all changes' | |||||
17 | adding changesets |
|
17 | adding changesets | |
18 | adding manifests |
|
18 | adding manifests | |
19 | adding file changes |
|
19 | adding file changes | |
20 |
added 1 changesets with |
|
20 | added 1 changesets with 2 changes to 2 files | |
21 |
|
|
21 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
22 | applying ../tip.patch |
|
22 | applying ../tip.patch | |
23 | patching file a |
|
|||
24 | transaction abort! |
|
23 | transaction abort! | |
25 | rollback completed |
|
24 | rollback completed | |
26 | % import of plain diff should be ok with message |
|
25 | % import of plain diff should be ok with message | |
@@ -28,38 +27,34 b' requesting all changes' | |||||
28 | adding changesets |
|
27 | adding changesets | |
29 | adding manifests |
|
28 | adding manifests | |
30 | adding file changes |
|
29 | adding file changes | |
31 |
added 1 changesets with |
|
30 | added 1 changesets with 2 changes to 2 files | |
32 |
|
|
31 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
33 | applying ../tip.patch |
|
32 | applying ../tip.patch | |
34 | patching file a |
|
|||
35 | % import from stdin |
|
33 | % import from stdin | |
36 | requesting all changes |
|
34 | requesting all changes | |
37 | adding changesets |
|
35 | adding changesets | |
38 | adding manifests |
|
36 | adding manifests | |
39 | adding file changes |
|
37 | adding file changes | |
40 |
added 1 changesets with |
|
38 | added 1 changesets with 2 changes to 2 files | |
41 |
|
|
39 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
42 | applying patch from stdin |
|
40 | applying patch from stdin | |
43 | patching file a |
|
|||
44 | % override commit message |
|
41 | % override commit message | |
45 | requesting all changes |
|
42 | requesting all changes | |
46 | adding changesets |
|
43 | adding changesets | |
47 | adding manifests |
|
44 | adding manifests | |
48 | adding file changes |
|
45 | adding file changes | |
49 |
added 1 changesets with |
|
46 | added 1 changesets with 2 changes to 2 files | |
50 |
|
|
47 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
51 | applying patch from stdin |
|
48 | applying patch from stdin | |
52 | patching file a |
|
|||
53 | summary: override |
|
49 | summary: override | |
54 | % plain diff in email, subject, message body |
|
50 | % plain diff in email, subject, message body | |
55 | requesting all changes |
|
51 | requesting all changes | |
56 | adding changesets |
|
52 | adding changesets | |
57 | adding manifests |
|
53 | adding manifests | |
58 | adding file changes |
|
54 | adding file changes | |
59 |
added 1 changesets with |
|
55 | added 1 changesets with 2 changes to 2 files | |
60 |
|
|
56 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
61 | applying ../msg.patch |
|
57 | applying ../msg.patch | |
62 | patching file a |
|
|||
63 | user: email patcher |
|
58 | user: email patcher | |
64 | summary: email patch |
|
59 | summary: email patch | |
65 | % plain diff in email, no subject, message body |
|
60 | % plain diff in email, no subject, message body | |
@@ -67,28 +62,25 b' requesting all changes' | |||||
67 | adding changesets |
|
62 | adding changesets | |
68 | adding manifests |
|
63 | adding manifests | |
69 | adding file changes |
|
64 | adding file changes | |
70 |
added 1 changesets with |
|
65 | added 1 changesets with 2 changes to 2 files | |
71 |
|
|
66 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
72 | applying patch from stdin |
|
67 | applying patch from stdin | |
73 | patching file a |
|
|||
74 | % plain diff in email, subject, no message body |
|
68 | % plain diff in email, subject, no message body | |
75 | requesting all changes |
|
69 | requesting all changes | |
76 | adding changesets |
|
70 | adding changesets | |
77 | adding manifests |
|
71 | adding manifests | |
78 | adding file changes |
|
72 | adding file changes | |
79 |
added 1 changesets with |
|
73 | added 1 changesets with 2 changes to 2 files | |
80 |
|
|
74 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
81 | applying patch from stdin |
|
75 | applying patch from stdin | |
82 | patching file a |
|
|||
83 | % plain diff in email, no subject, no message body, should fail |
|
76 | % plain diff in email, no subject, no message body, should fail | |
84 | requesting all changes |
|
77 | requesting all changes | |
85 | adding changesets |
|
78 | adding changesets | |
86 | adding manifests |
|
79 | adding manifests | |
87 | adding file changes |
|
80 | adding file changes | |
88 |
added 1 changesets with |
|
81 | added 1 changesets with 2 changes to 2 files | |
89 |
|
|
82 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
90 | applying patch from stdin |
|
83 | applying patch from stdin | |
91 | patching file a |
|
|||
92 | transaction abort! |
|
84 | transaction abort! | |
93 | rollback completed |
|
85 | rollback completed | |
94 | % hg export in email, should use patch header |
|
86 | % hg export in email, should use patch header | |
@@ -96,8 +88,20 b' requesting all changes' | |||||
96 | adding changesets |
|
88 | adding changesets | |
97 | adding manifests |
|
89 | adding manifests | |
98 | adding file changes |
|
90 | adding file changes | |
99 |
added 1 changesets with |
|
91 | added 1 changesets with 2 changes to 2 files | |
100 |
|
|
92 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
101 | applying patch from stdin |
|
93 | applying patch from stdin | |
102 | patching file a |
|
|||
103 | summary: second change |
|
94 | summary: second change | |
|
95 | % hg import in a subdirectory | |||
|
96 | requesting all changes | |||
|
97 | adding changesets | |||
|
98 | adding manifests | |||
|
99 | adding file changes | |||
|
100 | added 1 changesets with 2 changes to 2 files | |||
|
101 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
102 | applying ../../../tip.patch | |||
|
103 | % message should be 'subdir change' | |||
|
104 | summary: subdir change | |||
|
105 | % committer should be 'someoneelse' | |||
|
106 | user: someoneelse | |||
|
107 | % should be empty |
@@ -1,6 +1,3 b'' | |||||
1 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
2 | removing b |
|
2 | removing b | |
3 | this update spans a branch affecting the following files: |
|
3 | abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes | |
4 | b |
|
|||
5 | aborting update spanning branches! |
|
|||
6 | (use 'hg merge' to merge across branches or 'hg update -C' to lose changes) |
|
@@ -22,7 +22,7 b' added 1 changesets with 1 changes to 1 f' | |||||
22 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
22 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
23 | merge: warning: conflicts during merge |
|
23 | merge: warning: conflicts during merge | |
24 | resolving manifests |
|
24 | resolving manifests | |
25 | force False allow True moddirstate True linear False |
|
25 | overwrite None branchmerge True partial False linear False | |
26 | ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20 |
|
26 | ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20 | |
27 | test.txt versions differ, resolve |
|
27 | test.txt versions differ, resolve | |
28 | merging test.txt |
|
28 | merging test.txt |
@@ -36,13 +36,19 b' kill `cat hg.pid`' | |||||
36 |
|
36 | |||
37 | echo % expect success |
|
37 | echo % expect success | |
38 | echo 'allow_push = *' >> .hg/hgrc |
|
38 | echo 'allow_push = *' >> .hg/hgrc | |
|
39 | echo '[hooks]' >> .hg/hgrc | |||
|
40 | echo 'changegroup = echo changegroup: u=$HG_URL >> $HGTMP/urls' >> .hg/hgrc | |||
39 | hg serve -p 20059 -d --pid-file=hg.pid |
|
41 | hg serve -p 20059 -d --pid-file=hg.pid | |
40 | cat hg.pid >> $DAEMON_PIDS |
|
42 | cat hg.pid >> $DAEMON_PIDS | |
41 | hg --cwd ../test2 push http://localhost:20059/ |
|
43 | hg --cwd ../test2 push http://localhost:20059/ | |
42 | kill `cat hg.pid` |
|
44 | kill `cat hg.pid` | |
43 | hg rollback |
|
45 | hg rollback | |
44 |
|
46 | |||
|
47 | sed 's/\(remote:http.*\):.*/\1/' $HGTMP/urls | |||
|
48 | ||||
45 | echo % expect authorization error: all users denied |
|
49 | echo % expect authorization error: all users denied | |
|
50 | echo '[web]' > .hg/hgrc | |||
|
51 | echo 'push_ssl = false' >> .hg/hgrc | |||
46 | echo 'deny_push = *' >> .hg/hgrc |
|
52 | echo 'deny_push = *' >> .hg/hgrc | |
47 | hg serve -p 20059 -d --pid-file=hg.pid |
|
53 | hg serve -p 20059 -d --pid-file=hg.pid | |
48 | cat hg.pid >> $DAEMON_PIDS |
|
54 | cat hg.pid >> $DAEMON_PIDS |
@@ -20,6 +20,7 b' adding manifests' | |||||
20 | adding file changes |
|
20 | adding file changes | |
21 | added 1 changesets with 1 changes to 1 files |
|
21 | added 1 changesets with 1 changes to 1 files | |
22 | rolling back last transaction |
|
22 | rolling back last transaction | |
|
23 | changegroup: u=remote:http | |||
23 | % expect authorization error: all users denied |
|
24 | % expect authorization error: all users denied | |
24 | pushing to http://localhost:20059/ |
|
25 | pushing to http://localhost:20059/ | |
25 | searching for changes |
|
26 | searching for changes |
@@ -17,6 +17,8 b' if [ ! -x dummyssh ] ; then' | |||||
17 | exit -1 |
|
17 | exit -1 | |
18 | fi |
|
18 | fi | |
19 |
|
19 | |||
|
20 | SSH_CLIENT='127.0.0.1 1 2' | |||
|
21 | export SSH_CLIENT | |||
20 | echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog |
|
22 | echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog | |
21 | $2 |
|
23 | $2 | |
22 | EOF |
|
24 | EOF | |
@@ -29,6 +31,8 b' echo this > foo' | |||||
29 | hg ci -A -m "init" -d "1000000 0" foo |
|
31 | hg ci -A -m "init" -d "1000000 0" foo | |
30 | echo '[server]' > .hg/hgrc |
|
32 | echo '[server]' > .hg/hgrc | |
31 | echo 'uncompressed = True' >> .hg/hgrc |
|
33 | echo 'uncompressed = True' >> .hg/hgrc | |
|
34 | echo '[hooks]' >> .hg/hgrc | |||
|
35 | echo 'changegroup = echo changegroup in remote: u=$HG_URL >> ../dummylog' >> .hg/hgrc | |||
32 |
|
36 | |||
33 | cd .. |
|
37 | cd .. | |
34 |
|
38 | |||
@@ -46,6 +50,9 b' echo "# verify"' | |||||
46 | cd local |
|
50 | cd local | |
47 | hg verify |
|
51 | hg verify | |
48 |
|
52 | |||
|
53 | echo '[hooks]' >> .hg/hgrc | |||
|
54 | echo 'changegroup = echo changegroup in local: u=$HG_URL >> ../dummylog' >> .hg/hgrc | |||
|
55 | ||||
49 | echo "# empty default pull" |
|
56 | echo "# empty default pull" | |
50 | hg paths |
|
57 | hg paths | |
51 | hg pull -e ../dummyssh |
|
58 | hg pull -e ../dummyssh |
@@ -83,5 +83,7 b' Got arguments 1:user@dummy 2:hg -R remot' | |||||
83 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
83 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: | |
84 | Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5: |
|
84 | Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5: | |
85 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
85 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: | |
|
86 | changegroup in remote: u=remote:ssh:127.0.0.1 | |||
86 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
87 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: | |
87 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
88 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: | |
|
89 | changegroup in remote: u=remote:ssh:127.0.0.1 |
@@ -37,6 +37,14 b' http_proxy= hg clone static-http://local' | |||||
37 | cd local |
|
37 | cd local | |
38 | hg verify |
|
38 | hg verify | |
39 | cat bar |
|
39 | cat bar | |
|
40 | ||||
|
41 | cd ../remote | |||
|
42 | echo baz > quux | |||
|
43 | hg commit -A -mtest2 -d '100000000 0' | |||
|
44 | ||||
|
45 | cd ../local | |||
|
46 | echo '[hooks]' >> .hg/hgrc | |||
|
47 | echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc | |||
40 | http_proxy= hg pull |
|
48 | http_proxy= hg pull | |
41 |
|
49 | |||
42 | kill $! |
|
50 | kill $! |
@@ -19,6 +19,12 b' crosschecking files in changesets and ma' | |||||
19 | checking files |
|
19 | checking files | |
20 | 1 files, 1 changesets, 1 total revisions |
|
20 | 1 files, 1 changesets, 1 total revisions | |
21 | foo |
|
21 | foo | |
|
22 | adding quux | |||
|
23 | changegroup: u=static-http://localhost:20059/remote | |||
22 | pulling from static-http://localhost:20059/remote |
|
24 | pulling from static-http://localhost:20059/remote | |
23 | searching for changes |
|
25 | searching for changes | |
24 | no changes found |
|
26 | adding changesets | |
|
27 | adding manifests | |||
|
28 | adding file changes | |||
|
29 | added 1 changesets with 1 changes to 1 files | |||
|
30 | (run 'hg update' to get a working copy) |
@@ -35,3 +35,8 b' hg status modified added removed deleted' | |||||
35 | hg copy modified copied |
|
35 | hg copy modified copied | |
36 | echo "hg status -C:" |
|
36 | echo "hg status -C:" | |
37 | hg status -C |
|
37 | hg status -C | |
|
38 | ||||
|
39 | echo "hg status -t:" | |||
|
40 | hg status -t | |||
|
41 | echo "hg status -A:" | |||
|
42 | hg status -A |
@@ -108,3 +108,50 b' A copied' | |||||
108 | R removed |
|
108 | R removed | |
109 | ! deleted |
|
109 | ! deleted | |
110 | ? unknown |
|
110 | ? unknown | |
|
111 | hg status -t: | |||
|
112 | hg status: option -t not recognized | |||
|
113 | hg status [OPTION]... [FILE]... | |||
|
114 | ||||
|
115 | show changed files in the working directory | |||
|
116 | ||||
|
117 | Show status of files in the repository. If names are given, only | |||
|
118 | files that match are shown. Files that are clean or ignored, are | |||
|
119 | not listed unless -c (clean), -i (ignored) or -A is given. | |||
|
120 | ||||
|
121 | The codes used to show the status of files are: | |||
|
122 | M = modified | |||
|
123 | A = added | |||
|
124 | R = removed | |||
|
125 | C = clean | |||
|
126 | ! = deleted, but still tracked | |||
|
127 | ? = not tracked | |||
|
128 | I = ignored (not shown by default) | |||
|
129 | = the previous added file was copied from here | |||
|
130 | ||||
|
131 | aliases: st | |||
|
132 | ||||
|
133 | options: | |||
|
134 | ||||
|
135 | -A --all show status of all files | |||
|
136 | -m --modified show only modified files | |||
|
137 | -a --added show only added files | |||
|
138 | -r --removed show only removed files | |||
|
139 | -d --deleted show only deleted (but tracked) files | |||
|
140 | -c --clean show only files without changes | |||
|
141 | -u --unknown show only unknown (not tracked) files | |||
|
142 | -i --ignored show ignored files | |||
|
143 | -n --no-status hide status prefix | |||
|
144 | -C --copies show source of copied files | |||
|
145 | -0 --print0 end filenames with NUL, for use with xargs | |||
|
146 | -I --include include names matching the given patterns | |||
|
147 | -X --exclude exclude names matching the given patterns | |||
|
148 | hg status -A: | |||
|
149 | A added | |||
|
150 | A copied | |||
|
151 | modified | |||
|
152 | R removed | |||
|
153 | ! deleted | |||
|
154 | ? unknown | |||
|
155 | I ignored | |||
|
156 | C .hgignore | |||
|
157 | C modified |
@@ -19,6 +19,11 b' hg tag -l -d "1000000 0" "bleah1" 1' | |||||
19 | cat .hgtags |
|
19 | cat .hgtags | |
20 | cat .hg/localtags |
|
20 | cat .hg/localtags | |
21 |
|
21 | |||
|
22 | hg update 0 | |||
|
23 | hg tag -d "1000000 0" "foobar" | |||
|
24 | cat .hgtags | |||
|
25 | cat .hg/localtags | |||
|
26 | ||||
22 | hg tag -l 'xx |
|
27 | hg tag -l 'xx | |
23 | newline' |
|
28 | newline' | |
24 | hg tag -l 'xx:xx' |
|
29 | hg tag -l 'xx:xx' |
@@ -25,5 +25,8 b" use of 'hg tag NAME [REV]' is deprecated" | |||||
25 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah |
|
25 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah | |
26 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0 |
|
26 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0 | |
27 | c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1 |
|
27 | c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1 | |
|
28 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
29 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar | |||
|
30 | c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1 | |||
28 | abort: '\n' cannot be used in a tag name |
|
31 | abort: '\n' cannot be used in a tag name | |
29 | abort: ':' cannot be used in a tag name |
|
32 | abort: ':' cannot be used in a tag name |
@@ -15,7 +15,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||||
15 | summary: 1 |
|
15 | summary: 1 | |
16 |
|
16 | |||
17 | resolving manifests |
|
17 | resolving manifests | |
18 | force None allow None moddirstate True linear True |
|
18 | overwrite False branchmerge False partial False linear True | |
19 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e |
|
19 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e | |
20 | a versions differ, resolve |
|
20 | a versions differ, resolve | |
21 | remote created b |
|
21 | remote created b | |
@@ -31,7 +31,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||||
31 | summary: 2 |
|
31 | summary: 2 | |
32 |
|
32 | |||
33 | resolving manifests |
|
33 | resolving manifests | |
34 | force None allow None moddirstate True linear True |
|
34 | overwrite False branchmerge False partial False linear True | |
35 | ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c |
|
35 | ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c | |
36 | remote deleted b |
|
36 | remote deleted b | |
37 | removing b |
|
37 | removing b | |
@@ -41,7 +41,7 b' user: test' | |||||
41 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
41 | date: Mon Jan 12 13:46:40 1970 +0000 | |
42 | summary: 1 |
|
42 | summary: 1 | |
43 |
|
43 | |||
44 |
abort: there is nothing to merge |
|
44 | abort: there is nothing to merge - use "hg update" instead | |
45 | failed |
|
45 | failed | |
46 | changeset: 0:33aaa84a386b |
|
46 | changeset: 0:33aaa84a386b | |
47 | user: test |
|
47 | user: test | |
@@ -49,7 +49,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||||
49 | summary: 1 |
|
49 | summary: 1 | |
50 |
|
50 | |||
51 | resolving manifests |
|
51 | resolving manifests | |
52 | force None allow None moddirstate True linear True |
|
52 | overwrite False branchmerge False partial False linear True | |
53 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e |
|
53 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e | |
54 | a versions differ, resolve |
|
54 | a versions differ, resolve | |
55 | remote created b |
|
55 | remote created b | |
@@ -95,21 +95,12 b' user: test' | |||||
95 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
95 | date: Mon Jan 12 13:46:40 1970 +0000 | |
96 | summary: 2 |
|
96 | summary: 2 | |
97 |
|
97 | |||
98 | resolving manifests |
|
98 | abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes | |
99 | force None allow None moddirstate True linear False |
|
|||
100 | ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 |
|
|||
101 | a versions differ, resolve |
|
|||
102 | b versions differ, resolve |
|
|||
103 | this update spans a branch affecting the following files: |
|
|||
104 | a (resolve) |
|
|||
105 | b (resolve) |
|
|||
106 | aborting update spanning branches! |
|
|||
107 | (use 'hg merge' to merge across branches or 'hg update -C' to lose changes) |
|
|||
108 | failed |
|
99 | failed | |
109 | abort: outstanding uncommitted changes |
|
100 | abort: outstanding uncommitted changes | |
110 | failed |
|
101 | failed | |
111 | resolving manifests |
|
102 | resolving manifests | |
112 |
|
|
103 | overwrite False branchmerge True partial False linear False | |
113 | ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 |
|
104 | ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 | |
114 | a versions differ, resolve |
|
105 | a versions differ, resolve | |
115 | b versions differ, resolve |
|
106 | b versions differ, resolve |
@@ -40,7 +40,7 b' a' | |||||
40 | side1 |
|
40 | side1 | |
41 | side2 |
|
41 | side2 | |
42 | resolving manifests |
|
42 | resolving manifests | |
43 | force 1 allow None moddirstate True linear False |
|
43 | overwrite True branchmerge False partial False linear False | |
44 | ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae |
|
44 | ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae | |
45 | remote deleted side2, clobbering |
|
45 | remote deleted side2, clobbering | |
46 | remote deleted side1, clobbering |
|
46 | remote deleted side1, clobbering |
General Comments 0
You need to be logged in to leave comments.
Login now