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 | 1 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A= |
|
2 | 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk= |
@@ -11,3 +11,4 b' 979c049974485125e1f9357f6bbe9c1b548a64c3' | |||
|
11 | 11 | 3a56574f329a368d645853e0f9e09472aee62349 0.8 |
|
12 | 12 | 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1 |
|
13 | 13 | 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9 |
|
14 | 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1 |
@@ -4,6 +4,7 b' Goffredo Baroncelli <kreijack at libero.' | |||
|
4 | 4 | Muli Ben-Yehuda <mulix at mulix.org> |
|
5 | 5 | Mikael Berthe <mikael at lilotux.net> |
|
6 | 6 | Benoit Boissinot <bboissin at gmail.com> |
|
7 | Brendan Cully <brendan at kublai.com> | |
|
7 | 8 | Vincent Danjean <vdanjean.ml at free.fr> |
|
8 | 9 | Jake Edge <jake at edge2.net> |
|
9 | 10 | Michael Fetterman <michael.fetterman at intel.com> |
@@ -2,7 +2,7 b' include hg' | |||
|
2 | 2 | recursive-include mercurial *.py |
|
3 | 3 | include hgweb.cgi hgwebdir.cgi |
|
4 | 4 | include hgeditor rewrite-log |
|
5 |
include tests/README tests/ |
|
|
5 | include tests/README tests/*.py tests/test-*[a-z0-9] tests/*.out | |
|
6 | 6 | prune tests/*.err |
|
7 | 7 | include *.txt |
|
8 | 8 | include templates/map templates/map-*[a-z0-9] |
@@ -10,8 +10,10 b' include templates/*.tmpl' | |||
|
10 | 10 | include templates/static/* |
|
11 | 11 | include doc/README doc/Makefile doc/gendoc.py doc/*.txt doc/*.html doc/*.[0-9] |
|
12 | 12 | recursive-include contrib * |
|
13 | recursive-include hgext * | |
|
13 | 14 | include README |
|
14 | 15 | include CONTRIBUTORS |
|
15 | 16 | include COPYING |
|
16 | 17 | include Makefile |
|
17 | 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 | 289 | _hg_cmd_qdelete() |
|
290 | 290 | { |
|
291 |
_hg_ext_mq_patchlist q |
|
|
291 | _hg_ext_mq_patchlist qunapplied | |
|
292 | 292 | } |
|
293 | 293 | |
|
294 | 294 | _hg_cmd_qsave() |
@@ -313,6 +313,11 b' complete -o bashdefault -o default -F _h' | |||
|
313 | 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 | 322 | # hbisect |
|
318 | 323 | _hg_cmd_bisect() |
@@ -28,7 +28,8 b' class convert_git:' | |||
|
28 | 28 | self.path = path |
|
29 | 29 | |
|
30 | 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 | 34 | def catfile(self, rev, type): |
|
34 | 35 | if rev == "0" * 40: raise IOError() |
@@ -92,7 +92,7 b' def darcs_tip(darcs_repo):' | |||
|
92 | 92 | |
|
93 | 93 | def darcs_pull(hg_repo, darcs_repo, chash): |
|
94 | 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 | 96 | print res |
|
97 | 97 | new_tip = darcs_tip(darcs_repo) |
|
98 | 98 | if not new_tip != old_tip + 1: |
@@ -110,7 +110,8 b' def hg_commit( hg_repo, text, author, da' | |||
|
110 | 110 | old_tip = hg_tip(hg_repo) |
|
111 | 111 | cmd("hg add -X _darcs", hg_repo) |
|
112 | 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 | 115 | os.unlink(tmpfile) |
|
115 | 116 | new_tip = hg_tip(hg_repo) |
|
116 | 117 | if not new_tip == old_tip + 1: |
@@ -156,7 +157,7 b' if __name__ == "__main__":' | |||
|
156 | 157 | print "Given HG repository must not exist when no SKIP is specified." |
|
157 | 158 | sys.exit(-1) |
|
158 | 159 | if skip == None: |
|
159 |
cmd("hg init |
|
|
160 | cmd("hg init \"%s\"" % (hg_repo)) | |
|
160 | 161 | cmd("darcs initialize", hg_repo) |
|
161 | 162 | # Get the changes from the Darcs repository |
|
162 | 163 | change_number = 0 |
@@ -5,13 +5,73 b'' | |||
|
5 | 5 | <meta http-equiv="Content-Style-Type" content="text/css"> |
|
6 | 6 | <title></title> |
|
7 | 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 | 9 | p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px} |
|
10 | 10 | </style> |
|
11 | 11 | </head> |
|
12 | 12 | <body> |
|
13 | 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 | 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 | 76 | </body> |
|
17 | 77 | </html> |
@@ -380,7 +380,9 b" Handle frickin' frackin' gratuitous even" | |||
|
380 | 380 | (save-excursion |
|
381 | 381 | (while hg-prev-buffer |
|
382 | 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 | 386 | (if (or (not path) current-prefix-arg) |
|
385 | 387 | (expand-file-name |
|
386 | 388 | (eval (list* 'read-file-name |
@@ -716,7 +718,11 b' code by typing `M-x find-library mercuri' | |||
|
716 | 718 | (goto-char pos) |
|
717 | 719 | (end-of-line 1) |
|
718 | 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 | 727 | (defun hg-add (path) |
|
722 | 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 | 978 | (cd (hg-root path))) |
|
973 | 979 | (when update |
|
974 | 980 | (with-current-buffer buf |
|
975 |
|
|
|
981 | (when (local-variable-p 'backup-inhibited) | |
|
982 | (kill-local-variable 'backup-inhibited)) | |
|
976 | 983 | (hg-mode-line))))) |
|
977 | 984 | |
|
978 | 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 | 3 | " Vim plugin to assist in working with HG-controlled files. |
|
4 | 4 | " |
|
5 | 5 | " Last Change: 2006/02/22 |
|
6 |
" Version: 1.7 |
|
|
6 | " Version: 1.77 | |
|
7 | 7 | " Maintainer: Mathieu Clabaut <mathieu.clabaut@gmail.com> |
|
8 | 8 | " License: This file is placed in the public domain. |
|
9 | 9 | " Credits: |
@@ -13,7 +13,7 b'' | |||
|
13 | 13 | |
|
14 | 14 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
|
15 | 15 | " |
|
16 |
" Section: Documentation |
|
|
16 | " Section: Documentation | |
|
17 | 17 | "---------------------------- |
|
18 | 18 | " |
|
19 | 19 | " Documentation should be available by ":help hgcommand" command, once the |
@@ -21,7 +21,7 b'' | |||
|
21 | 21 | " |
|
22 | 22 | " You still can read the documentation at the end of this file. Locate it by |
|
23 | 23 | " searching the "hgcommand-contents" string (and set ft=help to have |
|
24 |
" appropriate syntaxic coloration). |
|
|
24 | " appropriate syntaxic coloration). | |
|
25 | 25 | |
|
26 | 26 | " Section: Plugin header {{{1 |
|
27 | 27 | |
@@ -34,11 +34,33 b' if exists("loaded_hgcommand")' | |||
|
34 | 34 | endif |
|
35 | 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 | 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 | 54 | finish |
|
40 | 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 | 64 | " Section: Event group setup {{{1 |
|
43 | 65 | |
|
44 | 66 | augroup HGCommand |
@@ -63,7 +85,7 b' unlet! s:vimDiffScratchList' | |||
|
63 | 85 | function! s:HGResolveLink(fileName) |
|
64 | 86 | let resolved = resolve(a:fileName) |
|
65 | 87 | if resolved != a:fileName |
|
66 |
let resolved = |
|
|
88 | let resolved = <SID>HGResolveLink(resolved) | |
|
67 | 89 | endif |
|
68 | 90 | return resolved |
|
69 | 91 | endfunction |
@@ -74,7 +96,7 b' endfunction' | |||
|
74 | 96 | |
|
75 | 97 | function! s:HGChangeToCurrentFileDir(fileName) |
|
76 | 98 | let oldCwd=getcwd() |
|
77 |
let fileName= |
|
|
99 | let fileName=<SID>HGResolveLink(a:fileName) | |
|
78 | 100 | let newCwd=fnamemodify(fileName, ':h') |
|
79 | 101 | if strlen(newCwd) > 0 |
|
80 | 102 | execute 'cd' escape(newCwd, ' ') |
@@ -82,7 +104,7 b' function! s:HGChangeToCurrentFileDir(fil' | |||
|
82 | 104 | return oldCwd |
|
83 | 105 | endfunction |
|
84 | 106 | |
|
85 |
" Function: |
|
|
107 | " Function: <SID>HGGetOption(name, default) {{{2 | |
|
86 | 108 | " Grab a user-specified option to override the default provided. Options are |
|
87 | 109 | " searched in the window, buffer, then global spaces. |
|
88 | 110 | |
@@ -110,9 +132,9 b' function! s:HGEditFile(name, origBuffNR)' | |||
|
110 | 132 | "Name parameter will be pasted into expression. |
|
111 | 133 | let name = escape(a:name, ' *?\') |
|
112 | 134 | |
|
113 |
let editCommand = |
|
|
135 | let editCommand = <SID>HGGetOption('HGCommandEdit', 'edit') | |
|
114 | 136 | if editCommand != 'edit' |
|
115 |
if |
|
|
137 | if <SID>HGGetOption('HGCommandSplit', 'horizontal') == 'horizontal' | |
|
116 | 138 | if name == "" |
|
117 | 139 | let editCommand = 'rightbelow new' |
|
118 | 140 | else |
@@ -154,8 +176,8 b' function! s:HGCreateCommandBuffer(cmd, c' | |||
|
154 | 176 | |
|
155 | 177 | let resultBufferName='' |
|
156 | 178 | |
|
157 |
if |
|
|
158 |
let nameMarker = |
|
|
179 | if <SID>HGGetOption("HGCommandNameResultBuffers", 0) | |
|
180 | let nameMarker = <SID>HGGetOption("HGCommandNameMarker", '_') | |
|
159 | 181 | if strlen(a:statusText) > 0 |
|
160 | 182 | let bufName=a:cmdName . ' -- ' . a:statusText |
|
161 | 183 | else |
@@ -170,7 +192,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||
|
170 | 192 | endwhile |
|
171 | 193 | endif |
|
172 | 194 | |
|
173 |
let hgCommand = |
|
|
195 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " " . a:cmd | |
|
174 | 196 | "echomsg "DBG :".hgCommand |
|
175 | 197 | let hgOut = system(hgCommand) |
|
176 | 198 | " HACK: diff command does not return proper error codes |
@@ -192,7 +214,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||
|
192 | 214 | return -1 |
|
193 | 215 | endif |
|
194 | 216 | |
|
195 |
if |
|
|
217 | if <SID>HGEditFile(resultBufferName, a:origBuffNR) == -1 | |
|
196 | 218 | return -1 |
|
197 | 219 | endif |
|
198 | 220 | |
@@ -200,7 +222,7 b' function! s:HGCreateCommandBuffer(cmd, c' | |||
|
200 | 222 | set noswapfile |
|
201 | 223 | set filetype= |
|
202 | 224 | |
|
203 |
if |
|
|
225 | if <SID>HGGetOption("HGCommandDeleteOnHide", 0) | |
|
204 | 226 | set bufhidden=delete |
|
205 | 227 | endif |
|
206 | 228 | |
@@ -213,8 +235,8 b' function! s:HGCreateCommandBuffer(cmd, c' | |||
|
213 | 235 | " This could be fixed by explicitly detecting whether the last line is |
|
214 | 236 | " within a fold, but I prefer to simply unfold the result buffer altogether. |
|
215 | 237 | |
|
216 |
if has( |
|
|
217 | normal zR | |
|
238 | if has("folding") | |
|
239 | setlocal nofoldenable | |
|
218 | 240 | endif |
|
219 | 241 | |
|
220 | 242 | $d |
@@ -243,7 +265,7 b' function! s:HGBufferCheck(hgBuffer)' | |||
|
243 | 265 | return origBuffer |
|
244 | 266 | else |
|
245 | 267 | " Original buffer no longer exists. |
|
246 |
return -1 |
|
|
268 | return -1 | |
|
247 | 269 | endif |
|
248 | 270 | else |
|
249 | 271 | " No original buffer |
@@ -256,7 +278,7 b' endfunction' | |||
|
256 | 278 | " for the current buffer. |
|
257 | 279 | |
|
258 | 280 | function! s:HGCurrentBufferCheck() |
|
259 |
return |
|
|
281 | return <SID>HGBufferCheck(bufnr("%")) | |
|
260 | 282 | endfunction |
|
261 | 283 | |
|
262 | 284 | " Function: s:HGToggleDeleteOnHide() {{{2 |
@@ -275,8 +297,8 b' endfunction' | |||
|
275 | 297 | " Returns: name of the new command buffer containing the command results |
|
276 | 298 | |
|
277 | 299 | function! s:HGDoCommand(cmd, cmdName, statusText) |
|
278 |
let hgBufferCheck= |
|
|
279 |
if hgBufferCheck == -1 |
|
|
300 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
|
301 | if hgBufferCheck == -1 | |
|
280 | 302 | echo "Original buffer no longer exists, aborting." |
|
281 | 303 | return -1 |
|
282 | 304 | endif |
@@ -285,8 +307,8 b' function! s:HGDoCommand(cmd, cmdName, st' | |||
|
285 | 307 | if isdirectory(fileName) |
|
286 | 308 | let fileName=fileName . "/" . getline(".") |
|
287 | 309 | endif |
|
288 |
let realFileName = fnamemodify( |
|
|
289 |
let oldCwd= |
|
|
310 | let realFileName = fnamemodify(<SID>HGResolveLink(fileName), ':t') | |
|
311 | let oldCwd=<SID>HGChangeToCurrentFileDir(fileName) | |
|
290 | 312 | try |
|
291 | 313 | " TODO |
|
292 | 314 | "if !filereadable('HG/Root') |
@@ -294,7 +316,7 b' function! s:HGDoCommand(cmd, cmdName, st' | |||
|
294 | 316 | "endif |
|
295 | 317 | let fullCmd = a:cmd . ' "' . realFileName . '"' |
|
296 | 318 | "echomsg "DEBUG".fullCmd |
|
297 |
let resultBuffer= |
|
|
319 | let resultBuffer=<SID>HGCreateCommandBuffer(fullCmd, a:cmdName, a:statusText, hgBufferCheck) | |
|
298 | 320 | return resultBuffer |
|
299 | 321 | catch |
|
300 | 322 | echoerr v:exception |
@@ -314,17 +336,17 b' endfunction' | |||
|
314 | 336 | " Returns: string to be exec'd that sets the multiple return values. |
|
315 | 337 | |
|
316 | 338 | function! s:HGGetStatusVars(revisionVar, branchVar, repositoryVar) |
|
317 |
let hgBufferCheck= |
|
|
339 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
|
318 | 340 | "echomsg "DBG : in HGGetStatusVars" |
|
319 |
if hgBufferCheck == -1 |
|
|
341 | if hgBufferCheck == -1 | |
|
320 | 342 | return "" |
|
321 | 343 | endif |
|
322 | 344 | let fileName=bufname(hgBufferCheck) |
|
323 |
let fileNameWithoutLink= |
|
|
345 | let fileNameWithoutLink=<SID>HGResolveLink(fileName) | |
|
324 | 346 | let realFileName = fnamemodify(fileNameWithoutLink, ':t') |
|
325 |
let oldCwd= |
|
|
347 | let oldCwd=<SID>HGChangeToCurrentFileDir(realFileName) | |
|
326 | 348 | try |
|
327 |
let hgCommand = |
|
|
349 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " root " | |
|
328 | 350 | let roottext=system(hgCommand) |
|
329 | 351 | " Suppress ending null char ! Does it work in window ? |
|
330 | 352 | let roottext=substitute(roottext,'^.*/\([^/\n\r]*\)\n\_.*$','\1','') |
@@ -335,31 +357,31 b' function! s:HGGetStatusVars(revisionVar,' | |||
|
335 | 357 | if a:repositoryVar != "" |
|
336 | 358 | let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . roottext . "'" |
|
337 | 359 | endif |
|
338 |
let hgCommand = |
|
|
360 | let hgCommand = <SID>HGGetOption("HGCommandHGExec", "hg") . " status -mardui " . realFileName | |
|
339 | 361 | let statustext=system(hgCommand) |
|
340 | 362 | if(v:shell_error) |
|
341 | 363 | return "" |
|
342 | 364 | endif |
|
343 |
if match(statustext, '^[?I]') >= 0 |
|
|
365 | if match(statustext, '^[?I]') >= 0 | |
|
344 | 366 | let revision="NEW" |
|
345 |
elseif match(statustext, '^[R]') >= 0 |
|
|
367 | elseif match(statustext, '^[R]') >= 0 | |
|
346 | 368 | let revision="REMOVED" |
|
347 |
elseif match(statustext, '^[D]') >= 0 |
|
|
369 | elseif match(statustext, '^[D]') >= 0 | |
|
348 | 370 | let revision="DELETED" |
|
349 |
elseif match(statustext, '^[A]') >= 0 |
|
|
371 | elseif match(statustext, '^[A]') >= 0 | |
|
350 | 372 | let revision="ADDED" |
|
351 | 373 | else |
|
352 | 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 | 376 | let statustext=system(hgCommand) |
|
355 | 377 | if(v:shell_error) |
|
356 |
|
|
|
378 | return "" | |
|
357 | 379 | endif |
|
358 | 380 | let revision=substitute(statustext, '^changeset:\s*\(\d\+\):.*\_$\_.*$', '\1', "") |
|
359 | 381 | |
|
360 | 382 | if a:branchVar != "" && match(statustext, '^\_.*\_^branch:') >= 0 |
|
361 |
|
|
|
362 |
|
|
|
383 | let branch=substitute(statustext, '^\_.*\_^branch:\s*\(\S\+\)\n\_.*$', '\1', "") | |
|
384 | let returnExpression=returnExpression . " | let " . a:branchVar . "='" . branch . "'" | |
|
363 | 385 | endif |
|
364 | 386 | endif |
|
365 | 387 | if (exists('revision')) |
@@ -381,7 +403,7 b' function! s:HGSetupBuffer(...)' | |||
|
381 | 403 | return |
|
382 | 404 | endif |
|
383 | 405 | |
|
384 |
if ! |
|
|
406 | if !<SID>HGGetOption("HGCommandEnableBufferSetup", 0) | |
|
385 | 407 | \ || @% == "" |
|
386 | 408 | \ || s:HGCommandEditFileRunning > 0 |
|
387 | 409 | \ || exists("b:HGOrigBuffNR") |
@@ -399,7 +421,7 b' function! s:HGSetupBuffer(...)' | |||
|
399 | 421 | let branch="" |
|
400 | 422 | let repository="" |
|
401 | 423 | |
|
402 |
exec |
|
|
424 | exec <SID>HGGetStatusVars('revision', 'branch', 'repository') | |
|
403 | 425 | "echomsg "DBG ".revision."#".branch."#".repository |
|
404 | 426 | if revision != "" |
|
405 | 427 | let b:HGRevision=revision |
@@ -427,7 +449,7 b' endfunction' | |||
|
427 | 449 | function! s:HGMarkOrigBufferForSetup(hgBuffer) |
|
428 | 450 | checktime |
|
429 | 451 | if a:hgBuffer != -1 |
|
430 |
let origBuffer = |
|
|
452 | let origBuffer = <SID>HGBufferCheck(a:hgBuffer) | |
|
431 | 453 | "This should never not work, but I'm paranoid |
|
432 | 454 | if origBuffer != a:hgBuffer |
|
433 | 455 | call setbufvar(origBuffer, "HGBufferSetup", 0) |
@@ -436,7 +458,7 b' function! s:HGMarkOrigBufferForSetup(hgB' | |||
|
436 | 458 | "We are presumably in the original buffer |
|
437 | 459 | let b:HGBufferSetup = 0 |
|
438 | 460 | "We do the setup now as now event will be triggered allowing it later. |
|
439 |
call |
|
|
461 | call <SID>HGSetupBuffer() | |
|
440 | 462 | endif |
|
441 | 463 | return a:hgBuffer |
|
442 | 464 | endfunction |
@@ -478,111 +500,93 b' endfunction' | |||
|
478 | 500 | " 1 if new document installed, 0 otherwise. |
|
479 | 501 | " Note: Cleaned and generalized by guo-peng Wen |
|
480 | 502 | "''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' |
|
481 | ||
|
482 | function! s:HGInstallDocumentation(full_name, revision) | |
|
483 | " Name of the document path based on the system we use: | |
|
484 | if (has("unix")) | |
|
485 | " On UNIX like system, using forward slash: | |
|
486 | let l:slash_char = '/' | |
|
487 | let l:mkdir_cmd = ':silent !mkdir -p ' | |
|
488 | else | |
|
489 | " On M$ system, use backslash. Also mkdir syntax is different. | |
|
490 | " This should only work on W2K and up. | |
|
491 | let l:slash_char = '\' | |
|
492 | let l:mkdir_cmd = ':silent !mkdir ' | |
|
493 | endif | |
|
494 | ||
|
495 | let l:doc_path = l:slash_char . 'doc' | |
|
496 | let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc' | |
|
503 | " Helper function to make mkdir as portable as possible | |
|
504 | function! s:HGFlexiMkdir(dir) | |
|
505 | if exists("*mkdir") " we can use Vim's own mkdir() | |
|
506 | call mkdir(a:dir) | |
|
507 | elseif !exists("+shellslash") | |
|
508 | call system("mkdir -p '".a:dir."'") | |
|
509 | else " M$ | |
|
510 | let l:ssl = &shellslash | |
|
511 | try | |
|
512 | set shellslash | |
|
513 | " no single quotes? | |
|
514 | call system('mkdir "'.a:dir.'"') | |
|
515 | finally | |
|
516 | let &shellslash = l:ssl | |
|
517 | endtry | |
|
518 | endif | |
|
519 | endfunction | |
|
497 | 520 | |
|
498 | " Figure out document path based on full name of this script: | |
|
499 | let l:vim_plugin_path = fnamemodify(a:full_name, ':h') | |
|
500 |
|
|
|
501 |
|
|
|
502 | echomsg "Doc path: " . l:vim_doc_path | |
|
503 | execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' | |
|
504 |
|
|
|
505 | " Try a default configuration in user home: | |
|
506 |
|
|
|
507 | if (!(filewritable(l:vim_doc_path) == 2)) | |
|
508 | execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' | |
|
509 | if (!(filewritable(l:vim_doc_path) == 2)) | |
|
510 | " Put a warning: | |
|
511 | echomsg "Unable to open documentation directory" | |
|
512 | echomsg " type :help add-local-help for more informations." | |
|
513 | return 0 | |
|
514 | endif | |
|
515 |
|
|
|
521 | function! s:HGInstallDocumentation(full_name) | |
|
522 | " Figure out document path based on full name of this script: | |
|
523 | let l:vim_doc_path = fnamemodify(a:full_name, ":h:h") . "/doc" | |
|
524 | if filewritable(l:vim_doc_path) != 2 | |
|
525 | echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path | |
|
526 | silent! call <SID>HGFlexiMkdir(l:vim_doc_path) | |
|
527 | if filewritable(l:vim_doc_path) != 2 | |
|
528 | " Try first item in 'runtimepath': | |
|
529 | let l:vim_doc_path = | |
|
530 | \ substitute(&runtimepath, '^\([^,]*\).*', '\1/doc', 'e') | |
|
531 | if filewritable(l:vim_doc_path) != 2 | |
|
532 | echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path | |
|
533 | silent! call <SID>HGFlexiMkdir(l:vim_doc_path) | |
|
534 | if filewritable(l:vim_doc_path) != 2 | |
|
535 | " Put a warning: | |
|
536 | echomsg "Unable to open documentation directory" | |
|
537 | echomsg " type `:help add-local-help' for more information." | |
|
538 | return 0 | |
|
516 | 539 | endif |
|
540 | endif | |
|
517 | 541 | endif |
|
518 | ||
|
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 | |
|
542 | endif | |
|
531 | 543 | |
|
532 | " Bail out if document file is still up to date: | |
|
533 | if (filereadable(l:doc_file) && | |
|
534 | \ getftime(l:plugin_file) < getftime(l:doc_file)) | |
|
535 | return 0 | |
|
536 | endif | |
|
544 | " Full name of documentation file: | |
|
545 | let l:doc_file = | |
|
546 | \ l:vim_doc_path . "/" . s:script_name . ".txt" | |
|
547 | " Bail out if document file is still up to date: | |
|
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: | |
|
539 | if (strlen(@%)) | |
|
540 | let l:go_back = 'b ' . bufnr("%") | |
|
541 | else | |
|
542 | let l:go_back = 'enew!' | |
|
543 | endif | |
|
544 | ||
|
545 | " Create a new buffer & read in the plugin file (me): | |
|
546 |
setl no |
|
|
547 | exe 'enew!' | |
|
548 | exe 'r ' . l:plugin_file | |
|
549 | ||
|
550 | setl modeline | |
|
551 | let l:buf = bufnr("%") | |
|
552 | setl noswapfile modifiable | |
|
553 | ||
|
554 | norm zR | |
|
555 | norm gg | |
|
553 | " temporary global settings | |
|
554 | let l:lz = &lazyredraw | |
|
555 | let l:hls = &hlsearch | |
|
556 | set lazyredraw nohlsearch | |
|
557 | " Create a new buffer & read in the plugin file (me): | |
|
558 | 1 new | |
|
559 | setlocal noswapfile modifiable nomodeline | |
|
560 | if has("folding") | |
|
561 | setlocal nofoldenable | |
|
562 | endif | |
|
563 | silent execute "read" escape(a:full_name, " ") | |
|
564 | let l:doc_buf = bufnr("%") | |
|
556 | 565 | |
|
557 | " Delete from first line to a line starts with | |
|
558 | " === START_DOC | |
|
559 | 1,/^=\{3,}\s\+START_DOC\C/ d | |
|
560 | ||
|
561 |
|
|
|
562 |
|
|
|
563 |
|
|
|
564 |
|
|
|
565 | ||
|
566 | " Remove fold marks: | |
|
567 | %s/{\{3}[1-9]/ / | |
|
566 | 1 | |
|
567 | " Delete from first line to a line starts with | |
|
568 | " === START_DOC | |
|
569 | silent 1,/^=\{3,}\s\+START_DOC\C/ d | |
|
570 | " Delete from a line starts with | |
|
571 | " === END_DOC | |
|
572 | " to the end of the documents: | |
|
573 | silent /^=\{3,}\s\+END_DOC\C/,$ d | |
|
568 | 574 | |
|
569 |
|
|
|
570 |
|
|
|
571 |
|
|
|
572 |
|
|
|
573 | ||
|
574 | " Replace revision: | |
|
575 | exe "normal :1s/#version#/ v" . a:revision . "/\<CR>" | |
|
575 | " Add modeline for help doc: the modeline string is mangled intentionally | |
|
576 | " to avoid it be recognized by VIM: | |
|
577 | call append(line("$"), "") | |
|
578 | call append(line("$"), " v" . "im:tw=78:ts=8:ft=help:norl:") | |
|
576 | 579 | |
|
577 | " Save the help document: | |
|
578 | exe 'w! ' . l:doc_file | |
|
579 | exe l:go_back | |
|
580 | exe 'bw ' . l:buf | |
|
580 | " Replace revision: | |
|
581 | silent execute "normal :1s/#version#/" . s:script_version . "/\<CR>" | |
|
582 | " Save the help document and wipe out buffer: | |
|
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: | |
|
583 | exe 'helptags ' . l:vim_doc_path | |
|
584 | ||
|
585 | return 1 | |
|
587 | let &hlsearch = l:hls | |
|
588 | let &lazyredraw = l:lz | |
|
589 | return 1 | |
|
586 | 590 | endfunction |
|
587 | 591 | |
|
588 | 592 | " Section: Public functions {{{1 |
@@ -593,7 +597,7 b' endfunction' | |||
|
593 | 597 | |
|
594 | 598 | function! HGGetRevision() |
|
595 | 599 | let revision="" |
|
596 |
exec |
|
|
600 | exec <SID>HGGetStatusVars('revision', '', '') | |
|
597 | 601 | return revision |
|
598 | 602 | endfunction |
|
599 | 603 | |
@@ -612,16 +616,16 b' function! HGEnableBufferSetup()' | |||
|
612 | 616 | let g:HGCommandEnableBufferSetup=1 |
|
613 | 617 | augroup HGCommandPlugin |
|
614 | 618 | au! |
|
615 |
au BufEnter * call |
|
|
616 |
au BufWritePost * call |
|
|
619 | au BufEnter * call <SID>HGSetupBuffer() | |
|
620 | au BufWritePost * call <SID>HGSetupBuffer() | |
|
617 | 621 | " Force resetting up buffer on external file change (HG update) |
|
618 |
au FileChangedShell * call |
|
|
622 | au FileChangedShell * call <SID>HGSetupBuffer(1) | |
|
619 | 623 | augroup END |
|
620 | 624 | |
|
621 | 625 | " Only auto-load if the plugin is fully loaded. This gives other plugins a |
|
622 | 626 | " chance to run. |
|
623 | 627 | if g:loaded_hgcommand == 2 |
|
624 |
call |
|
|
628 | call <SID>HGSetupBuffer() | |
|
625 | 629 | endif |
|
626 | 630 | endfunction |
|
627 | 631 | |
@@ -662,7 +666,7 b' endfunction' | |||
|
662 | 666 | |
|
663 | 667 | " Function: s:HGAdd() {{{2 |
|
664 | 668 | function! s:HGAdd() |
|
665 |
return |
|
|
669 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('add', 'hgadd', '')) | |
|
666 | 670 | endfunction |
|
667 | 671 | |
|
668 | 672 | " Function: s:HGAnnotate(...) {{{2 |
@@ -672,7 +676,7 b' function! s:HGAnnotate(...)' | |||
|
672 | 676 | " This is a HGAnnotate buffer. Perform annotation of the version |
|
673 | 677 | " indicated by the current line. |
|
674 | 678 | let revision = substitute(getline("."),'\(^[0-9]*\):.*','\1','') |
|
675 |
if |
|
|
679 | if <SID>HGGetOption('HGCommandAnnotateParent', 0) != 0 && revision > 0 | |
|
676 | 680 | let revision = revision - 1 |
|
677 | 681 | endif |
|
678 | 682 | else |
@@ -691,7 +695,7 b' function! s:HGAnnotate(...)' | |||
|
691 | 695 | return -1 |
|
692 | 696 | endif |
|
693 | 697 | |
|
694 |
let resultBuffer= |
|
|
698 | let resultBuffer=<SID>HGDoCommand('annotate -ndu -r ' . revision, 'hgannotate', revision) | |
|
695 | 699 | "echomsg "DBG: ".resultBuffer |
|
696 | 700 | if resultBuffer != -1 |
|
697 | 701 | set filetype=HGAnnotate |
@@ -706,10 +710,10 b' function! s:HGCommit(...)' | |||
|
706 | 710 | " is used; if bang is supplied, an empty message is used; otherwise, the |
|
707 | 711 | " user is provided a buffer from which to edit the commit message. |
|
708 | 712 | if a:2 != "" || a:1 == "!" |
|
709 |
return |
|
|
713 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('commit -m "' . a:2 . '"', 'hgcommit', '')) | |
|
710 | 714 | endif |
|
711 | 715 | |
|
712 |
let hgBufferCheck= |
|
|
716 | let hgBufferCheck=<SID>HGCurrentBufferCheck() | |
|
713 | 717 | if hgBufferCheck == -1 |
|
714 | 718 | echo "Original buffer no longer exists, aborting." |
|
715 | 719 | return -1 |
@@ -725,7 +729,7 b' function! s:HGCommit(...)' | |||
|
725 | 729 | let messageFileName = tempname() |
|
726 | 730 | |
|
727 | 731 | let fileName=bufname(hgBufferCheck) |
|
728 |
let realFilePath= |
|
|
732 | let realFilePath=<SID>HGResolveLink(fileName) | |
|
729 | 733 | let newCwd=fnamemodify(realFilePath, ':h') |
|
730 | 734 | if strlen(newCwd) == 0 |
|
731 | 735 | " Account for autochdir being in effect, which will make this blank, but |
@@ -735,7 +739,7 b' function! s:HGCommit(...)' | |||
|
735 | 739 | |
|
736 | 740 | let realFileName=fnamemodify(realFilePath, ':t') |
|
737 | 741 | |
|
738 |
if |
|
|
742 | if <SID>HGEditFile(messageFileName, hgBufferCheck) == -1 | |
|
739 | 743 | return |
|
740 | 744 | endif |
|
741 | 745 | |
@@ -766,9 +770,9 b' function! s:HGCommit(...)' | |||
|
766 | 770 | silent put =\"HG: Enter Log. Lines beginning with `HG:' are removed automatically\" |
|
767 | 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 | 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 | 776 | silent put ='HG: or write this buffer' |
|
773 | 777 | endif |
|
774 | 778 | |
@@ -797,7 +801,7 b' function! s:HGDiff(...)' | |||
|
797 | 801 | let caption = '' |
|
798 | 802 | endif |
|
799 | 803 | |
|
800 |
let hgdiffopt= |
|
|
804 | let hgdiffopt=<SID>HGGetOption('HGCommandDiffOpt', 'w') | |
|
801 | 805 | |
|
802 | 806 | if hgdiffopt == "" |
|
803 | 807 | let diffoptionstring="" |
@@ -805,8 +809,8 b' function! s:HGDiff(...)' | |||
|
805 | 809 | let diffoptionstring=" -" . hgdiffopt . " " |
|
806 | 810 | endif |
|
807 | 811 | |
|
808 |
let resultBuffer = |
|
|
809 |
if resultBuffer != -1 |
|
|
812 | let resultBuffer = <SID>HGDoCommand('diff ' . diffoptionstring . revOptions , 'hgdiff', caption) | |
|
813 | if resultBuffer != -1 | |
|
810 | 814 | set filetype=diff |
|
811 | 815 | endif |
|
812 | 816 | return resultBuffer |
@@ -815,7 +819,7 b' endfunction' | |||
|
815 | 819 | |
|
816 | 820 | " Function: s:HGGotoOriginal(["!]) {{{2 |
|
817 | 821 | function! s:HGGotoOriginal(...) |
|
818 |
let origBuffNR = |
|
|
822 | let origBuffNR = <SID>HGCurrentBufferCheck() | |
|
819 | 823 | if origBuffNR > 0 |
|
820 | 824 | let origWinNR = bufwinnr(origBuffNR) |
|
821 | 825 | if origWinNR == -1 |
@@ -845,11 +849,11 b' function! s:HGFinishCommit(messageFile, ' | |||
|
845 | 849 | if strlen(a:targetDir) > 0 |
|
846 | 850 | execute 'cd' escape(a:targetDir, ' ') |
|
847 | 851 | endif |
|
848 |
let resultBuffer= |
|
|
852 | let resultBuffer=<SID>HGCreateCommandBuffer('commit -l "' . a:messageFile . '" "'. a:targetFile . '"', 'hgcommit', '', a:origBuffNR) | |
|
849 | 853 | execute 'cd' escape(oldCwd, ' ') |
|
850 | 854 | execute 'bw' escape(a:messageFile, ' *?\') |
|
851 | 855 | silent execute 'call delete("' . a:messageFile . '")' |
|
852 |
return |
|
|
856 | return <SID>HGMarkOrigBufferForSetup(resultBuffer) | |
|
853 | 857 | else |
|
854 | 858 | echoerr "Can't read message file; no commit is possible." |
|
855 | 859 | return -1 |
@@ -866,7 +870,7 b' function! s:HGLog(...)' | |||
|
866 | 870 | let caption = a:1 |
|
867 | 871 | endif |
|
868 | 872 | |
|
869 |
let resultBuffer= |
|
|
873 | let resultBuffer=<SID>HGDoCommand('log' . versionOption, 'hglog', caption) | |
|
870 | 874 | if resultBuffer != "" |
|
871 | 875 | set filetype=rcslog |
|
872 | 876 | endif |
@@ -875,14 +879,14 b' endfunction' | |||
|
875 | 879 | |
|
876 | 880 | " Function: s:HGRevert() {{{2 |
|
877 | 881 | function! s:HGRevert() |
|
878 |
return |
|
|
882 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('revert', 'hgrevert', '')) | |
|
879 | 883 | endfunction |
|
880 | 884 | |
|
881 | 885 | " Function: s:HGReview(...) {{{2 |
|
882 | 886 | function! s:HGReview(...) |
|
883 | 887 | if a:0 == 0 |
|
884 | 888 | let versiontag="" |
|
885 |
if |
|
|
889 | if <SID>HGGetOption('HGCommandInteractive', 0) | |
|
886 | 890 | let versiontag=input('Revision: ') |
|
887 | 891 | endif |
|
888 | 892 | if versiontag == "" |
@@ -896,7 +900,7 b' function! s:HGReview(...)' | |||
|
896 | 900 | let versionOption=" -r " . versiontag . " " |
|
897 | 901 | endif |
|
898 | 902 | |
|
899 |
let resultBuffer = |
|
|
903 | let resultBuffer = <SID>HGDoCommand('cat' . versionOption, 'hgreview', versiontag) | |
|
900 | 904 | if resultBuffer > 0 |
|
901 | 905 | let &filetype=getbufvar(b:HGOrigBuffNR, '&filetype') |
|
902 | 906 | endif |
@@ -906,18 +910,18 b' endfunction' | |||
|
906 | 910 | |
|
907 | 911 | " Function: s:HGStatus() {{{2 |
|
908 | 912 | function! s:HGStatus() |
|
909 |
return |
|
|
913 | return <SID>HGDoCommand('status', 'hgstatus', '') | |
|
910 | 914 | endfunction |
|
911 | 915 | |
|
912 | 916 | |
|
913 | 917 | " Function: s:HGUpdate() {{{2 |
|
914 | 918 | function! s:HGUpdate() |
|
915 |
return |
|
|
919 | return <SID>HGMarkOrigBufferForSetup(<SID>HGDoCommand('update', 'update', '')) | |
|
916 | 920 | endfunction |
|
917 | 921 | |
|
918 | 922 | " Function: s:HGVimDiff(...) {{{2 |
|
919 | 923 | function! s:HGVimDiff(...) |
|
920 |
let originalBuffer = |
|
|
924 | let originalBuffer = <SID>HGCurrentBufferCheck() | |
|
921 | 925 | let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 |
|
922 | 926 | try |
|
923 | 927 | " If there's already a VimDiff'ed window, restore it. |
@@ -925,16 +929,16 b' function! s:HGVimDiff(...)' | |||
|
925 | 929 | |
|
926 | 930 | if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer |
|
927 | 931 | " Clear the existing vimdiff setup by removing the result buffers. |
|
928 |
call |
|
|
932 | call <SID>HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') | |
|
929 | 933 | endif |
|
930 | 934 | |
|
931 | 935 | " Split and diff |
|
932 | 936 | if(a:0 == 2) |
|
933 | 937 | " Reset the vimdiff system, as 2 explicit versions were provided. |
|
934 | 938 | if exists('s:vimDiffSourceBuffer') |
|
935 |
call |
|
|
939 | call <SID>HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') | |
|
936 | 940 | endif |
|
937 |
let resultBuffer = |
|
|
941 | let resultBuffer = <SID>HGReview(a:1) | |
|
938 | 942 | if resultBuffer < 0 |
|
939 | 943 | echomsg "Can't open HG revision " . a:1 |
|
940 | 944 | return resultBuffer |
@@ -945,10 +949,10 b' function! s:HGVimDiff(...)' | |||
|
945 | 949 | let s:vimDiffScratchList = '{'. resultBuffer . '}' |
|
946 | 950 | " If no split method is defined, cheat, and set it to vertical. |
|
947 | 951 | try |
|
948 |
call |
|
|
949 |
let resultBuffer= |
|
|
952 | call <SID>HGOverrideOption('HGCommandSplit', <SID>HGGetOption('HGCommandDiffSplit', <SID>HGGetOption('HGCommandSplit', 'vertical'))) | |
|
953 | let resultBuffer=<SID>HGReview(a:2) | |
|
950 | 954 | finally |
|
951 |
call |
|
|
955 | call <SID>HGOverrideOption('HGCommandSplit') | |
|
952 | 956 | endtry |
|
953 | 957 | if resultBuffer < 0 |
|
954 | 958 | echomsg "Can't open HG revision " . a:1 |
@@ -962,16 +966,16 b' function! s:HGVimDiff(...)' | |||
|
962 | 966 | " Add new buffer |
|
963 | 967 | try |
|
964 | 968 | " Force splitting behavior, otherwise why use vimdiff? |
|
965 |
call |
|
|
966 |
call |
|
|
969 | call <SID>HGOverrideOption("HGCommandEdit", "split") | |
|
970 | call <SID>HGOverrideOption("HGCommandSplit", <SID>HGGetOption('HGCommandDiffSplit', <SID>HGGetOption('HGCommandSplit', 'vertical'))) | |
|
967 | 971 | if(a:0 == 0) |
|
968 |
let resultBuffer= |
|
|
972 | let resultBuffer=<SID>HGReview() | |
|
969 | 973 | else |
|
970 |
let resultBuffer= |
|
|
974 | let resultBuffer=<SID>HGReview(a:1) | |
|
971 | 975 | endif |
|
972 | 976 | finally |
|
973 |
call |
|
|
974 |
call |
|
|
977 | call <SID>HGOverrideOption("HGCommandEdit") | |
|
978 | call <SID>HGOverrideOption("HGCommandSplit") | |
|
975 | 979 | endtry |
|
976 | 980 | if resultBuffer < 0 |
|
977 | 981 | echomsg "Can't open current HG revision" |
@@ -990,14 +994,14 b' function! s:HGVimDiff(...)' | |||
|
990 | 994 | wincmd W |
|
991 | 995 | execute 'buffer' originalBuffer |
|
992 | 996 | " Store info for later original buffer restore |
|
993 |
let s:vimDiffRestoreCmd = |
|
|
997 | let s:vimDiffRestoreCmd = | |
|
994 | 998 | \ "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")" |
|
995 | 999 | \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")" |
|
996 | 1000 | \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")" |
|
997 | 1001 | \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')" |
|
998 | 1002 | \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")" |
|
999 | 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 | 1005 | diffthis |
|
1002 | 1006 | wincmd w |
|
1003 | 1007 | else |
@@ -1027,17 +1031,17 b' endfunction' | |||
|
1027 | 1031 | |
|
1028 | 1032 | " Section: Command definitions {{{1 |
|
1029 | 1033 | " Section: Primary commands {{{2 |
|
1030 |
com! HGAdd call |
|
|
1031 |
com! -nargs=? HGAnnotate call |
|
|
1032 |
com! -bang -nargs=? HGCommit call |
|
|
1033 |
com! -nargs=* HGDiff call |
|
|
1034 |
com! -bang HGGotoOriginal call |
|
|
1035 |
com! -nargs=? HGLog call |
|
|
1036 |
com! HGRevert call |
|
|
1037 |
com! -nargs=? HGReview call |
|
|
1038 |
com! HGStatus call |
|
|
1039 |
com! HGUpdate call |
|
|
1040 |
com! -nargs=* HGVimDiff call |
|
|
1034 | com! HGAdd call <SID>HGAdd() | |
|
1035 | com! -nargs=? HGAnnotate call <SID>HGAnnotate(<f-args>) | |
|
1036 | com! -bang -nargs=? HGCommit call <SID>HGCommit(<q-bang>, <q-args>) | |
|
1037 | com! -nargs=* HGDiff call <SID>HGDiff(<f-args>) | |
|
1038 | com! -bang HGGotoOriginal call <SID>HGGotoOriginal(<q-bang>) | |
|
1039 | com! -nargs=? HGLog call <SID>HGLog(<f-args>) | |
|
1040 | com! HGRevert call <SID>HGRevert() | |
|
1041 | com! -nargs=? HGReview call <SID>HGReview(<f-args>) | |
|
1042 | com! HGStatus call <SID>HGStatus() | |
|
1043 | com! HGUpdate call <SID>HGUpdate() | |
|
1044 | com! -nargs=* HGVimDiff call <SID>HGVimDiff(<f-args>) | |
|
1041 | 1045 | |
|
1042 | 1046 | " Section: HG buffer management commands {{{2 |
|
1043 | 1047 | com! HGDisableBufferSetup call HGDisableBufferSetup() |
@@ -1173,7 +1177,7 b' endfunction' | |||
|
1173 | 1177 | |
|
1174 | 1178 | augroup HGVimDiffRestore |
|
1175 | 1179 | au! |
|
1176 |
au BufUnload * call |
|
|
1180 | au BufUnload * call <SID>HGVimDiffRestore(expand("<abuf>")) | |
|
1177 | 1181 | augroup END |
|
1178 | 1182 | |
|
1179 | 1183 | " Section: Optional activation of buffer management {{{1 |
@@ -1183,20 +1187,24 b" if s:HGGetOption('HGCommandEnableBufferS" | |||
|
1183 | 1187 | endif |
|
1184 | 1188 | |
|
1185 | 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 | 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 | 1203 | let loaded_hgcommand=2 |
|
1199 | 1204 | silent do HGCommand User HGPluginFinish |
|
1205 | ||
|
1206 | let &cpo = s:save_cpo | |
|
1207 | unlet s:save_cpo | |
|
1200 | 1208 | " vim:se expandtab sts=2 sw=2: |
|
1201 | 1209 | finish |
|
1202 | 1210 | |
@@ -1228,16 +1236,16 b' 1. Contents\t\t\t\t\t\t *hgcommand-contents*' | |||
|
1228 | 1236 | ============================================================================== |
|
1229 | 1237 | 2. HGCommand Installation *hgcommand-install* |
|
1230 | 1238 | |
|
1231 |
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 |
|
|
1239 | In order to install the plugin, place the hgcommand.vim file into a plugin' | |
|
1240 | directory in your runtime path (please see |add-global-plugin| and | |
|
1233 | 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 | 1244 | specifying event handlers. Please see |hgcommand-customize| for more |
|
1237 | 1245 | details. |
|
1238 | 1246 | |
|
1239 | 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 | 1249 | loaded for the first time. |
|
1242 | 1250 | |
|
1243 | 1251 | ============================================================================== |
@@ -1245,32 +1253,32 b' 2. HGCommand Installation\t\t\t\t *hgcomma' | |||
|
1245 | 1253 | 3. HGCommand Intro *hgcommand* |
|
1246 | 1254 | *hgcommand-intro* |
|
1247 | 1255 | |
|
1248 |
The HGCommand plugin provides global ex commands for manipulating |
|
|
1249 |
HG-controlled source files. In general, each command operates on the |
|
|
1250 |
current buffer and accomplishes a separate hg function, such as update, |
|
|
1256 | The HGCommand plugin provides global ex commands for manipulating | |
|
1257 | HG-controlled source files. In general, each command operates on the | |
|
1258 | current buffer and accomplishes a separate hg function, such as update, | |
|
1251 | 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 |
|
|
1253 |
scratch buffer. Several buffer variables are defined for those scratch |
|
|
1260 | available commands). The results of each operation are displayed in a | |
|
1261 | scratch buffer. Several buffer variables are defined for those scratch | |
|
1254 | 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 | 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 |
|
|
1260 |
as though it was invoked on the original file and splits the screen so that |
|
|
1267 | For convenience, any HGCommand invoked on a HGCommand scratch buffer acts | |
|
1268 | as though it was invoked on the original file and splits the screen so that | |
|
1261 | 1269 | the output appears in a new window. |
|
1262 | 1270 | |
|
1263 |
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 |
|
|
1271 | Many of the commands accept revisions as arguments. By default, most | |
|
1272 | operate on the most recent revision on the current branch if no revision is | |
|
1265 | 1273 | specified (though see |HGCommandInteractive| to prompt instead). |
|
1266 | 1274 | |
|
1267 |
Each HGCommand is mapped to a key sequence starting with the <Leader> |
|
|
1268 |
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 |
|
|
1270 |
fashion for plugin mappings. For examples, please see |
|
|
1275 | Each HGCommand is mapped to a key sequence starting with the <Leader> | |
|
1276 | keystroke. The default mappings may be overridden by supplying different | |
|
1277 | mappings before the plugin is loaded, such as in the vimrc, in the standard | |
|
1278 | fashion for plugin mappings. For examples, please see | |
|
1271 | 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 | 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 | 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 | 1306 | not commit the newly-added file. |
|
1299 | 1307 | |
|
1300 | 1308 | :HGAnnotate *:HGAnnotate* |
|
1301 | 1309 | |
|
1302 |
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 |
|
|
1304 |
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 |
|
|
1310 | This command performs "hg annotate" on the current file. If an argument is | |
|
1311 | given, the argument is used as a revision number to display. If not given | |
|
1312 | an argument, it uses the most recent version of the file on the current | |
|
1313 | branch. Additionally, if the current buffer is a HGAnnotate buffer | |
|
1306 | 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 |
|
|
1309 |
version previous to the one on the current line is used instead. This |
|
|
1316 | If the |HGCommandAnnotateParent| variable is set to a non-zero value, the | |
|
1317 | version previous to the one on the current line is used instead. This | |
|
1310 | 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 | 1321 | take advantage of the bundled syntax file. |
|
1314 | 1322 | |
|
1315 | 1323 | |
|
1316 | 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 | 1327 | the log message. |
|
1320 | 1328 | |
|
1321 | 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 |
|
|
1324 |
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 |
|
|
1326 |
that log message. The commit can be abandoned if the log message buffer is |
|
|
1331 | If called with no arguments, this is a two-step command. The first step | |
|
1332 | opens a buffer to accept a log message. When that buffer is written, it is | |
|
1333 | automatically closed and the file is committed using the information from | |
|
1334 | that log message. The commit can be abandoned if the log message buffer is | |
|
1327 | 1335 | deleted or wiped before being written. |
|
1328 | 1336 | |
|
1329 |
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. |
|
|
1331 |
This is useful if the |HGCommandCommitOnWrite| variable is set to 0 to |
|
|
1337 | Alternatively, the mapping that is used to invoke :HGCommit (by default | |
|
1338 | <Leader>hgc) can be used in the log message buffer to immediately commit. | |
|
1339 | This is useful if the |HGCommandCommitOnWrite| variable is set to 0 to | |
|
1332 | 1340 | disable the normal commit-on-write behavior. |
|
1333 | 1341 | |
|
1334 | 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 | 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 | 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 | 1351 | the current file. |
|
1344 | 1352 | |
|
1345 |
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 |
|
|
1353 | This command uses the 'HGCommandDiffOpt' variable to specify diff options. | |
|
1354 | If that variable does not exist, then 'wbBc' is assumed. If you wish to | |
|
1347 | 1355 | have no options, then set it to the empty string. |
|
1348 | 1356 | |
|
1349 | 1357 | |
|
1350 | 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 | 1361 | current buffer is a HG command output buffer. |
|
1354 | 1362 | |
|
1355 | 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 | 1366 | output buffers for the source buffer. |
|
1359 | 1367 | |
|
1360 | 1368 | :HGLog *:HGLog* |
|
1361 | 1369 | |
|
1362 | 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 | 1373 | "hg log". |
|
1366 | 1374 | |
|
1367 | 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 | 1378 | in order to wipe out any undesired changes. |
|
1371 | ||
|
1379 | ||
|
1372 | 1380 | :HGReview *:HGReview* |
|
1373 | 1381 | |
|
1374 |
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 |
|
|
1382 | Retrieves a particular version of the current file. If no argument is | |
|
1383 | given, the most recent version of the file on the current branch is | |
|
1376 | 1384 | retrieved. Otherwise, the specified version is retrieved. |
|
1377 | 1385 | |
|
1378 | 1386 | :HGStatus *:HGStatus* |
@@ -1381,37 +1389,37 b' 4.1 HGCommand commands\t\t\t\t\t *hgcommand-' | |||
|
1381 | 1389 | |
|
1382 | 1390 | :HGUpdate *:HGUpdate* |
|
1383 | 1391 | |
|
1384 |
Performs "hg update" on the current file. This intentionally does not |
|
|
1385 |
automatically reload the current buffer, though vim should prompt the user |
|
|
1392 | Performs "hg update" on the current file. This intentionally does not | |
|
1393 | automatically reload the current buffer, though vim should prompt the user | |
|
1386 | 1394 | to do so if the underlying file is altered by this command. |
|
1387 | 1395 | |
|
1388 | 1396 | :HGVimDiff *:HGVimDiff* |
|
1389 | 1397 | |
|
1390 |
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 |
|
|
1392 |
specified revision. If no revision is specified, the most recent version |
|
|
1398 | With no arguments, this prompts the user for a revision and then uses | |
|
1399 | vimdiff to display the differences between the current file and the | |
|
1400 | specified revision. If no revision is specified, the most recent version | |
|
1393 | 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 |
|
|
1396 |
two arguments, the differences between the two revisions is displayed using |
|
|
1403 | With one argument, that argument is used as the revision as above. With | |
|
1404 | two arguments, the differences between the two revisions is displayed using | |
|
1397 | 1405 | vimdiff. |
|
1398 | 1406 | |
|
1399 |
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 |
|
|
1407 | With either zero or one argument, the original buffer is used to perform | |
|
1408 | the vimdiff. When the other buffer is closed, the original buffer will be | |
|
1401 | 1409 | returned to normal mode. |
|
1402 | 1410 | |
|
1403 |
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. |
|
|
1411 | Once vimdiff mode is started using the above methods, additional vimdiff | |
|
1412 | buffers may be added by passing a single version argument to the command. | |
|
1405 | 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 |
|
|
1408 |
versions. Additionally, invoking the command on a different file will |
|
|
1415 | Using the 2-argument form of the command resets the vimdiff to only those 2 | |
|
1416 | versions. Additionally, invoking the command on a different file will | |
|
1409 | 1417 | close the previous vimdiff buffers. |
|
1410 | 1418 | |
|
1411 | 1419 | |
|
1412 | 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 | 1423 | the default (no-argument) form of each command. |
|
1416 | 1424 | |
|
1417 | 1425 | <Leader>hga HGAdd |
@@ -1428,20 +1436,20 b' 4.2 Mappings\t\t\t\t\t\t *hgcommand-mappings*' | |||
|
1428 | 1436 | |
|
1429 | 1437 | *hgcommand-mappings-override* |
|
1430 | 1438 | |
|
1431 |
The default mappings can be overriden by user-provided instead by mapping |
|
|
1432 |
to <Plug>CommandName. This is especially useful when these mappings |
|
|
1433 |
collide with other existing mappings (vim will warn of this during plugin |
|
|
1439 | The default mappings can be overriden by user-provided instead by mapping | |
|
1440 | to <Plug>CommandName. This is especially useful when these mappings | |
|
1441 | collide with other existing mappings (vim will warn of this during plugin | |
|
1434 | 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 | 1445 | '\add', add the following to the vimrc: > |
|
1438 | 1446 | |
|
1439 | 1447 | nmap \add <Plug>HGAdd |
|
1440 | 1448 | < |
|
1441 | 1449 | 4.3 Automatic buffer variables *hgcommand-buffer-variables* |
|
1442 | 1450 | |
|
1443 |
Several buffer variables are defined in each HGCommand result buffer. |
|
|
1444 |
These may be useful for additional customization in callbacks defined in |
|
|
1451 | Several buffer variables are defined in each HGCommand result buffer. | |
|
1452 | These may be useful for additional customization in callbacks defined in | |
|
1445 | 1453 | the event handlers (please see |hgcommand-events|). |
|
1446 | 1454 | |
|
1447 | 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 | 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 | 1464 | buffer. |
|
1457 | 1465 | ============================================================================== |
|
1458 | 1466 | |
|
1459 | 1467 | 5. Configuration and customization *hgcommand-customize* |
|
1460 | 1468 | *hgcommand-config* |
|
1461 | 1469 | |
|
1462 |
The HGCommand plugin can be configured in two ways: by setting |
|
|
1463 |
configuration variables (see |hgcommand-options|) or by defining HGCommand |
|
|
1464 |
event handlers (see |hgcommand-events|). Additionally, the HGCommand |
|
|
1465 |
plugin provides several option for naming the HG result buffers (see |
|
|
1466 |
|hgcommand-naming|) and supported a customized status line (see |
|
|
1470 | The HGCommand plugin can be configured in two ways: by setting | |
|
1471 | configuration variables (see |hgcommand-options|) or by defining HGCommand | |
|
1472 | event handlers (see |hgcommand-events|). Additionally, the HGCommand | |
|
1473 | plugin provides several option for naming the HG result buffers (see | |
|
1474 | |hgcommand-naming|) and supported a customized status line (see | |
|
1467 | 1475 | |hgcommand-statusline| and |hgcommand-buffer-management|). |
|
1468 | 1476 | |
|
1469 | 1477 | 5.1 HGCommand configuration variables *hgcommand-options* |
|
1470 | 1478 | |
|
1471 |
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 |
|
|
1479 | Several variables affect the plugin's behavior. These variables are | |
|
1480 | checked at time of execution, and may be defined at the window, buffer, or | |
|
1473 | 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 | 1499 | HGCommandAnnotateParent *HGCommandAnnotateParent* |
|
1492 | 1500 | |
|
1493 |
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 |
|
|
1495 |
previous to that displayed on the current line. If not set, it defaults to |
|
|
1501 | This variable, if set to a non-zero value, causes the zero-argument form of | |
|
1502 | HGAnnotate when invoked on a HGAnnotate buffer to go to the version | |
|
1503 | previous to that displayed on the current line. If not set, it defaults to | |
|
1496 | 1504 | 0. |
|
1497 | 1505 | |
|
1498 | 1506 | HGCommandCommitOnWrite *HGCommandCommitOnWrite* |
|
1499 | 1507 | |
|
1500 |
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 |
|
|
1502 |
set to zero, only the HGCommit mapping will cause the pending commit to |
|
|
1508 | This variable, if set to a non-zero value, causes the pending hg commit to | |
|
1509 | take place immediately as soon as the log message buffer is written. If | |
|
1510 | set to zero, only the HGCommit mapping will cause the pending commit to | |
|
1503 | 1511 | occur. If not set, it defaults to 1. |
|
1504 | 1512 | |
|
1505 | 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 | 1516 | set, it defaults to "hg". |
|
1509 | 1517 | |
|
1510 | 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 | 1521 | buffers to automatically delete themselves when hidden. |
|
1514 | 1522 | |
|
1515 | 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 | 1526 | HG. If not set, it defaults to 'w'. |
|
1519 | 1527 | |
|
1520 | 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 | 1531 | created with |:HGVimDiff|. |
|
1524 | 1532 | |
|
1525 | 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 | 1536 | split ('split'). If not set, it defaults to 'edit'. |
|
1529 | 1537 | |
|
1530 | 1538 | HGCommandEnableBufferSetup *HGCommandEnableBufferSetup* |
|
1531 | 1539 | |
|
1532 |
This variable, if set to a non-zero value, activates HG buffer management |
|
|
1533 |
mode see (|hgcommand-buffer-management|). This mode means that three |
|
|
1534 |
buffer variables, 'HGRepository', 'HGRevision' and 'HGBranch', are set if |
|
|
1535 |
the file is HG-controlled. This is useful for displaying version |
|
|
1540 | This variable, if set to a non-zero value, activates HG buffer management | |
|
1541 | mode see (|hgcommand-buffer-management|). This mode means that three | |
|
1542 | buffer variables, 'HGRepository', 'HGRevision' and 'HGBranch', are set if | |
|
1543 | the file is HG-controlled. This is useful for displaying version | |
|
1536 | 1544 | information in the status bar. |
|
1537 | 1545 | |
|
1538 | 1546 | HGCommandInteractive *HGCommandInteractive* |
|
1539 | 1547 | |
|
1540 |
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 |
|
|
1548 | This variable, if set to a non-zero value, causes appropriate commands (for | |
|
1549 | the moment, only |:HGReview|) to query the user for a revision to use | |
|
1542 | 1550 | instead of the current revision if none is specified. |
|
1543 | 1551 | |
|
1544 | 1552 | HGCommandNameMarker *HGCommandNameMarker* |
|
1545 | 1553 | |
|
1546 |
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 |
|
|
1548 |
has no effect unless |HGCommandNameResultBuffers| is set to a true value. |
|
|
1549 |
If not set, it defaults to '_'. |
|
|
1554 | This variable, if set, configures the special attention-getting characters | |
|
1555 | that appear on either side of the hg buffer type in the buffer name. This | |
|
1556 | has no effect unless |HGCommandNameResultBuffers| is set to a true value. | |
|
1557 | If not set, it defaults to '_'. | |
|
1550 | 1558 | |
|
1551 | 1559 | HGCommandNameResultBuffers *HGCommandNameResultBuffers* |
|
1552 | 1560 | |
|
1553 |
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 |
|
|
1561 | This variable, if set to a true value, causes the hg result buffers to be | |
|
1562 | named in the old way ('<source file name> _<hg command>_'). If not set or | |
|
1555 | 1563 | set to a false value, the result buffer is nameless. |
|
1556 | 1564 | |
|
1557 | 1565 | HGCommandSplit *HGCommandSplit* |
|
1558 | 1566 | |
|
1559 |
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 |
|
|
1561 |
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 |
|
|
1563 |
another. If set to 'vertical', the resulting windows will be side-by-side. |
|
|
1567 | This variable controls the orientation of the various window splits that | |
|
1568 | may occur (such as with HGVimDiff, when using a HG command on a HG command | |
|
1569 | buffer, or when the |HGCommandEdit| variable is set to 'split'. If set to | |
|
1570 | 'horizontal', the resulting windows will be on stacked on top of one | |
|
1571 | another. If set to 'vertical', the resulting windows will be side-by-side. | |
|
1564 | 1572 | If not set, it defaults to 'horizontal' for all but HGVimDiff windows. |
|
1565 | 1573 | |
|
1566 | 1574 | 5.2 HGCommand events *hgcommand-events* |
|
1567 | 1575 | |
|
1568 |
For additional customization, HGCommand can trigger user-defined events. |
|
|
1569 |
Event handlers are provided by defining User event autocommands (see |
|
|
1570 |
|autocommand|, |User|) in the HGCommand group with patterns matching the |
|
|
1576 | For additional customization, HGCommand can trigger user-defined events. | |
|
1577 | Event handlers are provided by defining User event autocommands (see | |
|
1578 | |autocommand|, |User|) in the HGCommand group with patterns matching the | |
|
1571 | 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 | 1582 | mapping to quit a HGCommand scratch buffer: > |
|
1575 | 1583 | |
|
1576 | 1584 | augroup HGCommand |
@@ -1582,10 +1590,10 b' 5.2 HGCommand events\t\t\t\t *hgc' | |||
|
1582 | 1590 | The following hooks are available: |
|
1583 | 1591 | |
|
1584 | 1592 | HGBufferCreated This event is fired just after a hg command result |
|
1585 |
buffer is created and filled with the result of a hg |
|
|
1586 |
command. It is executed within the context of the HG |
|
|
1587 |
command buffer. The HGCommand buffer variables may be |
|
|
1588 |
useful for handlers of this event (please see |
|
|
1593 | buffer is created and filled with the result of a hg | |
|
1594 | command. It is executed within the context of the HG | |
|
1595 | command buffer. The HGCommand buffer variables may be | |
|
1596 | useful for handlers of this event (please see | |
|
1589 | 1597 | |hgcommand-buffer-variables|). |
|
1590 | 1598 | |
|
1591 | 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 | 1606 | loads. |
|
1599 | 1607 | |
|
1600 | 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 | 1610 | window placement and focus. |
|
1603 | 1611 | |
|
1604 | 1612 | 5.3 HGCommand buffer naming *hgcommand-naming* |
|
1605 | 1613 | |
|
1606 |
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 |
|
|
1608 |
used to customize the statusline option so that the user may fully control |
|
|
1614 | By default, the buffers containing the result of HG commands are nameless | |
|
1615 | scratch buffers. It is intended that buffer variables of those buffers be | |
|
1616 | used to customize the statusline option so that the user may fully control | |
|
1609 | 1617 | the display of result buffers. |
|
1610 | 1618 | |
|
1611 |
If the old-style naming is desired, please enable the |
|
|
1612 |
|HGCommandNameResultBuffers| variable. Then, each result buffer will |
|
|
1613 |
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 |
|
|
1619 | If the old-style naming is desired, please enable the | |
|
1620 | |HGCommandNameResultBuffers| variable. Then, each result buffer will | |
|
1621 | receive a unique name that includes the source file name, the HG command, | |
|
1622 | and any extra data (such as revision numbers) that were part of the | |
|
1615 | 1623 | command. |
|
1616 | 1624 | |
|
1617 | 1625 | 5.4 HGCommand status line support *hgcommand-statusline* |
|
1618 | 1626 | |
|
1619 |
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 |
|
|
1621 |
the |'statusline'| option is provided by the plugin, HGGetStatusLine(). In |
|
|
1622 |
order to use that function in the status line, do something like the |
|
|
1627 | It is intended that the user will customize the |'statusline'| option to | |
|
1628 | include HG result buffer attributes. A sample function that may be used in | |
|
1629 | the |'statusline'| option is provided by the plugin, HGGetStatusLine(). In | |
|
1630 | order to use that function in the status line, do something like the | |
|
1623 | 1631 | following: > |
|
1624 | 1632 | |
|
1625 | 1633 | set statusline=%<%f\ %{HGGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P |
|
1626 | 1634 | < |
|
1627 | 1635 | of which %{HGGetStatusLine()} is the relevant portion. |
|
1628 | 1636 | |
|
1629 |
The sample HGGetStatusLine() function handles both HG result buffers and |
|
|
1630 |
HG-managed files if HGCommand buffer management is enabled (please see |
|
|
1637 | The sample HGGetStatusLine() function handles both HG result buffers and | |
|
1638 | HG-managed files if HGCommand buffer management is enabled (please see | |
|
1631 | 1639 | |hgcommand-buffer-management|). |
|
1632 | 1640 | |
|
1633 | 1641 | 5.5 HGCommand buffer management *hgcommand-buffer-management* |
|
1634 | 1642 | |
|
1635 |
The HGCommand plugin can operate in buffer management mode, which means |
|
|
1636 |
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 |
|
|
1638 |
status' will be invoked at each entry into a buffer (during the |BufEnter| |
|
|
1643 | The HGCommand plugin can operate in buffer management mode, which means | |
|
1644 | that it attempts to set two buffer variables ('HGRevision' and 'HGBranch') | |
|
1645 | upon entry into a buffer. This is rather slow because it means that 'hg | |
|
1646 | status' will be invoked at each entry into a buffer (during the |BufEnter| | |
|
1639 | 1647 | autocommand). |
|
1640 | 1648 | |
|
1641 |
This mode is enabl |
|
|
1642 |
|HGCommandEnableBufferSetup| variable to a false (zero) value. Enabling |
|
|
1643 |
this mode simply provides the buffer variables mentioned above. The user |
|
|
1644 |
must explicitly include those in the |'statusline'| option if they are to |
|
|
1649 | This mode is enabled by default. In order to disable it, set the | |
|
1650 | |HGCommandEnableBufferSetup| variable to a false (zero) value. Enabling | |
|
1651 | this mode simply provides the buffer variables mentioned above. The user | |
|
1652 | must explicitly include those in the |'statusline'| option if they are to | |
|
1645 | 1653 | appear in the status line (but see |hgcommand-statusline| for a simple way |
|
1646 | 1654 | to do that). |
|
1647 | 1655 | |
@@ -1655,10 +1663,10 b' 9.1 Split window annotation, by Michael ' | |||
|
1655 | 1663 | \:set nowrap<CR> |
|
1656 | 1664 | < |
|
1657 | 1665 | |
|
1658 |
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 |
|
|
1660 |
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 |
|
|
1666 | This splits the buffer vertically, puts an annotation on the left (minus | |
|
1667 | the header) with the width set to 40. An editable/normal copy is placed on | |
|
1668 | the right. The two versions are scroll locked so they move as one. and | |
|
1669 | wrapping is turned off so that the lines line up correctly. The advantages | |
|
1662 | 1670 | are... |
|
1663 | 1671 | |
|
1664 | 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 | 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 |
|
|
1675 |
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 |
|
|
1682 | HGVimDiff, when using the original (real) source buffer as one of the diff | |
|
1683 | buffers, uses some hacks to try to restore the state of the original buffer | |
|
1684 | when the scratch buffer containing the other version is destroyed. There | |
|
1677 | 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 | 1695 | " v im:tw=78:ts=8:ft=help:norl: |
|
1688 | 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 | 14 | </head> |
|
15 | 15 | |
|
16 | 16 | <body> |
|
17 | <h1>Mercurial version 0.9 for Windows</h1> | |
|
17 | <h1>Mercurial version 0.9.1 for Windows</h1> | |
|
18 | 18 | |
|
19 | 19 | <p>Welcome to Mercurial for Windows!</p> |
|
20 | 20 |
@@ -4,7 +4,7 b'' | |||
|
4 | 4 | [Setup] |
|
5 | 5 | AppCopyright=Copyright 2005, 2006 Matt Mackall and others |
|
6 | 6 | AppName=Mercurial |
|
7 | AppVerName=Mercurial version 0.9 | |
|
7 | AppVerName=Mercurial version 0.9.1 | |
|
8 | 8 | InfoAfterFile=contrib/win32/postinstall.txt |
|
9 | 9 | LicenseFile=COPYING |
|
10 | 10 | ShowLanguageDialog=yes |
@@ -14,10 +14,10 b' AppSupportURL=http://www.selenic.com/mer' | |||
|
14 | 14 | AppUpdatesURL=http://www.selenic.com/mercurial |
|
15 | 15 | AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} |
|
16 | 16 | AppContact=mercurial@selenic.com |
|
17 | OutputBaseFilename=Mercurial-0.9 | |
|
17 | OutputBaseFilename=Mercurial-0.9.1 | |
|
18 | 18 | DefaultDirName={sd}\Mercurial |
|
19 | 19 | SourceDir=C:\hg\hg-release |
|
20 | VersionInfoVersion=0.9 | |
|
20 | VersionInfoVersion=0.9.1 | |
|
21 | 21 | VersionInfoDescription=Mercurial distributed SCM |
|
22 | 22 | VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others |
|
23 | 23 | VersionInfoCompany=Matt Mackall and others |
@@ -7,6 +7,62 b' file that comes with this package.' | |||
|
7 | 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 | 66 | 2006-05-10 v0.9 |
|
11 | 67 | |
|
12 | 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 | 217 | COPYING |
|
218 | 218 | ------- |
|
219 | Copyright \(C) 2005 Matt Mackall. | |
|
219 | Copyright \(C) 2005, 2006 Matt Mackall. | |
|
220 | 220 | Free use of this software is granted under the terms of the GNU General |
|
221 | 221 | Public License (GPL). |
@@ -30,6 +30,6 b' hg(1) - the command line interface to Me' | |||
|
30 | 30 | |
|
31 | 31 | COPYING |
|
32 | 32 | ------- |
|
33 | Copyright \(C) 2005 Matt Mackall. | |
|
33 | Copyright \(C) 2005, 2006 Matt Mackall. | |
|
34 | 34 | Free use of this software is granted under the terms of the GNU General |
|
35 | 35 | Public License (GPL). |
@@ -138,9 +138,17 b' email::' | |||
|
138 | 138 | from;; |
|
139 | 139 | Optional. Email address to use in "From" header and SMTP envelope |
|
140 | 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 | 149 | method;; |
|
142 | 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 | 152 | configuration). Otherwise, use as name of program to run that |
|
145 | 153 | acts like sendmail (takes "-f" option for sender, list of |
|
146 | 154 | recipients on command line, message on stdin). Normally, setting |
@@ -194,7 +202,8 b' hooks::' | |||
|
194 | 202 | |
|
195 | 203 | changegroup;; |
|
196 | 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 | 207 | commit;; |
|
199 | 208 | Run after a changeset has been created in the local repository. |
|
200 | 209 | ID of the newly created changeset is in $HG_NODE. Parent |
@@ -202,7 +211,7 b' hooks::' | |||
|
202 | 211 | incoming;; |
|
203 | 212 | Run after a changeset has been pulled, pushed, or unbundled into |
|
204 | 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 | 215 | outgoing;; |
|
207 | 216 | Run after sending changes from local repository to another. ID of |
|
208 | 217 | first changeset sent is in $HG_NODE. Source of operation is in |
@@ -210,7 +219,8 b' hooks::' | |||
|
210 | 219 | prechangegroup;; |
|
211 | 220 | Run before a changegroup is added via push, pull or unbundle. |
|
212 | 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 | 224 | precommit;; |
|
215 | 225 | Run before starting a local commit. Exit status 0 allows the |
|
216 | 226 | commit to proceed. Non-zero status will cause the commit to fail. |
@@ -236,7 +246,8 b' hooks::' | |||
|
236 | 246 | before accepting them. Passed the ID of the first new changeset |
|
237 | 247 | in $HG_NODE. Exit status 0 allows the transaction to commit. |
|
238 | 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 | 251 | pretxncommit;; |
|
241 | 252 | Run after a changeset has been created but the transaction not yet |
|
242 | 253 | committed. Changeset is visible to hook program. This lets you |
@@ -295,7 +306,7 b' http_proxy::' | |||
|
295 | 306 | smtp:: |
|
296 | 307 | Configuration for extensions that need to send email messages. |
|
297 | 308 | host;; |
|
298 |
|
|
|
309 | Host name of mail server, e.g. "mail.example.com". | |
|
299 | 310 | port;; |
|
300 | 311 | Optional. Port to connect to on mail server. Default: 25. |
|
301 | 312 | tls;; |
@@ -440,6 +451,9 b' web::' | |||
|
440 | 451 | push_ssl;; |
|
441 | 452 | Whether to require that inbound pushes be transported over SSL to |
|
442 | 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 | 457 | style;; |
|
444 | 458 | Which template map style to use. |
|
445 | 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 | 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 | 36 | このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで |
|
37 | 37 | 認められます。 |
@@ -5,34 +5,49 b'' | |||
|
5 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | 7 | # |
|
8 | # allow to use external programs to compare revisions, or revision | |
|
9 | # with working dir. program is called with two arguments: paths to | |
|
10 | # directories containing snapshots of files to compare. | |
|
8 | # The `extdiff' Mercurial extension allows you to use external programs | |
|
9 | # to compare revisions, or revision with working dir. The external diff | |
|
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 | 16 | # [extensions] |
|
15 | 17 | # hgext.extdiff = |
|
16 | 18 | # |
|
17 |
# also allows to configure new diff commands, so |
|
|
18 | # type "hg extdiff -p kdiff3" always. | |
|
19 | # The `extdiff' extension also allows to configure new diff commands, so | |
|
20 | # you do not need to type "hg extdiff -p kdiff3" always. | |
|
19 | 21 | # |
|
20 | 22 | # [extdiff] |
|
23 | # # add new command that runs GNU diff(1) in 'context diff' mode | |
|
24 | # cmd.cdiff = gdiff | |
|
25 | # opts.cdiff = -Nprc5 | |
|
21 | 26 | # # add new command called vdiff, runs kdiff3 |
|
22 | 27 | # cmd.vdiff = kdiff3 |
|
23 | 28 | # # add new command called meld, runs meld (no need to name twice) |
|
24 | 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 | |
|
27 | # "hg diff" command. extdiff makes snapshots of only needed files, so | |
|
28 | # compare program will be fast. | |
|
34 | # Each custom diff commands can have two parts: a `cmd' and an `opts' | |
|
35 | # part. The cmd.xxx option defines the name of an executable program | |
|
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 | 45 | from mercurial.demandload import demandload |
|
31 | 46 | from mercurial.i18n import gettext as _ |
|
32 | 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 | 51 | def snapshot_node(files, node): |
|
37 | 52 | '''snapshot files as of some revision''' |
|
38 | 53 | changes = repo.changelog.read(node) |
@@ -76,9 +91,9 b' def dodiff(ui, repo, diffcmd, pats, opts' | |||
|
76 | 91 | return dirname |
|
77 | 92 | |
|
78 | 93 | node1, node2 = commands.revpair(ui, repo, opts['rev']) |
|
79 |
files, matchfn, anypats = c |
|
|
80 |
modified, added, removed, deleted, unknown = repo. |
|
|
81 | node1, node2, files, match=matchfn) | |
|
94 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
95 | modified, added, removed, deleted, unknown = repo.status( | |
|
96 | node1, node2, files, match=matchfn)[:5] | |
|
82 | 97 | if not (modified or added or removed): |
|
83 | 98 | return 0 |
|
84 | 99 | |
@@ -89,9 +104,12 b' def dodiff(ui, repo, diffcmd, pats, opts' | |||
|
89 | 104 | dir2 = snapshot_node(modified + added, node2) |
|
90 | 105 | else: |
|
91 | 106 | dir2 = snapshot_wdir(modified + added) |
|
92 |
|
|
|
93 | (diffcmd, ' '.join(opts['option']), dir1, dir2), | |
|
94 | cwd=tmproot) | |
|
107 | cmdline = ('%s %s %s %s' % | |
|
108 | (util.shellquote(diffcmd), | |
|
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 | 113 | return 1 |
|
96 | 114 | finally: |
|
97 | 115 | ui.note(_('cleaning up temp directory\n')) |
@@ -101,7 +119,9 b' def extdiff(ui, repo, *pats, **opts):' | |||
|
101 | 119 | '''use external program to diff repository (or selected files) |
|
102 | 120 | |
|
103 | 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 | 125 | To select a different program, use the -p option. The program |
|
106 | 126 | will be passed the names of two directories to compare. To pass |
|
107 | 127 | additional options to the program, use the -o option. These will |
@@ -112,7 +132,8 b' def extdiff(ui, repo, *pats, **opts):' | |||
|
112 | 132 | specified then that revision is compared to the working |
|
113 | 133 | directory, and, when no revisions are specified, the |
|
114 | 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 | 138 | cmdtable = { |
|
118 | 139 | "extdiff": |
@@ -130,20 +151,24 b' def uisetup(ui):' | |||
|
130 | 151 | if not cmd.startswith('cmd.'): continue |
|
131 | 152 | cmd = cmd[4:] |
|
132 | 153 | if not path: path = cmd |
|
154 | diffopts = ui.config('extdiff', 'opts.' + cmd, '') | |
|
155 | diffopts = diffopts and [diffopts] or [] | |
|
133 | 156 | def save(cmd, path): |
|
134 | 157 | '''use closure to save diff command to use''' |
|
135 | 158 | def mydiff(ui, repo, *pats, **opts): |
|
136 | return dodiff(ui, repo, path, pats, opts) | |
|
137 |
mydiff.__doc__ = '''use % |
|
|
159 | return dodiff(ui, repo, path, diffopts, pats, opts) | |
|
160 | mydiff.__doc__ = '''use %(path)r to diff repository (or selected files) | |
|
138 | 161 | |
|
139 | 162 | Show differences between revisions for the specified |
|
140 |
files, using the % |
|
|
163 | files, using the %(path)r program. | |
|
141 | 164 | |
|
142 | 165 | When two revision arguments are given, then changes are |
|
143 | 166 | shown between those revisions. If only one revision is |
|
144 | 167 | specified then that revision is compared to the working |
|
145 | 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 | 172 | return mydiff |
|
148 | 173 | cmdtable[cmd] = (save(cmd, path), |
|
149 | 174 | cmdtable['extdiff'][1][1:], |
@@ -221,7 +221,7 b' def sign(ui, repo, *revs, **opts):' | |||
|
221 | 221 | repo.opener("localsigs", "ab").write(sigmessage) |
|
222 | 222 | return |
|
223 | 223 | |
|
224 |
for x in repo. |
|
|
224 | for x in repo.status()[:5]: | |
|
225 | 225 | if ".hgsigs" in x and not opts["force"]: |
|
226 | 226 | raise util.Abort(_("working copy of .hgsigs is changed " |
|
227 | 227 | "(please commit .hgsigs manually " |
@@ -23,10 +23,10 b' def lookup_rev(ui, repo, rev=None):' | |||
|
23 | 23 | return parents.pop() |
|
24 | 24 | |
|
25 | 25 | def check_clean(ui, repo): |
|
26 |
|
|
|
27 |
|
|
|
28 |
|
|
|
29 |
|
|
|
26 | modified, added, removed, deleted, unknown = repo.status()[:5] | |
|
27 | if modified or added or removed: | |
|
28 | ui.warn("Repository is not clean, please commit or revert\n") | |
|
29 | sys.exit(1) | |
|
30 | 30 | |
|
31 | 31 | class bisect(object): |
|
32 | 32 | """dichotomic search in the DAG of changesets""" |
@@ -50,7 +50,7 b' class bisect(object):' | |||
|
50 | 50 | if r: |
|
51 | 51 | self.badrev = hg.bin(r.pop(0)) |
|
52 | 52 | |
|
53 |
def |
|
|
53 | def write(self): | |
|
54 | 54 | if not os.path.isdir(self.path): |
|
55 | 55 | return |
|
56 | 56 | f = self.opener(self.good_path, "w") |
@@ -197,7 +197,7 b' class bisect(object):' | |||
|
197 | 197 | check_clean(self.ui, self.repo) |
|
198 | 198 | rev = self.next() |
|
199 | 199 | if rev is not None: |
|
200 |
return self.repo |
|
|
200 | return hg.clean(self.repo, rev) | |
|
201 | 201 | |
|
202 | 202 | def good(self, rev): |
|
203 | 203 | self.goodrevs.append(rev) |
@@ -288,7 +288,10 b' for subcommands see "hg bisect help\\"' | |||
|
288 | 288 | if len(args) > bisectcmdtable[cmd][1]: |
|
289 | 289 | ui.warn(_("bisect: Too many arguments\n")) |
|
290 | 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 | 296 | cmdtable = { |
|
294 | 297 | "bisect": (bisect_run, [], _("hg bisect [help|init|reset|next|good|bad]")), |
@@ -1,12 +1,13 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | 7 | |
|
8 | import time, sys, signal, os | |
|
9 | from mercurial import hg, mdiff, fancyopts, commands, ui, util | |
|
8 | from mercurial.demandload import * | |
|
9 | demandload(globals(), 'time sys signal os') | |
|
10 | demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util') | |
|
10 | 11 | |
|
11 | 12 | def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, |
|
12 | 13 | changes=None, text=False): |
@@ -14,7 +15,7 b' def dodiff(fp, ui, repo, node1, node2, f' | |||
|
14 | 15 | return time.asctime(time.gmtime(c[2][0])) |
|
15 | 16 | |
|
16 | 17 | if not changes: |
|
17 |
changes = repo. |
|
|
18 | changes = repo.status(node1, node2, files, match=match)[:5] | |
|
18 | 19 | modified, added, removed, deleted, unknown = changes |
|
19 | 20 | if files: |
|
20 | 21 | modified, added, removed = map(lambda x: filterfiles(files, x), |
@@ -67,12 +68,12 b' def difftree(ui, repo, node1=None, node2' | |||
|
67 | 68 | if node2: |
|
68 | 69 | change = repo.changelog.read(node2) |
|
69 | 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 | 72 | def read(f): return repo.file(f).read(mmap2[f]) |
|
72 | 73 | date2 = date(change) |
|
73 | 74 | else: |
|
74 | 75 | date2 = time.asctime() |
|
75 |
modified, added, removed, deleted, unknown = repo. |
|
|
76 | modified, added, removed, deleted, unknown = repo.status(node1)[:5] | |
|
76 | 77 | if not node1: |
|
77 | 78 | node1 = repo.dirstate.parents()[0] |
|
78 | 79 | def read(f): return file(os.path.join(repo.root, f)).read() |
@@ -334,6 +335,3 b' cmdtable = {' | |||
|
334 | 335 | ('n', 'max-count', 0, 'max-count')], |
|
335 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 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 | 32 | from mercurial.demandload import * |
|
33 | from mercurial.i18n import gettext as _ | |
|
33 | 34 | demandload(globals(), "os sys re struct traceback errno bz2") |
|
34 | from mercurial.i18n import gettext as _ | |
|
35 | from mercurial import ui, hg, revlog, commands, util | |
|
35 | demandload(globals(), "mercurial:cmdutil,commands,hg,patch,revlog,ui,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 | 53 | class queue: |
|
43 | 54 | def __init__(self, ui, path, patchdir=None): |
|
44 | 55 | self.basepath = path |
|
45 | if patchdir: | |
|
46 | self.path = patchdir | |
|
47 | else: | |
|
48 | self.path = os.path.join(path, "patches") | |
|
56 | self.path = patchdir or os.path.join(path, "patches") | |
|
49 | 57 | self.opener = util.opener(self.path) |
|
50 | 58 | self.ui = ui |
|
51 | 59 | self.applied = [] |
@@ -54,13 +62,26 b' class queue:' | |||
|
54 | 62 | self.series_dirty = 0 |
|
55 | 63 | self.series_path = "series" |
|
56 | 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 | 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)): | |
|
63 | self.applied = self.opener(self.status_path).read().splitlines() | |
|
78 | def diffopts(self): | |
|
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 | 86 | def find_series(self, patch): |
|
66 | 87 | pre = re.compile("(\s*)([^#]+)") |
@@ -75,34 +96,132 b' class queue:' | |||
|
75 | 96 | index += 1 |
|
76 | 97 | return None |
|
77 | 98 | |
|
78 | def read_series(self, list): | |
|
79 | def matcher(list): | |
|
80 | pre = re.compile("(\s*)([^#]+)") | |
|
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 | |
|
99 | guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)') | |
|
100 | ||
|
101 | def parse_series(self): | |
|
88 | 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 | 216 | def save_dirty(self): |
|
92 | if self.applied_dirty: | |
|
93 | if len(self.applied) > 0: | |
|
94 | nl = "\n" | |
|
95 | else: | |
|
96 | nl = "" | |
|
97 | f = self.opener(self.status_path, "w") | |
|
98 | f.write("\n".join(self.applied) + nl) | |
|
99 | if self.series_dirty: | |
|
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) | |
|
217 | def write_list(items, path): | |
|
218 | fp = self.opener(path, 'w') | |
|
219 | for i in items: | |
|
220 | print >> fp, i | |
|
221 | fp.close() | |
|
222 | if self.applied_dirty: write_list(map(str, self.applied), self.status_path) | |
|
223 | if self.series_dirty: write_list(self.full_series, self.series_path) | |
|
224 | if self.guards_dirty: write_list(self.active_guards, self.guards_path) | |
|
106 | 225 | |
|
107 | 226 | def readheaders(self, patch): |
|
108 | 227 | def eatdiff(lines): |
@@ -122,7 +241,7 b' class queue:' | |||
|
122 | 241 | else: |
|
123 | 242 | break |
|
124 | 243 | |
|
125 |
pf = |
|
|
244 | pf = self.join(patch) | |
|
126 | 245 | message = [] |
|
127 | 246 | comments = [] |
|
128 | 247 | user = None |
@@ -133,6 +252,9 b' class queue:' | |||
|
133 | 252 | |
|
134 | 253 | for line in file(pf): |
|
135 | 254 | line = line.rstrip() |
|
255 | if line.startswith('diff --git'): | |
|
256 | diffstart = 2 | |
|
257 | break | |
|
136 | 258 | if diffstart: |
|
137 | 259 | if line.startswith('+++ '): |
|
138 | 260 | diffstart = 2 |
@@ -178,6 +300,13 b' class queue:' | |||
|
178 | 300 | message.insert(0, subject) |
|
179 | 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 | 310 | def mergeone(self, repo, mergeq, head, patch, rev, wlock): |
|
182 | 311 | # first try just applying the patch |
|
183 | 312 | (err, n) = self.apply(repo, [ patch ], update_status=False, |
@@ -187,35 +316,31 b' class queue:' | |||
|
187 | 316 | return (err, n) |
|
188 | 317 | |
|
189 | 318 | if n is None: |
|
190 |
sel |
|
|
191 | sys.exit(1) | |
|
319 | raise util.Abort(_("apply failed for patch %s") % patch) | |
|
192 | 320 | |
|
193 | 321 | self.ui.warn("patch didn't work out, merging %s\n" % patch) |
|
194 | 322 | |
|
195 | 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 | 325 | self.strip(repo, n, update=False, backup='strip', wlock=wlock) |
|
198 | 326 | |
|
199 | 327 | c = repo.changelog.read(rev) |
|
200 |
ret = repo |
|
|
328 | ret = hg.merge(repo, rev, wlock=wlock) | |
|
201 | 329 | if ret: |
|
202 |
sel |
|
|
203 | sys.exit(1) | |
|
330 | raise util.Abort(_("update returned %d") % ret) | |
|
204 | 331 | n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) |
|
205 | 332 | if n == None: |
|
206 |
sel |
|
|
207 | sys.exit(1) | |
|
333 | raise util.Abort(_("repo commit failed")) | |
|
208 | 334 | try: |
|
209 | 335 | message, comments, user, date, patchfound = mergeq.readheaders(patch) |
|
210 | 336 | except: |
|
211 |
sel |
|
|
212 | sys.exit(1) | |
|
337 | raise util.Abort(_("unable to read %s") % patch) | |
|
213 | 338 | |
|
214 | 339 | patchf = self.opener(patch, "w") |
|
215 | 340 | if comments: |
|
216 | 341 | comments = "\n".join(comments) + '\n\n' |
|
217 | 342 | patchf.write(comments) |
|
218 | commands.dodiff(patchf, self.ui, repo, head, n) | |
|
343 | self.printdiff(repo, head, n, fp=patchf) | |
|
219 | 344 | patchf.close() |
|
220 | 345 | return (0, n) |
|
221 | 346 | |
@@ -226,12 +351,10 b' class queue:' | |||
|
226 | 351 | return p1 |
|
227 | 352 | if len(self.applied) == 0: |
|
228 | 353 | return None |
|
229 | (top, patch) = self.applied[-1].split(':') | |
|
230 | top = revlog.bin(top) | |
|
231 | return top | |
|
354 | return revlog.bin(self.applied[-1].rev) | |
|
232 | 355 | pp = repo.changelog.parents(rev) |
|
233 | 356 | if pp[1] != revlog.nullid: |
|
234 |
arevs = [ x. |
|
|
357 | arevs = [ x.rev for x in self.applied ] | |
|
235 | 358 | p0 = revlog.hex(pp[0]) |
|
236 | 359 | p1 = revlog.hex(pp[1]) |
|
237 | 360 | if p0 in arevs: |
@@ -251,17 +374,20 b' class queue:' | |||
|
251 | 374 | pname = ".hg.patches.merge.marker" |
|
252 | 375 | n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
|
253 | 376 | wlock=wlock) |
|
254 |
self.applied.append(revlog.hex(n) |
|
|
377 | self.applied.append(statusentry(revlog.hex(n), pname)) | |
|
255 | 378 | self.applied_dirty = 1 |
|
256 | 379 | |
|
257 | 380 | head = self.qparents(repo) |
|
258 | 381 | |
|
259 | 382 | for patch in series: |
|
260 | patch = mergeq.lookup(patch) | |
|
383 | patch = mergeq.lookup(patch, strict=True) | |
|
261 | 384 | if not patch: |
|
262 | 385 | self.ui.warn("patch %s does not exist\n" % patch) |
|
263 | 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 | 391 | info = mergeq.isapplied(patch) |
|
266 | 392 | if not info: |
|
267 | 393 | self.ui.warn("patch %s is not applied\n" % patch) |
@@ -269,102 +395,80 b' class queue:' | |||
|
269 | 395 | rev = revlog.bin(info[1]) |
|
270 | 396 | (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
|
271 | 397 | if head: |
|
272 |
self.applied.append(revlog.hex(head) |
|
|
398 | self.applied.append(statusentry(revlog.hex(head), patch)) | |
|
273 | 399 | self.applied_dirty = 1 |
|
274 | 400 | if err: |
|
275 | 401 | return (err, head) |
|
276 | 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 | 418 | def apply(self, repo, series, list=False, update_status=True, |
|
279 | 419 | strict=False, patchdir=None, merge=None, wlock=None): |
|
280 | 420 | # TODO unify with commands.py |
|
281 | 421 | if not patchdir: |
|
282 | 422 | patchdir = self.path |
|
283 | pwd = os.getcwd() | |
|
284 | os.chdir(repo.root) | |
|
285 | 423 | err = 0 |
|
286 | 424 | if not wlock: |
|
287 | 425 | wlock = repo.wlock() |
|
288 | 426 | lock = repo.lock() |
|
289 | 427 | tr = repo.transaction() |
|
290 | 428 | n = None |
|
291 | for patch in series: | |
|
292 | self.ui.warn("applying %s\n" % patch) | |
|
293 | pf = os.path.join(patchdir, patch) | |
|
429 | for patchname in series: | |
|
430 | pushable, reason = self.pushable(patchname) | |
|
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 | 437 | try: |
|
296 | message, comments, user, date, patchfound = self.readheaders(patch) | |
|
438 | message, comments, user, date, patchfound = self.readheaders(patchname) | |
|
297 | 439 | except: |
|
298 |
self.ui.warn("Unable to read %s\n" % p |
|
|
440 | self.ui.warn("Unable to read %s\n" % patchname) | |
|
299 | 441 | err = 1 |
|
300 | 442 | break |
|
301 | 443 | |
|
302 | 444 | if not message: |
|
303 | message = "imported patch %s\n" % patch | |
|
445 | message = "imported patch %s\n" % patchname | |
|
304 | 446 | else: |
|
305 | 447 | if list: |
|
306 | message.append("\nimported patch %s" % patch) | |
|
448 | message.append("\nimported patch %s" % patchname) | |
|
307 | 449 | message = '\n'.join(message) |
|
308 | 450 | |
|
309 | try: | |
|
310 | pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') | |
|
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() | |
|
451 | (patcherr, files, fuzz) = self.patch(repo, pf) | |
|
452 | patcherr = not patcherr | |
|
346 | 453 | |
|
347 |
if merge and |
|
|
454 | if merge and files: | |
|
348 | 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 | 457 | p1, p2 = repo.dirstate.parents() |
|
351 | 458 | repo.dirstate.setparents(p1, merge) |
|
352 | if len(files) > 0: | |
|
353 | commands.addremove_lock(self.ui, repo, files, | |
|
354 | opts={}, wlock=wlock) | |
|
459 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) | |
|
355 | 460 | n = repo.commit(files, message, user, date, force=1, lock=lock, |
|
356 | 461 | wlock=wlock) |
|
357 | 462 | |
|
358 | 463 | if n == None: |
|
359 |
sel |
|
|
360 | sys.exit(1) | |
|
464 | raise util.Abort(_("repo commit failed")) | |
|
361 | 465 | |
|
362 | 466 | if update_status: |
|
363 |
self.applied.append(revlog.hex(n) |
|
|
467 | self.applied.append(statusentry(revlog.hex(n), patchname)) | |
|
364 | 468 | |
|
365 | 469 | if patcherr: |
|
366 | 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 | 472 | err = 0 |
|
369 | 473 | else: |
|
370 | 474 | self.ui.warn("patch failed, rejects left in working dir\n") |
@@ -376,49 +480,58 b' class queue:' | |||
|
376 | 480 | err = 1 |
|
377 | 481 | break |
|
378 | 482 | tr.close() |
|
379 | os.chdir(pwd) | |
|
380 | 483 | return (err, n) |
|
381 | 484 | |
|
382 | def delete(self, repo, patch): | |
|
383 | patch = self.lookup(patch) | |
|
384 | info = self.isapplied(patch) | |
|
385 | if info: | |
|
386 | self.ui.warn("cannot delete applied patch %s\n" % patch) | |
|
387 |
|
|
|
388 | if patch not in self.series: | |
|
389 |
self. |
|
|
390 | sys.exit(1) | |
|
391 | i = self.find_series(patch) | |
|
392 | del self.full_series[i] | |
|
393 | self.read_series(self.full_series) | |
|
485 | def delete(self, repo, patches, keep=False): | |
|
486 | realpatches = [] | |
|
487 | for patch in patches: | |
|
488 | patch = self.lookup(patch, strict=True) | |
|
489 | info = self.isapplied(patch) | |
|
490 | if info: | |
|
491 | raise util.Abort(_("cannot delete applied patch %s") % patch) | |
|
492 | if patch not in self.series: | |
|
493 | raise util.Abort(_("patch %s not in series file") % patch) | |
|
494 | realpatches.append(patch) | |
|
495 | ||
|
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 | 508 | self.series_dirty = 1 |
|
395 | 509 | |
|
396 | 510 | def check_toppatch(self, repo): |
|
397 | 511 | if len(self.applied) > 0: |
|
398 |
|
|
|
399 | top = revlog.bin(top) | |
|
512 | top = revlog.bin(self.applied[-1].rev) | |
|
400 | 513 | pp = repo.dirstate.parents() |
|
401 | 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]))) | |
|
403 | sys.exit(1) | |
|
515 | raise util.Abort(_("queue top not at same revision as working directory")) | |
|
404 | 516 | return top |
|
405 | 517 | return None |
|
406 | def check_localchanges(self, repo): | |
|
407 |
|
|
|
408 |
if |
|
|
409 | self.ui.write("Local changes found, refresh first\n") | |
|
410 | sys.exit(1) | |
|
518 | def check_localchanges(self, repo, force=False, refresh=True): | |
|
519 | m, a, r, d = repo.status()[:4] | |
|
520 | if m or a or r or d: | |
|
521 | if not force: | |
|
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 | 527 | def new(self, repo, patch, msg=None, force=None): |
|
412 | commitfiles = [] | |
|
413 | (c, a, r, d, u) = repo.changes(None, None) | |
|
414 | if c or a or d or r: | |
|
415 | if not force: | |
|
416 | raise util.Abort(_("Local changes found, refresh first")) | |
|
417 | else: | |
|
418 | commitfiles = c + a + r | |
|
528 | if os.path.exists(self.join(patch)): | |
|
529 | raise util.Abort(_('patch "%s" already exists') % patch) | |
|
530 | m, a, r, d = self.check_localchanges(repo, force) | |
|
531 | commitfiles = m + a + r | |
|
419 | 532 | self.check_toppatch(repo) |
|
420 | 533 | wlock = repo.wlock() |
|
421 | insert = self.series_end() | |
|
534 | insert = self.full_series_end() | |
|
422 | 535 | if msg: |
|
423 | 536 | n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True, |
|
424 | 537 | wlock=wlock) |
@@ -426,11 +539,10 b' class queue:' | |||
|
426 | 539 | n = repo.commit(commitfiles, |
|
427 | 540 | "New patch: %s" % patch, force=True, wlock=wlock) |
|
428 | 541 | if n == None: |
|
429 |
sel |
|
|
430 | sys.exit(1) | |
|
542 | raise util.Abort(_("repo commit failed")) | |
|
431 | 543 | self.full_series[insert:insert] = [patch] |
|
432 |
self.applied.append(revlog.hex(n) |
|
|
433 |
self.re |
|
|
544 | self.applied.append(statusentry(revlog.hex(n), patch)) | |
|
545 | self.parse_series() | |
|
434 | 546 | self.series_dirty = 1 |
|
435 | 547 | self.applied_dirty = 1 |
|
436 | 548 | p = self.opener(patch, "w") |
@@ -509,9 +621,9 b' class queue:' | |||
|
509 | 621 | # we go in two steps here so the strip loop happens in a |
|
510 | 622 | # sensible order. When stripping many files, this helps keep |
|
511 | 623 | # our disk access patterns under control. |
|
512 | list = seen.keys() | |
|
513 | list.sort() | |
|
514 | for f in list: | |
|
624 | seen_list = seen.keys() | |
|
625 | seen_list.sort() | |
|
626 | for f in seen_list: | |
|
515 | 627 | ff = repo.file(f) |
|
516 | 628 | filerev = seen[f] |
|
517 | 629 | if filerev != 0: |
@@ -530,8 +642,9 b' class queue:' | |||
|
530 | 642 | revnum = chlog.rev(rev) |
|
531 | 643 | |
|
532 | 644 | if update: |
|
645 | self.check_localchanges(repo, refresh=False) | |
|
533 | 646 | urev = self.qparents(repo, rev) |
|
534 |
repo |
|
|
647 | hg.clean(repo, urev, wlock=wlock) | |
|
535 | 648 | repo.dirstate.write() |
|
536 | 649 | |
|
537 | 650 | # save is a list of all the branches we are truncating away |
@@ -540,7 +653,6 b' class queue:' | |||
|
540 | 653 | saveheads = [] |
|
541 | 654 | savebases = {} |
|
542 | 655 | |
|
543 | tip = chlog.tip() | |
|
544 | 656 | heads = limitheads(chlog, rev) |
|
545 | 657 | seen = {} |
|
546 | 658 | |
@@ -571,7 +683,7 b' class queue:' | |||
|
571 | 683 | savebases[x] = 1 |
|
572 | 684 | |
|
573 | 685 | # create a changegroup for all the branches we need to keep |
|
574 |
if backup |
|
|
686 | if backup == "all": | |
|
575 | 687 | backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') |
|
576 | 688 | bundle(backupch) |
|
577 | 689 | if saveheads: |
@@ -586,37 +698,89 b' class queue:' | |||
|
586 | 698 | if saveheads: |
|
587 | 699 | self.ui.status("adding branch\n") |
|
588 | 700 | commands.unbundle(self.ui, repo, chgrpfile, update=False) |
|
589 |
if backup |
|
|
701 | if backup != "strip": | |
|
590 | 702 | os.unlink(chgrpfile) |
|
591 | 703 | |
|
592 | 704 | def isapplied(self, patch): |
|
593 | 705 | """returns (index, rev, patch)""" |
|
594 | 706 | for i in xrange(len(self.applied)): |
|
595 |
|
|
|
596 |
a = p |
|
|
597 | if a[1] == patch: | |
|
598 | return (i, a[0], a[1]) | |
|
707 | a = self.applied[i] | |
|
708 | if a.name == patch: | |
|
709 | return (i, a.rev, a.name) | |
|
599 | 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 | 738 | if patch == None: |
|
603 | 739 | return None |
|
604 | if patch in self.series: | |
|
605 | return patch | |
|
606 | if not os.path.isfile(os.path.join(self.path, patch)): | |
|
740 | ||
|
741 | # we don't want to return a partial match until we make | |
|
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 | 748 | try: |
|
608 | 749 | sno = int(patch) |
|
609 | 750 | except(ValueError, OverflowError): |
|
610 | self.ui.warn("patch %s not in series\n" % patch) | |
|
611 |
|
|
|
612 |
if sno |
|
|
613 | self.ui.warn("patch number %d is out of range\n" % sno) | |
|
614 |
|
|
|
615 | patch = self.series[sno] | |
|
616 |
e |
|
|
617 | self.ui.warn("patch %s not in series\n" % patch) | |
|
618 | sys.exit(1) | |
|
619 | return patch | |
|
751 | pass | |
|
752 | else: | |
|
753 | if sno < len(self.series): | |
|
754 | return self.series[sno] | |
|
755 | if not strict: | |
|
756 | # return any partial match made above | |
|
757 | if res: | |
|
758 | return res | |
|
759 | minus = patch.rsplit('-', 1) | |
|
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 | 785 | def push(self, repo, patch=None, force=False, list=False, |
|
622 | 786 | mergeq=None, wlock=None): |
@@ -624,10 +788,10 b' class queue:' | |||
|
624 | 788 | wlock = repo.wlock() |
|
625 | 789 | patch = self.lookup(patch) |
|
626 | 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 | 792 | sys.exit(1) |
|
629 | 793 | if self.series_end() == len(self.series): |
|
630 |
self.ui.warn(" |
|
|
794 | self.ui.warn(_("patch series fully applied\n")) | |
|
631 | 795 | sys.exit(1) |
|
632 | 796 | if not force: |
|
633 | 797 | self.check_localchanges(repo) |
@@ -646,7 +810,7 b' class queue:' | |||
|
646 | 810 | ret = self.mergepatch(repo, mergeq, s, wlock) |
|
647 | 811 | else: |
|
648 | 812 | ret = self.apply(repo, s, list, wlock=wlock) |
|
649 |
top = self.applied[-1]. |
|
|
813 | top = self.applied[-1].name | |
|
650 | 814 | if ret[0]: |
|
651 | 815 | self.ui.write("Errors during apply, please fix and refresh %s\n" % |
|
652 | 816 | top) |
@@ -654,7 +818,8 b' class queue:' | |||
|
654 | 818 | self.ui.write("Now at: %s\n" % top) |
|
655 | 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 | 823 | def getfile(f, rev): |
|
659 | 824 | t = repo.file(f).read(rev) |
|
660 | 825 | try: |
@@ -675,15 +840,14 b' class queue:' | |||
|
675 | 840 | patch = self.lookup(patch) |
|
676 | 841 | info = self.isapplied(patch) |
|
677 | 842 | if not info: |
|
678 |
sel |
|
|
679 | sys.exit(1) | |
|
843 | raise util.Abort(_("patch %s is not applied") % patch) | |
|
680 | 844 | if len(self.applied) == 0: |
|
681 |
self.ui.warn(" |
|
|
845 | self.ui.warn(_("no patches applied\n")) | |
|
682 | 846 | sys.exit(1) |
|
683 | 847 | |
|
684 | 848 | if not update: |
|
685 | 849 | parents = repo.dirstate.parents() |
|
686 |
rr = [ revlog.bin(x. |
|
|
850 | rr = [ revlog.bin(x.rev) for x in self.applied ] | |
|
687 | 851 | for p in parents: |
|
688 | 852 | if p in rr: |
|
689 | 853 | self.ui.warn("qpop: forcing dirstate update\n") |
@@ -695,7 +859,17 b' class queue:' | |||
|
695 | 859 | self.applied_dirty = 1; |
|
696 | 860 | end = len(self.applied) |
|
697 | 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 | 873 | start = info[0] |
|
700 | 874 | rev = revlog.bin(info[1]) |
|
701 | 875 | |
@@ -705,17 +879,16 b' class queue:' | |||
|
705 | 879 | top = self.check_toppatch(repo) |
|
706 | 880 | qp = self.qparents(repo, rev) |
|
707 | 881 | changes = repo.changelog.read(qp) |
|
708 | mf1 = repo.manifest.readflags(changes[0]) | |
|
709 | 882 | mmap = repo.manifest.read(changes[0]) |
|
710 |
|
|
|
883 | m, a, r, d, u = repo.status(qp, top)[:5] | |
|
711 | 884 | if d: |
|
712 | 885 | raise util.Abort("deletions found between repo revs") |
|
713 |
for f in |
|
|
886 | for f in m: | |
|
714 | 887 | getfile(f, mmap[f]) |
|
715 | 888 | for f in r: |
|
716 | 889 | getfile(f, mmap[f]) |
|
717 |
util.set_exec(repo.wjoin(f), m |
|
|
718 |
repo.dirstate.update( |
|
|
890 | util.set_exec(repo.wjoin(f), mmap.execf(f)) | |
|
891 | repo.dirstate.update(m + r, 'n') | |
|
719 | 892 | for f in a: |
|
720 | 893 | try: os.unlink(repo.wjoin(f)) |
|
721 | 894 | except: raise |
@@ -727,36 +900,46 b' class queue:' | |||
|
727 | 900 | self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
|
728 | 901 | del self.applied[start:end] |
|
729 | 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 | 904 | else: |
|
732 | 905 | self.ui.write("Patch queue now empty\n") |
|
733 | 906 | |
|
734 |
def diff(self, repo, |
|
|
907 | def diff(self, repo, pats, opts): | |
|
735 | 908 | top = self.check_toppatch(repo) |
|
736 | 909 | if not top: |
|
737 | 910 | self.ui.write("No patches applied\n") |
|
738 | 911 | return |
|
739 | 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 | 916 | if len(self.applied) == 0: |
|
744 | 917 | self.ui.write("No patches applied\n") |
|
745 | 918 | return |
|
746 | 919 | wlock = repo.wlock() |
|
747 | 920 | self.check_toppatch(repo) |
|
748 | qp = self.qparents(repo) | |
|
749 | (top, patch) = self.applied[-1].split(':') | |
|
921 | (top, patch) = (self.applied[-1].rev, self.applied[-1].name) | |
|
750 | 922 | top = revlog.bin(top) |
|
751 | 923 | cparents = repo.changelog.parents(top) |
|
752 | 924 | patchparent = self.qparents(repo, top) |
|
753 | 925 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
754 | 926 | |
|
755 | 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 | 938 | if comments: |
|
757 | 939 | comments = "\n".join(comments) + '\n\n' |
|
758 | 940 | patchf.write(comments) |
|
759 | 941 | |
|
942 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
760 | 943 | tip = repo.changelog.tip() |
|
761 | 944 | if top == tip: |
|
762 | 945 | # if the top of our patch queue is also the tip, there is an |
@@ -769,30 +952,30 b' class queue:' | |||
|
769 | 952 | # patch already |
|
770 | 953 | # |
|
771 | 954 | # this should really read: |
|
772 |
# |
|
|
955 | # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] | |
|
773 | 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 |
|
|
|
777 | if short: | |
|
778 |
filelist = |
|
|
959 | mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] | |
|
960 | if opts.get('short'): | |
|
961 | filelist = mm + aa + dd | |
|
779 | 962 | else: |
|
780 | 963 | filelist = None |
|
781 |
|
|
|
964 | m, a, r, d, u = repo.status(files=filelist)[:5] | |
|
782 | 965 | |
|
783 | 966 | # we might end up with files that were added between tip and |
|
784 | 967 | # the dirstate parent, but then changed in the local dirstate. |
|
785 | 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 | 970 | if x not in aa: |
|
788 |
|
|
|
971 | mm.append(x) | |
|
789 | 972 | # we might end up with files added by the local dirstate that |
|
790 | 973 | # were deleted by the patch. In this case, they should only |
|
791 | 974 | # show up in the changed section. |
|
792 | 975 | for x in a: |
|
793 | 976 | if x in dd: |
|
794 | 977 | del dd[dd.index(x)] |
|
795 |
|
|
|
978 | mm.append(x) | |
|
796 | 979 | else: |
|
797 | 980 | aa.append(x) |
|
798 | 981 | # make sure any files deleted in the local dirstate |
@@ -803,70 +986,97 b' class queue:' | |||
|
803 | 986 | del aa[aa.index(x)] |
|
804 | 987 | forget.append(x) |
|
805 | 988 | continue |
|
806 |
elif x in |
|
|
807 |
del |
|
|
989 | elif x in mm: | |
|
990 | del mm[mm.index(x)] | |
|
808 | 991 | dd.append(x) |
|
809 | 992 | |
|
810 |
|
|
|
993 | m = list(util.unique(mm)) | |
|
811 | 994 | r = list(util.unique(dd)) |
|
812 | 995 | a = list(util.unique(aa)) |
|
813 |
filelist = |
|
|
814 |
|
|
|
815 |
|
|
|
996 | filelist = filter(matchfn, util.unique(m + r + a)) | |
|
997 | self.printdiff(repo, patchparent, files=filelist, | |
|
998 | changes=(m, a, r, [], u), fp=patchf) | |
|
816 | 999 | patchf.close() |
|
817 | 1000 | |
|
818 | 1001 | changes = repo.changelog.read(tip) |
|
819 | 1002 | repo.dirstate.setparents(*cparents) |
|
1003 | copies = [(f, repo.dirstate.copied(f)) for f in a] | |
|
820 | 1004 | repo.dirstate.update(a, 'a') |
|
1005 | for dst, src in copies: | |
|
1006 | repo.dirstate.copy(src, dst) | |
|
821 | 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 | 1017 | repo.dirstate.forget(forget) |
|
824 | 1018 | |
|
825 |
if not m |
|
|
826 | message = "patch queue: %s\n" % patch | |
|
1019 | if not msg: | |
|
1020 | if not message: | |
|
1021 | message = "patch queue: %s\n" % patch | |
|
1022 | else: | |
|
1023 | message = "\n".join(message) | |
|
827 | 1024 | else: |
|
828 |
message = |
|
|
1025 | message = msg | |
|
1026 | ||
|
829 | 1027 | self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
|
830 | 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 | 1030 | self.applied_dirty = 1 |
|
833 | 1031 | else: |
|
834 |
|
|
|
1032 | self.printdiff(repo, patchparent, fp=patchf) | |
|
835 | 1033 | patchf.close() |
|
836 | 1034 | self.pop(repo, force=True, wlock=wlock) |
|
837 | 1035 | self.push(repo, force=True, wlock=wlock) |
|
838 | 1036 | |
|
839 | 1037 | def init(self, repo, create=False): |
|
840 | 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 | 1040 | os.mkdir(self.path) |
|
843 | 1041 | if create: |
|
844 | 1042 | return self.qrepo(create=True) |
|
845 | 1043 | |
|
846 | 1044 | def unapplied(self, repo, patch=None): |
|
847 | 1045 | if patch and patch not in self.series: |
|
848 |
sel |
|
|
849 | sys.exit(1) | |
|
1046 | raise util.Abort(_("patch %s is not in series file") % patch) | |
|
850 | 1047 | if not patch: |
|
851 | 1048 | start = self.series_end() |
|
852 | 1049 | else: |
|
853 | 1050 | start = self.series.index(patch) + 1 |
|
854 | for p in self.series[start:]: | |
|
855 | self.ui.write("%s\n" % p) | |
|
1051 | unapplied = [] | |
|
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): | |
|
858 | start = self.series_end() | |
|
1059 | def qseries(self, repo, missing=None, summary=False): | |
|
1060 | start = self.series_end(all_patches=True) | |
|
859 | 1061 | if not missing: |
|
860 |
for |
|
|
1062 | for i in range(len(self.series)): | |
|
1063 | patch = self.series[i] | |
|
861 | 1064 | if self.ui.verbose: |
|
862 | self.ui.write("%d A " % self.series.index(p)) | |
|
863 | self.ui.write("%s\n" % p) | |
|
864 | for p in self.series[start:]: | |
|
865 | if self.ui.verbose: | |
|
866 | self.ui.write("%d U " % self.series.index(p)) | |
|
867 | self.ui.write("%s\n" % p) | |
|
1065 | if i < start: | |
|
1066 | status = 'A' | |
|
1067 | elif self.pushable(i)[0]: | |
|
1068 | status = 'U' | |
|
1069 | else: | |
|
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 | 1078 | else: |
|
869 | list = [] | |
|
1079 | msng_list = [] | |
|
870 | 1080 | for root, dirs, files in os.walk(self.path): |
|
871 | 1081 | d = root[len(self.path) + 1:] |
|
872 | 1082 | for f in files: |
@@ -874,21 +1084,19 b' class queue:' | |||
|
874 | 1084 | if (fl not in self.series and |
|
875 | 1085 | fl not in (self.status_path, self.series_path) |
|
876 | 1086 | and not fl.startswith('.')): |
|
877 | list.append(fl) | |
|
878 | list.sort() | |
|
879 |
|
|
|
880 |
f |
|
|
881 |
|
|
|
882 |
|
|
|
883 | self.ui.write("%s\n" % x) | |
|
1087 | msng_list.append(fl) | |
|
1088 | msng_list.sort() | |
|
1089 | for x in msng_list: | |
|
1090 | if self.ui.verbose: | |
|
1091 | self.ui.write("D ") | |
|
1092 | self.ui.write("%s\n" % x) | |
|
884 | 1093 | |
|
885 | 1094 | def issaveline(self, l): |
|
886 | name = l.split(':')[1] | |
|
887 | if name == '.hg.patches.save.line': | |
|
1095 | if l.name == '.hg.patches.save.line': | |
|
888 | 1096 | return True |
|
889 | 1097 | |
|
890 | 1098 | def qrepo(self, create=False): |
|
891 |
if create or os.path.isdir( |
|
|
1099 | if create or os.path.isdir(self.join(".hg")): | |
|
892 | 1100 | return hg.repository(self.ui, path=self.path, create=create) |
|
893 | 1101 | |
|
894 | 1102 | def restore(self, repo, rev, delete=None, qupdate=None): |
@@ -909,19 +1117,18 b' class queue:' | |||
|
909 | 1117 | qpp = [ hg.bin(x) for x in l ] |
|
910 | 1118 | elif datastart != None: |
|
911 | 1119 | l = lines[i].rstrip() |
|
912 |
|
|
|
913 |
|
|
|
914 |
|
|
|
915 |
|
|
|
916 |
|
|
|
917 | series.append(file) | |
|
1120 | se = statusentry(l) | |
|
1121 | file_ = se.name | |
|
1122 | if se.rev: | |
|
1123 | applied.append(se) | |
|
1124 | series.append(file_) | |
|
918 | 1125 | if datastart == None: |
|
919 | 1126 | self.ui.warn("No saved patch data found\n") |
|
920 | 1127 | return 1 |
|
921 | 1128 | self.ui.warn("restoring status: %s\n" % lines[0]) |
|
922 | 1129 | self.full_series = series |
|
923 | 1130 | self.applied = applied |
|
924 |
self.re |
|
|
1131 | self.parse_series() | |
|
925 | 1132 | self.series_dirty = 1 |
|
926 | 1133 | self.applied_dirty = 1 |
|
927 | 1134 | heads = repo.changelog.heads() |
@@ -945,7 +1152,7 b' class queue:' | |||
|
945 | 1152 | if not r: |
|
946 | 1153 | self.ui.warn("Unable to load queue repository\n") |
|
947 | 1154 | return 1 |
|
948 | r.update(qpp[0], allow=False, force=True) | |
|
1155 | hg.clean(r, qpp[0]) | |
|
949 | 1156 | |
|
950 | 1157 | def save(self, repo, msg=None): |
|
951 | 1158 | if len(self.applied) == 0: |
@@ -965,30 +1172,49 b' class queue:' | |||
|
965 | 1172 | pp = r.dirstate.parents() |
|
966 | 1173 | msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
|
967 | 1174 | msg += "\n\nPatch Data:\n" |
|
968 |
text = msg + "\n".join(self.applied) + '\n' + (ar and |
|
|
969 | + '\n' or "") | |
|
1175 | text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and | |
|
1176 | "\n".join(ar) + '\n' or "") | |
|
970 | 1177 | n = repo.commit(None, text, user=None, force=1) |
|
971 | 1178 | if not n: |
|
972 | 1179 | self.ui.warn("repo commit failed\n") |
|
973 | 1180 | return 1 |
|
974 |
self.applied.append(revlog.hex(n) |
|
|
1181 | self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line')) | |
|
975 | 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 | 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 | 1206 | if len(self.applied) > 0: |
|
980 |
|
|
|
1207 | p = self.applied[-1].name | |
|
981 | 1208 | try: |
|
982 | 1209 | end = self.series.index(p) |
|
983 | 1210 | except ValueError: |
|
984 | 1211 | return 0 |
|
985 | return end + 1 | |
|
986 | return end | |
|
1212 | return next(end + 1) | |
|
1213 | return next(end) | |
|
987 | 1214 | |
|
988 | 1215 | def qapplied(self, repo, patch=None): |
|
989 | 1216 | if patch and patch not in self.series: |
|
990 |
sel |
|
|
991 | sys.exit(1) | |
|
1217 | raise util.Abort(_("patch %s is not in series file") % patch) | |
|
992 | 1218 | if not patch: |
|
993 | 1219 | end = len(self.applied) |
|
994 | 1220 | else: |
@@ -998,9 +1224,11 b' class queue:' | |||
|
998 | 1224 | self.ui.write("%s\n" % p) |
|
999 | 1225 | |
|
1000 | 1226 | def appliedname(self, index): |
|
1001 | p = self.applied[index] | |
|
1227 | pname = self.applied[index].name | |
|
1002 | 1228 | if not self.ui.verbose: |
|
1003 |
p = p |
|
|
1229 | p = pname | |
|
1230 | else: | |
|
1231 | p = str(self.series.index(pname)) + " " + pname | |
|
1004 | 1232 | return p |
|
1005 | 1233 | |
|
1006 | 1234 | def top(self, repo): |
@@ -1015,7 +1243,10 b' class queue:' | |||
|
1015 | 1243 | if end == len(self.series): |
|
1016 | 1244 | self.ui.write("All patches applied\n") |
|
1017 | 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 | 1251 | def prev(self, repo): |
|
1021 | 1252 | if len(self.applied) > 1: |
@@ -1028,36 +1259,33 b' class queue:' | |||
|
1028 | 1259 | |
|
1029 | 1260 | def qimport(self, repo, files, patch=None, existing=None, force=None): |
|
1030 | 1261 | if len(files) > 1 and patch: |
|
1031 |
sel |
|
|
1032 | sys.exit(1) | |
|
1262 | raise util.Abort(_('option "-n" not valid when importing multiple ' | |
|
1263 | 'files')) | |
|
1033 | 1264 | i = 0 |
|
1034 | 1265 | added = [] |
|
1035 | 1266 | for filename in files: |
|
1036 | 1267 | if existing: |
|
1037 | 1268 | if not patch: |
|
1038 | 1269 | patch = filename |
|
1039 |
if not os.path.isfile( |
|
|
1040 |
sel |
|
|
1041 | sys.exit(1) | |
|
1270 | if not os.path.isfile(self.join(patch)): | |
|
1271 | raise util.Abort(_("patch %s does not exist") % patch) | |
|
1042 | 1272 | else: |
|
1043 | 1273 | try: |
|
1044 | 1274 | text = file(filename).read() |
|
1045 | 1275 | except IOError: |
|
1046 |
sel |
|
|
1047 | sys.exit(1) | |
|
1276 | raise util.Abort(_("unable to read %s") % patch) | |
|
1048 | 1277 | if not patch: |
|
1049 | 1278 | patch = os.path.split(filename)[1] |
|
1050 |
if not force and os.path. |
|
|
1051 |
sel |
|
|
1052 | sys.exit(1) | |
|
1279 | if not force and os.path.exists(self.join(patch)): | |
|
1280 | raise util.Abort(_('patch "%s" already exists') % patch) | |
|
1053 | 1281 | patchf = self.opener(patch, "w") |
|
1054 | 1282 | patchf.write(text) |
|
1055 | 1283 | if patch in self.series: |
|
1056 |
sel |
|
|
1057 | sys.exit(1) | |
|
1058 | index = self.series_end() + i | |
|
1284 | raise util.Abort(_('patch %s is already in the series file') | |
|
1285 | % patch) | |
|
1286 | index = self.full_series_end() + i | |
|
1059 | 1287 | self.full_series[index:index] = [patch] |
|
1060 |
self.re |
|
|
1288 | self.parse_series() | |
|
1061 | 1289 | self.ui.warn("adding %s to series file\n" % patch) |
|
1062 | 1290 | i += 1 |
|
1063 | 1291 | added.append(patch) |
@@ -1067,34 +1295,44 b' class queue:' | |||
|
1067 | 1295 | if qrepo: |
|
1068 | 1296 | qrepo.add(added) |
|
1069 | 1297 | |
|
1070 | def delete(ui, repo, patch, **opts): | |
|
1071 |
"""remove |
|
|
1072 | q = repomap[repo] | |
|
1073 | q.delete(repo, patch) | |
|
1298 | def delete(ui, repo, patch, *patches, **opts): | |
|
1299 | """remove patches from queue | |
|
1300 | ||
|
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 | 1305 | q.save_dirty() |
|
1075 | 1306 | return 0 |
|
1076 | 1307 | |
|
1077 | 1308 | def applied(ui, repo, patch=None, **opts): |
|
1078 | 1309 | """print the patches already applied""" |
|
1079 |
|
|
|
1310 | repo.mq.qapplied(repo, patch) | |
|
1080 | 1311 | return 0 |
|
1081 | 1312 | |
|
1082 | 1313 | def unapplied(ui, repo, patch=None, **opts): |
|
1083 | 1314 | """print the patches not yet applied""" |
|
1084 |
|
|
|
1085 | return 0 | |
|
1315 | for i, p in repo.mq.unapplied(repo, patch): | |
|
1316 | if ui.verbose: | |
|
1317 | ui.write("%d " % i) | |
|
1318 | ui.write("%s\n" % p) | |
|
1086 | 1319 | |
|
1087 | 1320 | def qimport(ui, repo, *filename, **opts): |
|
1088 | 1321 | """import a patch""" |
|
1089 |
q = |
|
|
1322 | q = repo.mq | |
|
1090 | 1323 | q.qimport(repo, filename, patch=opts['name'], |
|
1091 | 1324 | existing=opts['existing'], force=opts['force']) |
|
1092 | 1325 | q.save_dirty() |
|
1093 | 1326 | return 0 |
|
1094 | 1327 | |
|
1095 | 1328 | def init(ui, repo, **opts): |
|
1096 |
"""init a new queue repository |
|
|
1097 | q = repomap[repo] | |
|
1329 | """init a new queue repository | |
|
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 | 1336 | r = q.init(repo, create=opts['create_repo']) |
|
1099 | 1337 | q.save_dirty() |
|
1100 | 1338 | if r: |
@@ -1106,68 +1344,254 b' def init(ui, repo, **opts):' | |||
|
1106 | 1344 | r.add(['.hgignore', 'series']) |
|
1107 | 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 | 1391 | def commit(ui, repo, *pats, **opts): |
|
1110 | 1392 | """commit changes in the queue repository""" |
|
1111 |
q = |
|
|
1393 | q = repo.mq | |
|
1112 | 1394 | r = q.qrepo() |
|
1113 | 1395 | if not r: raise util.Abort('no queue repository') |
|
1114 | 1396 | commands.commit(r.ui, r, *pats, **opts) |
|
1115 | 1397 | |
|
1116 | 1398 | def series(ui, repo, **opts): |
|
1117 | 1399 | """print the entire series file""" |
|
1118 |
|
|
|
1400 | repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary']) | |
|
1119 | 1401 | return 0 |
|
1120 | 1402 | |
|
1121 | 1403 | def top(ui, repo, **opts): |
|
1122 | 1404 | """print the name of the current patch""" |
|
1123 |
|
|
|
1405 | repo.mq.top(repo) | |
|
1124 | 1406 | return 0 |
|
1125 | 1407 | |
|
1126 | 1408 | def next(ui, repo, **opts): |
|
1127 | 1409 | """print the name of the next patch""" |
|
1128 |
|
|
|
1410 | repo.mq.next(repo) | |
|
1129 | 1411 | return 0 |
|
1130 | 1412 | |
|
1131 | 1413 | def prev(ui, repo, **opts): |
|
1132 | 1414 | """print the name of the previous patch""" |
|
1133 |
|
|
|
1415 | repo.mq.prev(repo) | |
|
1134 | 1416 | return 0 |
|
1135 | 1417 | |
|
1136 | 1418 | def new(ui, repo, patch, **opts): |
|
1137 |
"""create a new patch |
|
|
1138 | q = repomap[repo] | |
|
1139 | q.new(repo, patch, msg=opts['message'], force=opts['force']) | |
|
1419 | """create a new patch | |
|
1420 | ||
|
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 | 1453 | q.save_dirty() |
|
1141 | 1454 | return 0 |
|
1142 | 1455 | |
|
1143 |
def |
|
|
1144 |
""" |
|
|
1145 | q = repomap[repo] | |
|
1146 | q.refresh(repo, short=opts['short']) | |
|
1147 | q.save_dirty() | |
|
1456 | def diff(ui, repo, *pats, **opts): | |
|
1457 | """diff of the current patch""" | |
|
1458 | repo.mq.diff(repo, pats, opts) | |
|
1148 | 1459 | return 0 |
|
1149 | 1460 | |
|
1150 |
def |
|
|
1151 |
""" |
|
|
1152 | # deep in the dirstate code, the walkhelper method wants a list, not a tuple | |
|
1153 | repomap[repo].diff(repo, list(files)) | |
|
1154 | return 0 | |
|
1461 | def fold(ui, repo, *files, **opts): | |
|
1462 | """fold the named patches into the current patch | |
|
1463 | ||
|
1464 | Patches must not yet be applied. Each patch will be successively | |
|
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 | 1580 | def lastsavename(path): |
|
1157 | (dir, base) = os.path.split(path) | |
|
1158 | names = os.listdir(dir) | |
|
1581 | (directory, base) = os.path.split(path) | |
|
1582 | names = os.listdir(directory) | |
|
1159 | 1583 | namere = re.compile("%s.([0-9]+)" % base) |
|
1160 | max = None | |
|
1584 | maxindex = None | |
|
1161 | 1585 | maxname = None |
|
1162 | 1586 | for f in names: |
|
1163 | 1587 | m = namere.match(f) |
|
1164 | 1588 | if m: |
|
1165 | 1589 | index = int(m.group(1)) |
|
1166 | if max == None or index > max: | |
|
1167 | max = index | |
|
1590 | if maxindex == None or index > maxindex: | |
|
1591 | maxindex = index | |
|
1168 | 1592 | maxname = f |
|
1169 | 1593 | if maxname: |
|
1170 | return (os.path.join(dir, maxname), max) | |
|
1594 | return (os.path.join(directory, maxname), maxindex) | |
|
1171 | 1595 | return (None, None) |
|
1172 | 1596 | |
|
1173 | 1597 | def savename(path): |
@@ -1179,7 +1603,7 b' def savename(path):' | |||
|
1179 | 1603 | |
|
1180 | 1604 | def push(ui, repo, patch=None, **opts): |
|
1181 | 1605 | """push the next patch onto the stack""" |
|
1182 |
q = |
|
|
1606 | q = repo.mq | |
|
1183 | 1607 | mergeq = None |
|
1184 | 1608 | |
|
1185 | 1609 | if opts['all']: |
@@ -1207,17 +1631,65 b' def pop(ui, repo, patch=None, **opts):' | |||
|
1207 | 1631 | ui.warn('using patch queue: %s\n' % q.path) |
|
1208 | 1632 | localupdate = False |
|
1209 | 1633 | else: |
|
1210 |
q = |
|
|
1211 | if opts['all'] and len(q.applied) > 0: | |
|
1212 | patch = q.applied[0].split(':')[1] | |
|
1213 | q.pop(repo, patch, force=opts['force'], update=localupdate) | |
|
1634 | q = repo.mq | |
|
1635 | q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all']) | |
|
1214 | 1636 | q.save_dirty() |
|
1215 | 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 | 1689 | def restore(ui, repo, rev, **opts): |
|
1218 | 1690 | """restore the queue state saved by a rev""" |
|
1219 | 1691 | rev = repo.lookup(rev) |
|
1220 |
q = |
|
|
1692 | q = repo.mq | |
|
1221 | 1693 | q.restore(repo, rev, delete=opts['delete'], |
|
1222 | 1694 | qupdate=opts['update']) |
|
1223 | 1695 | q.save_dirty() |
@@ -1225,8 +1697,9 b' def restore(ui, repo, rev, **opts):' | |||
|
1225 | 1697 | |
|
1226 | 1698 | def save(ui, repo, **opts): |
|
1227 | 1699 | """save current queue state""" |
|
1228 |
q = |
|
|
1229 | ret = q.save(repo, msg=opts['message']) | |
|
1700 | q = repo.mq | |
|
1701 | message = commands.logmessage(opts) | |
|
1702 | ret = q.save(repo, msg=message) | |
|
1230 | 1703 | if ret: |
|
1231 | 1704 | return ret |
|
1232 | 1705 | q.save_dirty() |
@@ -1236,20 +1709,18 b' def save(ui, repo, **opts):' | |||
|
1236 | 1709 | newpath = os.path.join(q.basepath, opts['name']) |
|
1237 | 1710 | if os.path.exists(newpath): |
|
1238 | 1711 | if not os.path.isdir(newpath): |
|
1239 |
ui. |
|
|
1240 | newpath) | |
|
1241 | sys.exit(1) | |
|
1712 | raise util.Abort(_('destination %s exists and is not ' | |
|
1713 | 'a directory') % newpath) | |
|
1242 | 1714 | if not opts['force']: |
|
1243 |
ui. |
|
|
1244 | newpath) | |
|
1245 | sys.exit(1) | |
|
1715 | raise util.Abort(_('destination %s exists, ' | |
|
1716 | 'use -f to force') % newpath) | |
|
1246 | 1717 | else: |
|
1247 | 1718 | newpath = savename(path) |
|
1248 | 1719 | ui.warn("copy %s to %s\n" % (path, newpath)) |
|
1249 | 1720 | util.copyfiles(path, newpath) |
|
1250 | 1721 | if opts['empty']: |
|
1251 | 1722 | try: |
|
1252 |
os.unlink( |
|
|
1723 | os.unlink(q.join(q.status_path)) | |
|
1253 | 1724 | except: |
|
1254 | 1725 | pass |
|
1255 | 1726 | return 0 |
@@ -1262,25 +1733,196 b' def strip(ui, repo, rev, **opts):' | |||
|
1262 | 1733 | backup = 'strip' |
|
1263 | 1734 | elif opts['nobackup']: |
|
1264 | 1735 | backup = 'none' |
|
1265 |
|
|
|
1736 | repo.mq.strip(repo, rev, backup=backup) | |
|
1266 | 1737 | return 0 |
|
1267 | 1738 | |
|
1268 | def version(ui, q=None): | |
|
1269 | """print the version number""" | |
|
1270 | ui.write("mq version %s\n" % versionstr) | |
|
1271 | return 0 | |
|
1739 | def select(ui, repo, *args, **opts): | |
|
1740 | '''set or print guarded patches to push | |
|
1741 | ||
|
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 | 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 | 1890 | cmdtable = { |
|
1277 | 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 | 1902 | "qcommit|qci": |
|
1279 | 1903 | (commit, |
|
1280 | 1904 | commands.table["^commit|ci"][1], |
|
1281 | 1905 | 'hg qcommit [OPTION]... [FILE]...'), |
|
1282 | "^qdiff": (diff, [], 'hg qdiff [FILE]...'), | |
|
1283 | "qdelete": (delete, [], 'hg qdelete PATCH'), | |
|
1906 | "^qdiff": (diff, | |
|
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 | 1926 | "^qimport": |
|
1285 | 1927 | (qimport, |
|
1286 | 1928 | [('e', 'existing', None, 'import file in patch dir'), |
@@ -1293,9 +1935,11 b' cmdtable = {' | |||
|
1293 | 1935 | 'hg qinit [-c]'), |
|
1294 | 1936 | "qnew": |
|
1295 | 1937 | (new, |
|
1296 |
[(' |
|
|
1297 | ('f', 'force', None, 'force')], | |
|
1298 | 'hg qnew [-m TEXT] [-f] PATCH'), | |
|
1938 | [('e', 'edit', None, _('edit commit message')), | |
|
1939 | ('m', 'message', '', _('use <text> as commit message')), | |
|
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 | 1943 | "qnext": (next, [], 'hg qnext'), |
|
1300 | 1944 | "qprev": (prev, [], 'hg qprev'), |
|
1301 | 1945 | "^qpop": |
@@ -1314,8 +1958,15 b' cmdtable = {' | |||
|
1314 | 1958 | 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'), |
|
1315 | 1959 | "^qrefresh": |
|
1316 | 1960 | (refresh, |
|
1317 |
[(' |
|
|
1318 | 'hg qrefresh [-s]'), | |
|
1961 | [('e', 'edit', None, _('edit commit message')), | |
|
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 | 1970 | "qrestore": |
|
1320 | 1971 | (restore, |
|
1321 | 1972 | [('d', 'delete', None, 'delete save entry'), |
@@ -1323,15 +1974,24 b' cmdtable = {' | |||
|
1323 | 1974 | 'hg qrestore [-d] [-u] REV'), |
|
1324 | 1975 | "qsave": |
|
1325 | 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 | 1979 | ('c', 'copy', None, 'copy patch directory'), |
|
1328 | 1980 | ('n', 'name', '', 'copy directory name'), |
|
1329 | 1981 | ('e', 'empty', None, 'clear queue status file'), |
|
1330 | 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 | 1991 | "qseries": |
|
1333 | 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 | 1995 | 'hg qseries [-m]'), |
|
1336 | 1996 | "^strip": |
|
1337 | 1997 | (strip, |
@@ -1341,6 +2001,4 b' cmdtable = {' | |||
|
1341 | 2001 | 'hg strip [-f] [-b] [-n] REV'), |
|
1342 | 2002 | "qtop": (top, [], 'hg qtop'), |
|
1343 | 2003 | "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'), |
|
1344 | "qversion": (version, [], 'hg qversion') | |
|
1345 | 2004 | } |
|
1346 |
@@ -67,8 +67,8 b'' | |||
|
67 | 67 | from mercurial.demandload import * |
|
68 | 68 | from mercurial.i18n import gettext as _ |
|
69 | 69 | from mercurial.node import * |
|
70 |
demandload(globals(), ' |
|
|
71 | demandload(globals(), 'fnmatch socket time') | |
|
70 | demandload(globals(), 'mercurial:commands,patch,templater,util,mail') | |
|
71 | demandload(globals(), 'email.Parser fnmatch socket time') | |
|
72 | 72 | |
|
73 | 73 | # template for single changeset can include email headers. |
|
74 | 74 | single_template = ''' |
@@ -229,8 +229,8 b' class notifier(object):' | |||
|
229 | 229 | else: |
|
230 | 230 | self.ui.status(_('notify: sending %d subscribers %d changes\n') % |
|
231 | 231 | (len(self.subs), count)) |
|
232 | mail = self.ui.sendmail() | |
|
233 | mail.sendmail(templater.email(msg['From']), self.subs, msgtext) | |
|
232 | mail.sendmail(self.ui, templater.email(msg['From']), | |
|
233 | self.subs, msgtext) | |
|
234 | 234 | |
|
235 | 235 | def diff(self, node, ref): |
|
236 | 236 | maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) |
@@ -238,7 +238,7 b' class notifier(object):' | |||
|
238 | 238 | return |
|
239 | 239 | fp = templater.stringio() |
|
240 | 240 | prev = self.repo.changelog.parents(node)[0] |
|
241 |
|
|
|
241 | patch.diff(self.repo, fp, prev, ref) | |
|
242 | 242 | difflines = fp.getvalue().splitlines(1) |
|
243 | 243 | if maxdiff > 0 and len(difflines) > maxdiff: |
|
244 | 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 | 255 | changegroup. else send one email per changeset.''' |
|
256 | 256 | n = notifier(ui, repo, hooktype) |
|
257 | 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 | 259 | return |
|
260 | 260 | if n.skipsource(source): |
|
261 | 261 | ui.debug(_('notify: changes have source "%s" - skipping\n') % |
@@ -23,27 +23,52 b'' | |||
|
23 | 23 | # the changeset summary, so you can be sure you are sending the right |
|
24 | 24 | # changes. |
|
25 | 25 | # |
|
26 | # It is best to run this script with the "-n" (test only) flag before | |
|
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. | |
|
26 | # To enable this extension: | |
|
29 | 27 | # |
|
30 | # The "-m" (mbox) option will create an mbox file instead of sending | |
|
31 | # the messages directly. This can be reviewed e.g. with "mutt -R -f mbox", | |
|
32 | # and finally sent with "formail -s sendmail -bm -t < mbox". | |
|
28 | # [extensions] | |
|
29 | # hgext.patchbomb = | |
|
33 | 30 | # |
|
34 | 31 | # To configure other defaults, add a section like this to your hgrc |
|
35 | 32 | # file: |
|
36 | 33 | # |
|
37 | # [email] | |
|
38 | # from = My Name <my@email> | |
|
39 | # to = recipient1, recipient2, ... | |
|
40 | # cc = cc1, cc2, ... | |
|
34 | # [email] | |
|
35 | # from = My Name <my@email> | |
|
36 | # to = recipient1, recipient2, ... | |
|
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 | 66 | from mercurial.demandload import * |
|
43 | 67 | demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils |
|
44 | mercurial:commands,hg,ui | |
|
68 | mercurial:commands,hg,mail,ui | |
|
45 | 69 | os errno popen2 socket sys tempfile time''') |
|
46 | 70 | from mercurial.i18n import gettext as _ |
|
71 | from mercurial.node import * | |
|
47 | 72 | |
|
48 | 73 | try: |
|
49 | 74 | # readline gives raw_input editing capabilities, but is not |
@@ -129,8 +154,26 b' def patchbomb(ui, repo, *revs, **opts):' | |||
|
129 | 154 | while patch and not patch[0].strip(): patch.pop(0) |
|
130 | 155 | if opts['diffstat']: |
|
131 | 156 | body += cdiffstat('\n'.join(desc), patch) + '\n\n' |
|
132 | body += '\n'.join(patch) | |
|
133 |
msg = email.MIME |
|
|
157 | if opts['attach']: | |
|
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 | 177 | if total == 1: |
|
135 | 178 | subj = '[PATCH] ' + desc[0].strip() |
|
136 | 179 | else: |
@@ -185,11 +228,14 b' def patchbomb(ui, repo, *revs, **opts):' | |||
|
185 | 228 | to = getaddrs('to', 'To') |
|
186 | 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 | 235 | if len(patches) > 1: |
|
189 | 236 | ui.write(_('\nWrite the introductory message for the patch series.\n\n')) |
|
190 | 237 | |
|
191 | msg = email.MIMEMultipart.MIMEMultipart() | |
|
192 | msg['Subject'] = '[PATCH 0 of %d] %s' % ( | |
|
238 | subj = '[PATCH 0 of %d] %s' % ( | |
|
193 | 239 | len(patches), |
|
194 | 240 | opts['subject'] or |
|
195 | 241 | prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches))) |
@@ -204,18 +250,21 b' def patchbomb(ui, repo, *revs, **opts):' | |||
|
204 | 250 | if l == '.': break |
|
205 | 251 | body.append(l) |
|
206 | 252 | |
|
207 | msg.attach(email.MIMEText.MIMEText('\n'.join(body) + '\n')) | |
|
208 | ||
|
209 | 253 | if opts['diffstat']: |
|
210 | 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 | 262 | msgs.insert(0, msg) |
|
214 | 263 | |
|
215 | 264 | ui.write('\n') |
|
216 | 265 | |
|
217 | 266 | if not opts['test'] and not opts['mbox']: |
|
218 |
mail = ui |
|
|
267 | mailer = mail.connect(ui) | |
|
219 | 268 | parent = None |
|
220 | 269 | |
|
221 | 270 | # Calculate UTC offset |
@@ -240,7 +289,8 b' def patchbomb(ui, repo, *revs, **opts):' | |||
|
240 | 289 | start_time += 1 |
|
241 | 290 | m['From'] = sender |
|
242 | 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 | 294 | if opts['test']: |
|
245 | 295 | ui.status('Displaying ', m['Subject'], ' ...\n') |
|
246 | 296 | fp = os.popen(os.getenv('PAGER', 'more'), 'w') |
@@ -261,12 +311,16 b' def patchbomb(ui, repo, *revs, **opts):' | |||
|
261 | 311 | fp.close() |
|
262 | 312 | else: |
|
263 | 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 | 318 | cmdtable = { |
|
267 | 319 | 'email': |
|
268 | 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 | 324 | ('d', 'diffstat', None, 'add diffstat output to messages'), |
|
271 | 325 | ('f', 'from', '', 'email address of sender'), |
|
272 | 326 | ('', 'plain', None, 'omit hg patch header'), |
@@ -163,12 +163,12 b' def archive(repo, dest, node, kind, deco' | |||
|
163 | 163 | change = repo.changelog.read(node) |
|
164 | 164 | mn = change[0] |
|
165 | 165 | archiver = archivers[kind](dest, prefix, mtime or change[2][0]) |
|
166 |
m |
|
|
167 | mff = repo.manifest.readflags(mn) | |
|
168 |
|
|
|
166 | m = repo.manifest.read(mn) | |
|
167 | items = m.items() | |
|
168 | items.sort() | |
|
169 | 169 | write('.hg_archival.txt', 0644, |
|
170 | 170 | 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node))) |
|
171 |
for filename, filenode in |
|
|
172 |
write(filename, m |
|
|
171 | for filename, filenode in items: | |
|
172 | write(filename, m.execf(filename) and 0755 or 0644, | |
|
173 | 173 | repo.file(filename).read(filenode)) |
|
174 | 174 | archiver.done() |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | /* |
|
2 | 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 | 6 | This software may be used and distributed according to the terms of |
|
7 | 7 | the GNU General Public License, incorporated herein by reference. |
@@ -159,6 +159,10 b' class bundlefilelog(bundlerevlog, filelo' | |||
|
159 | 159 | class bundlerepository(localrepo.localrepository): |
|
160 | 160 | def __init__(self, ui, path, bundlename): |
|
161 | 161 | localrepo.localrepository.__init__(self, ui, path) |
|
162 | ||
|
163 | self._url = 'bundle:' + bundlename | |
|
164 | if path: self._url += '+' + path | |
|
165 | ||
|
162 | 166 | self.tempfile = None |
|
163 | 167 | self.bundlefile = open(bundlename, "rb") |
|
164 | 168 | header = self.bundlefile.read(6) |
@@ -208,6 +212,9 b' class bundlerepository(localrepo.localre' | |||
|
208 | 212 | for c in changegroup.chunkiter(self.bundlefile): |
|
209 | 213 | pass |
|
210 | 214 | |
|
215 | def url(self): | |
|
216 | return self._url | |
|
217 | ||
|
211 | 218 | def dev(self): |
|
212 | 219 | return -1 |
|
213 | 220 | |
@@ -230,3 +237,18 b' class bundlerepository(localrepo.localre' | |||
|
230 | 237 | self.bundlefile.close() |
|
231 | 238 | if self.tempfile is not None: |
|
232 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -10,10 +10,10 b' from node import *' | |||
|
10 | 10 | from i18n import gettext as _ |
|
11 | 11 | demandload(globals(), "os re sys signal shutil imp urllib pdb") |
|
12 | 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 | 14 | demandload(globals(), "traceback errno socket version struct atexit sets bz2") |
|
15 |
demandload(globals(), "archival cStringIO changegroup |
|
|
16 | demandload(globals(), "hgweb.server sshserver") | |
|
15 | demandload(globals(), "archival cStringIO changegroup") | |
|
16 | demandload(globals(), "cmdutil hgweb.server sshserver") | |
|
17 | 17 | |
|
18 | 18 | class UnknownCommand(Exception): |
|
19 | 19 | """Exception raised if command is not in the command table.""" |
@@ -21,47 +21,34 b' class AmbiguousCommand(Exception):' | |||
|
21 | 21 | """Exception raised if command shortcut matches more than one command.""" |
|
22 | 22 | |
|
23 | 23 | def bail_if_changed(repo): |
|
24 |
modified, added, removed, deleted |
|
|
24 | modified, added, removed, deleted = repo.status()[:4] | |
|
25 | 25 | if modified or added or removed or deleted: |
|
26 | 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 | 28 | def relpath(repo, args): |
|
38 | 29 | cwd = repo.getcwd() |
|
39 | 30 | if cwd: |
|
40 | 31 | return [util.normpath(os.path.join(cwd, x)) for x in args] |
|
41 | 32 | return args |
|
42 | 33 | |
|
43 | def matchpats(repo, pats=[], opts={}, head=''): | |
|
44 | cwd = repo.getcwd() | |
|
45 | if not pats and cwd: | |
|
46 | opts['include'] = [os.path.join(cwd, i) for i in opts['include']] | |
|
47 | opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] | |
|
48 | cwd = '' | |
|
49 | return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), | |
|
50 |
|
|
|
51 | ||
|
52 | def makewalk(repo, pats, opts, node=None, head='', badmatch=None): | |
|
53 | files, matchfn, anypats = matchpats(repo, pats, opts, head) | |
|
54 | exact = dict(zip(files, files)) | |
|
55 | def walk(): | |
|
56 | for src, fn in repo.walk(node=node, files=files, match=matchfn, | |
|
57 | badmatch=badmatch): | |
|
58 | yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact | |
|
59 | return files, matchfn, walk() | |
|
60 | ||
|
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 | |
|
34 | def logmessage(opts): | |
|
35 | """ get the log message according to -m and -l option """ | |
|
36 | message = opts['message'] | |
|
37 | logfile = opts['logfile'] | |
|
38 | ||
|
39 | if message and logfile: | |
|
40 | raise util.Abort(_('options --message and --logfile are mutually ' | |
|
41 | 'exclusive')) | |
|
42 | if not message and logfile: | |
|
43 | try: | |
|
44 | if logfile == '-': | |
|
45 | message = sys.stdin.read() | |
|
46 | else: | |
|
47 | message = open(logfile).read() | |
|
48 | except IOError, inst: | |
|
49 | raise util.Abort(_("can't read commit message '%s': %s") % | |
|
50 | (logfile, inst.strerror)) | |
|
51 | return message | |
|
65 | 52 | |
|
66 | 53 | def walkchangerevs(ui, repo, pats, opts): |
|
67 | 54 | '''Iterate over files and the revs they changed in. |
@@ -105,12 +92,23 b' def walkchangerevs(ui, repo, pats, opts)' | |||
|
105 | 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 | 98 | if repo.changelog.count() == 0: |
|
111 | 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 | 112 | wanted = {} |
|
115 | 113 | slowpath = anypats |
|
116 | 114 | fncache = {} |
@@ -125,37 +123,54 b' def walkchangerevs(ui, repo, pats, opts)' | |||
|
125 | 123 | if not slowpath and not files: |
|
126 | 124 | # No files, no patterns. Display all revs. |
|
127 | 125 | wanted = dict(zip(revs, revs)) |
|
126 | copies = [] | |
|
128 | 127 | if not slowpath: |
|
129 | 128 | # Only files, no patterns. Check the history of each file. |
|
130 | def filerevgen(filelog): | |
|
129 | def filerevgen(filelog, node): | |
|
131 | 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 | 136 | revs = [] |
|
134 | 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 | 141 | revs.reverse() |
|
137 | 142 | for rev in revs: |
|
138 | 143 | # only yield rev for which we have the changelog, it can |
|
139 | 144 | # happen while doing "hg log" during a pull or commit |
|
140 | if rev < cl_count: | |
|
145 | if rev[0] < cl_count: | |
|
141 | 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 | 152 | minrev, maxrev = min(revs), max(revs) |
|
144 | for file_ in files: | |
|
153 | for file_, node in iterfiles(): | |
|
145 | 154 | filelog = repo.file(file_) |
|
146 | 155 | # A zero count may be a directory or deleted file, so |
|
147 | 156 | # try to find matching entries on the slow path. |
|
148 | 157 | if filelog.count() == 0: |
|
149 | 158 | slowpath = True |
|
150 | 159 | break |
|
151 | for rev in filerevgen(filelog): | |
|
160 | for rev, copied in filerevgen(filelog, node): | |
|
152 | 161 | if rev <= maxrev: |
|
153 | 162 | if rev < minrev: |
|
154 | 163 | break |
|
155 | 164 | fncache.setdefault(rev, []) |
|
156 | 165 | fncache[rev].append(file_) |
|
157 | 166 | wanted[rev] = 1 |
|
167 | if follow and copied: | |
|
168 | copies.append(copied) | |
|
158 | 169 | if slowpath: |
|
170 | if follow: | |
|
171 | raise util.Abort(_('can only follow copies/renames for explicit ' | |
|
172 | 'file names')) | |
|
173 | ||
|
159 | 174 | # The slow path checks files modified in every changeset. |
|
160 | 175 | def changerevgen(): |
|
161 | 176 | for i, window in increasing_windows(repo.changelog.count()-1, -1): |
@@ -168,11 +183,66 b' def walkchangerevs(ui, repo, pats, opts)' | |||
|
168 | 183 | fncache[rev] = matches |
|
169 | 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 | 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 | 243 | for i, window in increasing_windows(0, len(revs)): |
|
173 | 244 | yield 'window', revs[0] < revs[-1], revs[-1] |
|
174 | nrevs = [rev for rev in revs[i:i+window] | |
|
175 | if rev in wanted] | |
|
245 | nrevs = [rev for rev in revs[i:i+window] if want(rev)] | |
|
176 | 246 | srevs = list(nrevs) |
|
177 | 247 | srevs.sort() |
|
178 | 248 | for rev in srevs: |
@@ -252,62 +322,6 b' def revrange(ui, repo, revs):' | |||
|
252 | 322 | seen[rev] = 1 |
|
253 | 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 | 325 | def write_bundle(cg, filename=None, compress=True): |
|
312 | 326 | """Write a bundle file and return its filename. |
|
313 | 327 | |
@@ -360,83 +374,6 b' def write_bundle(cg, filename=None, comp' | |||
|
360 | 374 | if cleanup is not None: |
|
361 | 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 | 377 | def trimuser(ui, name, rev, revcache): |
|
441 | 378 | """trim the name of the user who committed a change""" |
|
442 | 379 | user = revcache.get(rev) |
@@ -493,7 +430,7 b' class changeset_printer(object):' | |||
|
493 | 430 | self.ui.status(_("date: %s\n") % date) |
|
494 | 431 | |
|
495 | 432 | if self.ui.debugflag: |
|
496 |
files = self.repo. |
|
|
433 | files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
|
497 | 434 | for key, value in zip([_("files:"), _("files+:"), _("files-:")], |
|
498 | 435 | files): |
|
499 | 436 | if value: |
@@ -537,12 +474,19 b' def show_changeset(ui, repo, opts):' | |||
|
537 | 474 | return t |
|
538 | 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 | 484 | def show_version(ui): |
|
541 | 485 | """output version and copyright information""" |
|
542 | 486 | ui.write(_("Mercurial Distributed SCM (version %s)\n") |
|
543 | 487 | % version.get_version()) |
|
544 | 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 | 490 | "This is free software; see the source for copying conditions. " |
|
547 | 491 | "There is NO\nwarranty; " |
|
548 | 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 | 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 | 644 | if exact: |
|
701 | 645 | if ui.verbose: |
|
702 | 646 | ui.status(_('adding %s\n') % rel) |
@@ -715,22 +659,7 b' def addremove(ui, repo, *pats, **opts):' | |||
|
715 | 659 | New files are ignored if they match any of the patterns in .hgignore. As |
|
716 | 660 | with add, these changes take effect at the next commit. |
|
717 | 661 | """ |
|
718 |
return addremove |
|
|
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) | |
|
662 | return cmdutil.addremove(repo, pats, opts) | |
|
734 | 663 | |
|
735 | 664 | def annotate(ui, repo, *pats, **opts): |
|
736 | 665 | """show changeset information per file line |
@@ -773,7 +702,8 b' def annotate(ui, repo, *pats, **opts):' | |||
|
773 | 702 | |
|
774 | 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 | 707 | fctx = ctx.filectx(abs) |
|
778 | 708 | if not opts['text'] and util.binary(fctx.data()): |
|
779 | 709 | ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) |
@@ -825,10 +755,10 b' def archive(ui, repo, dest, **opts):' | |||
|
825 | 755 | raise util.Abort(_('uncommitted merge - please provide a ' |
|
826 | 756 | 'specific revision')) |
|
827 | 757 | |
|
828 | dest = make_filename(repo, dest, node) | |
|
758 | dest = cmdutil.make_filename(repo, dest, node) | |
|
829 | 759 | if os.path.realpath(dest) == repo.root: |
|
830 | 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 | 762 | kind = opts.get('type') or 'files' |
|
833 | 763 | prefix = opts['prefix'] |
|
834 | 764 | if dest == '-': |
@@ -836,7 +766,7 b' def archive(ui, repo, dest, **opts):' | |||
|
836 | 766 | raise util.Abort(_('cannot archive plain files to stdout')) |
|
837 | 767 | dest = sys.stdout |
|
838 | 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 | 770 | archival.archive(repo, dest, node, kind, not opts['no_decode'], |
|
841 | 771 | matchfn, prefix) |
|
842 | 772 | |
@@ -879,7 +809,7 b' def backout(ui, repo, rev, **opts):' | |||
|
879 | 809 | if opts['parent']: |
|
880 | 810 | raise util.Abort(_('cannot use --parent on non-merge changeset')) |
|
881 | 811 | parent = p1 |
|
882 |
repo |
|
|
812 | hg.clean(repo, node, show_stats=False) | |
|
883 | 813 | revert_opts = opts.copy() |
|
884 | 814 | revert_opts['rev'] = hex(parent) |
|
885 | 815 | revert(ui, repo, **revert_opts) |
@@ -896,11 +826,13 b' def backout(ui, repo, rev, **opts):' | |||
|
896 | 826 | if op1 != node: |
|
897 | 827 | if opts['merge']: |
|
898 | 828 | ui.status(_('merging with changeset %s\n') % nice(op1)) |
|
899 |
|
|
|
829 | n = _lookup(repo, hex(op1)) | |
|
830 | hg.merge(repo, n) | |
|
900 | 831 | else: |
|
901 | 832 | ui.status(_('the backout changeset is a new head - ' |
|
902 | 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 | 837 | def bundle(ui, repo, fname, dest=None, **opts): |
|
906 | 838 | """create a changegroup file |
@@ -937,9 +869,10 b' def cat(ui, repo, file1, *pats, **opts):' | |||
|
937 | 869 | %d dirname of file being printed, or '.' if in repo root |
|
938 | 870 | %p root-relative path name of file being printed |
|
939 | 871 | """ |
|
940 | ctx = repo.changectx(opts['rev'] or -1) | |
|
941 |
for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, |
|
|
942 | fp = make_file(repo, opts['output'], ctx.node(), pathname=abs) | |
|
872 | ctx = repo.changectx(opts['rev'] or "-1") | |
|
873 | for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, | |
|
874 | ctx.node()): | |
|
875 | fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) | |
|
943 | 876 | fp.write(ctx.filectx(abs).data()) |
|
944 | 877 | |
|
945 | 878 | def clone(ui, source, dest=None, **opts): |
@@ -954,10 +887,25 b' def clone(ui, source, dest=None, **opts)' | |||
|
954 | 887 | .hg/hgrc file, as the default to be used for future pulls. |
|
955 | 888 | |
|
956 | 889 | For efficiency, hardlinks are used for cloning whenever the source |
|
957 |
and destination are on the same filesystem |
|
|
958 | such as AFS, implement hardlinking incorrectly, but do not report | |
|
959 | errors. In these cases, use the --pull option to avoid | |
|
960 | hardlinking. | |
|
890 | and destination are on the same filesystem (note this applies only | |
|
891 | to the repository data, not to the checked out files). Some | |
|
892 | filesystems, such as AFS, implement hardlinking incorrectly, but | |
|
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 | 910 | See pull for valid source format details. |
|
963 | 911 | |
@@ -965,7 +913,7 b' def clone(ui, source, dest=None, **opts)' | |||
|
965 | 913 | .hg/hgrc will be created on the remote side. Look at the help text |
|
966 | 914 | for the pull command for important details about ssh:// URLs. |
|
967 | 915 | """ |
|
968 | ui.setconfig_remoteopts(**opts) | |
|
916 | setremoteconfig(ui, opts) | |
|
969 | 917 | hg.clone(ui, ui.expandpath(source), dest, |
|
970 | 918 | pull=opts['pull'], |
|
971 | 919 | stream=opts['uncompressed'], |
@@ -983,28 +931,13 b' def commit(ui, repo, *pats, **opts):' | |||
|
983 | 931 | If no commit message is specified, the editor configured in your hgrc |
|
984 | 932 | or in the EDITOR environment variable is started to enter a message. |
|
985 | 933 | """ |
|
986 |
message = 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)) | |
|
934 | message = logmessage(opts) | |
|
1001 | 935 | |
|
1002 | 936 | if opts['addremove']: |
|
1003 |
addremove |
|
|
1004 | fns, match, anypats = matchpats(repo, pats, opts) | |
|
937 | cmdutil.addremove(repo, pats, opts) | |
|
938 | fns, match, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
1005 | 939 | if pats: |
|
1006 | modified, added, removed, deleted, unknown = ( | |
|
1007 | repo.changes(files=fns, match=match)) | |
|
940 | modified, added, removed = repo.status(files=fns, match=match)[:3] | |
|
1008 | 941 | files = modified + added + removed |
|
1009 | 942 | else: |
|
1010 | 943 | files = [] |
@@ -1159,7 +1092,7 b' def docopy(ui, repo, pats, opts, wlock):' | |||
|
1159 | 1092 | copylist = [] |
|
1160 | 1093 | for pat in pats: |
|
1161 | 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 | 1096 | origsrc = okaytocopy(abssrc, relsrc, exact) |
|
1164 | 1097 | if origsrc: |
|
1165 | 1098 | srcs.append((origsrc, abssrc, relsrc, exact)) |
@@ -1233,9 +1166,9 b' def debugrebuildstate(ui, repo, rev=None' | |||
|
1233 | 1166 | rev = repo.lookup(rev) |
|
1234 | 1167 | change = repo.changelog.read(rev) |
|
1235 | 1168 | n = change[0] |
|
1236 |
files = repo.manifest.read |
|
|
1169 | files = repo.manifest.read(n) | |
|
1237 | 1170 | wlock = repo.wlock() |
|
1238 |
repo.dirstate.rebuild(rev, files |
|
|
1171 | repo.dirstate.rebuild(rev, files) | |
|
1239 | 1172 | |
|
1240 | 1173 | def debugcheckstate(ui, repo): |
|
1241 | 1174 | """validate the correctness of the current dirstate""" |
@@ -1376,7 +1309,7 b' def debugrename(ui, repo, file, rev=None' | |||
|
1376 | 1309 | |
|
1377 | 1310 | def debugwalk(ui, repo, *pats, **opts): |
|
1378 | 1311 | """show how files match on given patterns""" |
|
1379 | items = list(walk(repo, pats, opts)) | |
|
1312 | items = list(cmdutil.walk(repo, pats, opts)) | |
|
1380 | 1313 | if not items: |
|
1381 | 1314 | return |
|
1382 | 1315 | fmt = '%%s %%-%ds %%-%ds %%s' % ( |
@@ -1405,37 +1338,10 b' def diff(ui, repo, *pats, **opts):' | |||
|
1405 | 1338 | """ |
|
1406 | 1339 | node1, node2 = revpair(ui, repo, opts['rev']) |
|
1407 | 1340 | |
|
1408 | fns, matchfn, anypats = matchpats(repo, pats, opts) | |
|
1409 | ||
|
1410 |
|
|
|
1411 | text=opts['text'], opts=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() | |
|
1341 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
1342 | ||
|
1343 | patch.diff(repo, node1, node2, fns, match=matchfn, | |
|
1344 | opts=patch.diffopts(ui, opts)) | |
|
1439 | 1345 | |
|
1440 | 1346 | def export(ui, repo, *changesets, **opts): |
|
1441 | 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 | 1373 | if not changesets: |
|
1468 | 1374 | raise util.Abort(_("export requires at least one changeset")) |
|
1469 | seqno = 0 | |
|
1470 | 1375 | revs = list(revrange(ui, repo, changesets)) |
|
1471 |
|
|
|
1472 | revwidth = max(map(len, revs)) | |
|
1473 | msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n") | |
|
1474 | ui.note(msg) | |
|
1475 | for cset in revs: | |
|
1476 | seqno += 1 | |
|
1477 | doexport(ui, repo, cset, seqno, total, revwidth, opts) | |
|
1376 | if len(revs) > 1: | |
|
1377 | ui.note(_('exporting patches:\n')) | |
|
1378 | else: | |
|
1379 | ui.note(_('exporting patch:\n')) | |
|
1380 | patch.export(repo, map(repo.lookup, revs), template=opts['output'], | |
|
1381 | switch_parent=opts['switch_parent'], | |
|
1382 | opts=patch.diffopts(ui, opts)) | |
|
1478 | 1383 | |
|
1479 | 1384 | def forget(ui, repo, *pats, **opts): |
|
1480 | 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 | 1393 | ui.warn(_("(the forget command is deprecated; use revert instead)\n")) |
|
1489 | 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 | 1396 | if repo.dirstate.state(abs) == 'a': |
|
1492 | 1397 | forget.append(abs) |
|
1493 | 1398 | if ui.verbose or not exact: |
@@ -1544,42 +1449,56 b' def grep(ui, repo, pattern, *pats, **opt' | |||
|
1544 | 1449 | self.linenum = linenum |
|
1545 | 1450 | self.colstart = colstart |
|
1546 | 1451 | self.colend = colend |
|
1452 | ||
|
1547 | 1453 | def __eq__(self, other): |
|
1548 | 1454 | return self.line == other.line |
|
1549 | def __hash__(self): | |
|
1550 | return hash(self.line) | |
|
1551 | 1455 | |
|
1552 | 1456 | matches = {} |
|
1457 | copies = {} | |
|
1553 | 1458 | def grepbody(fn, rev, body): |
|
1554 |
matches[rev].setdefault(fn, |
|
|
1459 | matches[rev].setdefault(fn, []) | |
|
1555 | 1460 | m = matches[rev][fn] |
|
1556 | 1461 | for lnum, cstart, cend, line in matchlines(body): |
|
1557 | 1462 | s = linestate(line, lnum, cstart, cend) |
|
1558 |
m |
|
|
1559 | ||
|
1560 | # FIXME: prev isn't used, why ? | |
|
1463 | m.append(s) | |
|
1464 | ||
|
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 | 1480 | prev = {} |
|
1562 | 1481 | ucache = {} |
|
1563 | 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 | 1483 | counts = {'-': 0, '+': 0} |
|
1567 | 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 | 1490 | if incrementing or not opts['all']: |
|
1570 | change = ((l in prevstates) and '-') or '+' | |
|
1571 | 1491 | r = rev |
|
1572 | 1492 | else: |
|
1573 | change = ((l in states) and '-') or '+' | |
|
1574 | 1493 | r = prev[fn] |
|
1575 |
cols = [fn, str(r |
|
|
1494 | cols = [fn, str(r)] | |
|
1576 | 1495 | if opts['line_number']: |
|
1577 | 1496 | cols.append(str(l.linenum)) |
|
1578 | 1497 | if opts['all']: |
|
1579 | 1498 | cols.append(change) |
|
1580 | 1499 | if opts['user']: |
|
1581 |
cols.append(trimuser(ui, getchange(r |
|
|
1582 |
|
|
|
1500 | cols.append(trimuser(ui, getchange(r)[1], rev, | |
|
1501 | ucache)) | |
|
1583 | 1502 | if opts['files_with_matches']: |
|
1584 | 1503 | c = (fn, rev) |
|
1585 | 1504 | if c in filerevmatches: |
@@ -1596,6 +1515,7 b' def grep(ui, repo, pattern, *pats, **opt' | |||
|
1596 | 1515 | changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) |
|
1597 | 1516 | count = 0 |
|
1598 | 1517 | incrementing = False |
|
1518 | follow = opts.get('follow') | |
|
1599 | 1519 | for st, rev, fns in changeiter: |
|
1600 | 1520 | if st == 'window': |
|
1601 | 1521 | incrementing = rev |
@@ -1610,20 +1530,31 b' def grep(ui, repo, pattern, *pats, **opt' | |||
|
1610 | 1530 | fstate.setdefault(fn, {}) |
|
1611 | 1531 | try: |
|
1612 | 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 | 1537 | except KeyError: |
|
1614 | 1538 | pass |
|
1615 | 1539 | elif st == 'iter': |
|
1616 | 1540 | states = matches[rev].items() |
|
1617 | 1541 | states.sort() |
|
1618 | 1542 | for fn, m in states: |
|
1543 | copy = copies.get(rev, {}).get(fn) | |
|
1619 | 1544 | if fn in skip: |
|
1545 | if copy: | |
|
1546 | skip[copy] = True | |
|
1620 | 1547 | continue |
|
1621 | 1548 | if incrementing or not opts['all'] or fstate[fn]: |
|
1622 | 1549 | pos, neg = display(fn, rev, m, fstate[fn]) |
|
1623 | 1550 | count += pos + neg |
|
1624 | 1551 | if pos and not opts['all']: |
|
1625 | 1552 | skip[fn] = True |
|
1553 | if copy: | |
|
1554 | skip[copy] = True | |
|
1626 | 1555 | fstate[fn] = m |
|
1556 | if copy: | |
|
1557 | fstate[copy] = m | |
|
1627 | 1558 | prev[fn] = rev |
|
1628 | 1559 | |
|
1629 | 1560 | if not incrementing: |
@@ -1632,7 +1563,8 b' def grep(ui, repo, pattern, *pats, **opt' | |||
|
1632 | 1563 | for fn, state in fstate: |
|
1633 | 1564 | if fn in skip: |
|
1634 | 1565 | continue |
|
1635 | display(fn, rev, {}, state) | |
|
1566 | if fn not in copies.get(prev[fn], {}): | |
|
1567 | display(fn, rev, {}, state) | |
|
1636 | 1568 | return (count == 0 and 1) or 0 |
|
1637 | 1569 | |
|
1638 | 1570 | def heads(ui, repo, **opts): |
@@ -1670,7 +1602,7 b' def identify(ui, repo):' | |||
|
1670 | 1602 | return |
|
1671 | 1603 | |
|
1672 | 1604 | hexfunc = ui.verbose and hex or short |
|
1673 |
modified, added, removed, deleted |
|
|
1605 | modified, added, removed, deleted = repo.status()[:4] | |
|
1674 | 1606 | output = ["%s%s" % |
|
1675 | 1607 | ('+'.join([hexfunc(parent) for parent in parents]), |
|
1676 | 1608 | (modified or added or removed or deleted) and "+" or "")] |
@@ -1714,81 +1646,23 b' def import_(ui, repo, patch1, *patches, ' | |||
|
1714 | 1646 | d = opts["base"] |
|
1715 | 1647 | strip = opts["strip"] |
|
1716 | 1648 | |
|
1717 | mailre = re.compile(r'(?:From |[\w-]+:)') | |
|
1718 | ||
|
1719 | # attempt to detect the start of a patch | |
|
1720 | # (this heuristic is borrowed from quilt) | |
|
1721 | diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + | |
|
1722 | 'retrieving revision [0-9]+(\.[0-9]+)*$|' + | |
|
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() | |
|
1649 | wlock = repo.wlock() | |
|
1650 | lock = repo.lock() | |
|
1651 | ||
|
1652 | for p in patches: | |
|
1653 | pf = os.path.join(d, p) | |
|
1654 | ||
|
1734 | 1655 | if pf == '-': |
|
1735 | msg = p.parse(sys.stdin) | |
|
1736 | 1656 | ui.status(_("applying patch from stdin\n")) |
|
1657 | tmpname, message, user, date = patch.extract(ui, sys.stdin) | |
|
1737 | 1658 | else: |
|
1738 | msg = p.parse(file(pf)) | |
|
1739 | ui.status(_("applying %s\n") % patch) | |
|
1740 | ||
|
1741 | fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') | |
|
1742 | tmpfp = os.fdopen(fd, 'w') | |
|
1659 | ui.status(_("applying %s\n") % p) | |
|
1660 | tmpname, message, user, date = patch.extract(ui, file(pf)) | |
|
1661 | ||
|
1662 | if tmpname is None: | |
|
1663 | raise util.Abort(_('no diffs found')) | |
|
1664 | ||
|
1743 | 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 | 1666 | if opts['message']: |
|
1793 | 1667 | # pickup the cmdline msg |
|
1794 | 1668 | message = opts['message'] |
@@ -1800,14 +1674,9 b' def import_(ui, repo, patch1, *patches, ' | |||
|
1800 | 1674 | message = None |
|
1801 | 1675 | ui.debug(_('message:\n%s\n') % message) |
|
1802 | 1676 | |
|
1803 | tmpfp.close() | |
|
1804 | if not diffs_seen: | |
|
1805 | raise util.Abort(_('no diffs found')) | |
|
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) | |
|
1677 | files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) | |
|
1678 | files = patch.updatedir(ui, repo, files, wlock=wlock) | |
|
1679 | repo.commit(files, message, user, date, wlock=wlock, lock=lock) | |
|
1811 | 1680 | finally: |
|
1812 | 1681 | os.unlink(tmpname) |
|
1813 | 1682 | |
@@ -1824,7 +1693,7 b' def incoming(ui, repo, source="default",' | |||
|
1824 | 1693 | See pull for valid source format details. |
|
1825 | 1694 | """ |
|
1826 | 1695 | source = ui.expandpath(source) |
|
1827 | ui.setconfig_remoteopts(**opts) | |
|
1696 | setremoteconfig(ui, opts) | |
|
1828 | 1697 | |
|
1829 | 1698 | other = hg.repository(ui, source) |
|
1830 | 1699 | incoming = repo.findincoming(other, force=opts["force"]) |
@@ -1860,7 +1729,7 b' def incoming(ui, repo, source="default",' | |||
|
1860 | 1729 | displayer.show(changenode=n) |
|
1861 | 1730 | if opts['patch']: |
|
1862 | 1731 | prev = (parents and parents[0]) or nullid |
|
1863 |
|
|
|
1732 | patch.diff(repo, other, prev, n) | |
|
1864 | 1733 | ui.write("\n") |
|
1865 | 1734 | finally: |
|
1866 | 1735 | if hasattr(other, 'close'): |
@@ -1880,7 +1749,7 b' def init(ui, dest=".", **opts):' | |||
|
1880 | 1749 | Look at the help text for the pull command for important details |
|
1881 | 1750 | about ssh:// URLs. |
|
1882 | 1751 | """ |
|
1883 | ui.setconfig_remoteopts(**opts) | |
|
1752 | setremoteconfig(ui, opts) | |
|
1884 | 1753 | hg.repository(ui, dest, create=1) |
|
1885 | 1754 | |
|
1886 | 1755 | def locate(ui, repo, *pats, **opts): |
@@ -1908,8 +1777,8 b' def locate(ui, repo, *pats, **opts):' | |||
|
1908 | 1777 | else: |
|
1909 | 1778 | node = None |
|
1910 | 1779 | |
|
1911 | for src, abs, rel, exact in walk(repo, pats, opts, node=node, | |
|
1912 | head='(?:.*/|)'): | |
|
1780 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, | |
|
1781 | head='(?:.*/|)'): | |
|
1913 | 1782 | if not node and repo.dirstate.state(abs) == '?': |
|
1914 | 1783 | continue |
|
1915 | 1784 | if opts['fullpath']: |
@@ -1920,7 +1789,18 b' def locate(ui, repo, *pats, **opts):' | |||
|
1920 | 1789 | def log(ui, repo, *pats, **opts): |
|
1921 | 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 | 1805 | By default this command outputs: changeset id and hash, tags, |
|
1926 | 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 | 1880 | displayer.show(rev, brinfo=br) |
|
2001 | 1881 | if opts['patch']: |
|
2002 | 1882 | prev = (parents and parents[0]) or nullid |
|
2003 |
|
|
|
1883 | patch.diff(repo, prev, changenode, match=matchfn, fp=du) | |
|
2004 | 1884 | du.write("\n\n") |
|
2005 | 1885 | elif st == 'iter': |
|
2006 | 1886 | if count == limit: break |
@@ -2031,22 +1911,44 b' def manifest(ui, repo, rev=None):' | |||
|
2031 | 1911 | else: |
|
2032 | 1912 | n = repo.manifest.tip() |
|
2033 | 1913 | m = repo.manifest.read(n) |
|
2034 | mf = repo.manifest.readflags(n) | |
|
2035 | 1914 | files = m.keys() |
|
2036 | 1915 | files.sort() |
|
2037 | 1916 | |
|
2038 | 1917 | for f in files: |
|
2039 |
ui.write("%40s %3s %s\n" % (hex(m[f]), |
|
|
2040 | ||
|
2041 | def merge(ui, repo, node=None, **opts): | |
|
1918 | ui.write("%40s %3s %s\n" % (hex(m[f]), | |
|
1919 | m.execf(f) and "755" or "644", f)) | |
|
1920 | ||
|
1921 | def merge(ui, repo, node=None, force=None, branch=None): | |
|
2042 | 1922 | """Merge working directory with another revision |
|
2043 | 1923 | |
|
2044 | 1924 | Merge the contents of the current working directory and the |
|
2045 | 1925 | requested revision. Files that changed between either parent are |
|
2046 | 1926 | marked as changed for the next commit and a commit must be |
|
2047 | 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 | 1953 | def outgoing(ui, repo, dest=None, **opts): |
|
2052 | 1954 | """show changesets not found in destination |
@@ -2058,7 +1960,7 b' def outgoing(ui, repo, dest=None, **opts' | |||
|
2058 | 1960 | See pull for valid destination format details. |
|
2059 | 1961 | """ |
|
2060 | 1962 | dest = ui.expandpath(dest or 'default-push', dest or 'default') |
|
2061 | ui.setconfig_remoteopts(**opts) | |
|
1963 | setremoteconfig(ui, opts) | |
|
2062 | 1964 | revs = None |
|
2063 | 1965 | if opts['rev']: |
|
2064 | 1966 | revs = [repo.lookup(rev) for rev in opts['rev']] |
@@ -2079,16 +1981,31 b' def outgoing(ui, repo, dest=None, **opts' | |||
|
2079 | 1981 | displayer.show(changenode=n) |
|
2080 | 1982 | if opts['patch']: |
|
2081 | 1983 | prev = (parents and parents[0]) or nullid |
|
2082 |
|
|
|
1984 | patch.diff(repo, prev, n) | |
|
2083 | 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 | 1988 | """show the parents of the working dir or revision |
|
2087 | 1989 | |
|
2088 | 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 | 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 | 2009 | else: |
|
2093 | 2010 | p = repo.dirstate.parents() |
|
2094 | 2011 | |
@@ -2125,7 +2042,7 b' def postincoming(ui, repo, modheads, opt' | |||
|
2125 | 2042 | return |
|
2126 | 2043 | if optupdate: |
|
2127 | 2044 | if modheads == 1: |
|
2128 |
return |
|
|
2045 | return hg.update(repo, repo.changelog.tip()) # update | |
|
2129 | 2046 | else: |
|
2130 | 2047 | ui.status(_("not updating, since new heads added\n")) |
|
2131 | 2048 | if modheads > 1: |
@@ -2165,7 +2082,7 b' def pull(ui, repo, source="default", **o' | |||
|
2165 | 2082 | with the --ssh command line option. |
|
2166 | 2083 | """ |
|
2167 | 2084 | source = ui.expandpath(source) |
|
2168 | ui.setconfig_remoteopts(**opts) | |
|
2085 | setremoteconfig(ui, opts) | |
|
2169 | 2086 | |
|
2170 | 2087 | other = hg.repository(ui, source) |
|
2171 | 2088 | ui.status(_('pulling from %s\n') % (source)) |
@@ -2203,7 +2120,7 b' def push(ui, repo, dest=None, **opts):' | |||
|
2203 | 2120 | feature is enabled on the remote Mercurial server. |
|
2204 | 2121 | """ |
|
2205 | 2122 | dest = ui.expandpath(dest or 'default-push', dest or 'default') |
|
2206 | ui.setconfig_remoteopts(**opts) | |
|
2123 | setremoteconfig(ui, opts) | |
|
2207 | 2124 | |
|
2208 | 2125 | other = hg.repository(ui, dest) |
|
2209 | 2126 | ui.status('pushing to %s\n' % (dest)) |
@@ -2257,7 +2174,7 b' def recover(ui, repo):' | |||
|
2257 | 2174 | operation. It should only be necessary when Mercurial suggests it. |
|
2258 | 2175 | """ |
|
2259 | 2176 | if repo.recover(): |
|
2260 |
return |
|
|
2177 | return hg.verify(repo) | |
|
2261 | 2178 | return 1 |
|
2262 | 2179 | |
|
2263 | 2180 | def remove(ui, repo, *pats, **opts): |
@@ -2277,12 +2194,12 b' def remove(ui, repo, *pats, **opts):' | |||
|
2277 | 2194 | names = [] |
|
2278 | 2195 | if not opts['after'] and not pats: |
|
2279 | 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 | 2198 | exact = dict.fromkeys(files) |
|
2282 |
mardu = map(dict.fromkeys, repo. |
|
|
2199 | mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] | |
|
2283 | 2200 | modified, added, removed, deleted, unknown = mardu |
|
2284 | 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 | 2203 | reason = None |
|
2287 | 2204 | if abs not in deleted and opts['after']: |
|
2288 | 2205 | reason = _('is still present') |
@@ -2389,20 +2306,21 b' def revert(ui, repo, *pats, **opts):' | |||
|
2389 | 2306 | |
|
2390 | 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 | 2311 | names[abs] = (rel, exact) |
|
2394 | 2312 | if src == 'b': |
|
2395 | 2313 | target_only[abs] = True |
|
2396 | 2314 | |
|
2397 | 2315 | # walk target manifest. |
|
2398 | 2316 | |
|
2399 | for src, abs, rel, exact in walk(repo, pats, opts, node=node, | |
|
2400 | badmatch=names.has_key): | |
|
2317 | for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, | |
|
2318 | badmatch=names.has_key): | |
|
2401 | 2319 | if abs in names: continue |
|
2402 | 2320 | names[abs] = (rel, exact) |
|
2403 | 2321 | target_only[abs] = True |
|
2404 | 2322 | |
|
2405 |
changes = repo. |
|
|
2323 | changes = repo.status(match=names.has_key, wlock=wlock)[:5] | |
|
2406 | 2324 | modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) |
|
2407 | 2325 | |
|
2408 | 2326 | revert = ([], _('reverting %s\n')) |
@@ -2474,8 +2392,7 b' def revert(ui, repo, *pats, **opts):' | |||
|
2474 | 2392 | |
|
2475 | 2393 | if not opts.get('dry_run'): |
|
2476 | 2394 | repo.dirstate.forget(forget[0]) |
|
2477 |
r = repo |
|
|
2478 | show_stats=False) | |
|
2395 | r = hg.revert(repo, node, update.has_key, wlock) | |
|
2479 | 2396 | repo.dirstate.update(add[0], 'a') |
|
2480 | 2397 | repo.dirstate.update(undelete[0], 'n') |
|
2481 | 2398 | repo.dirstate.update(remove[0], 'r') |
@@ -2593,37 +2510,44 b' def serve(ui, repo, **opts):' | |||
|
2593 | 2510 | def status(ui, repo, *pats, **opts): |
|
2594 | 2511 | """show changed files in the working directory |
|
2595 | 2512 | |
|
2596 |
Show |
|
|
2597 | given, only files that match are shown. | |
|
2513 | Show status of files in the repository. If names are given, only | |
|
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 | 2517 | The codes used to show the status of files are: |
|
2600 | 2518 | M = modified |
|
2601 | 2519 | A = added |
|
2602 | 2520 | R = removed |
|
2521 | C = clean | |
|
2603 | 2522 | ! = deleted, but still tracked |
|
2604 | 2523 | ? = not tracked |
|
2605 | 2524 | I = ignored (not shown by default) |
|
2606 | 2525 | = the previous added file was copied from here |
|
2607 | 2526 | """ |
|
2608 | 2527 | |
|
2609 | show_ignored = opts['ignored'] and True or False | |
|
2610 | files, matchfn, anypats = matchpats(repo, pats, opts) | |
|
2528 | all = opts['all'] | |
|
2529 | ||
|
2530 | files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
|
2611 | 2531 | cwd = (pats and repo.getcwd()) or '' |
|
2612 | modified, added, removed, deleted, unknown, ignored = [ | |
|
2532 | modified, added, removed, deleted, unknown, ignored, clean = [ | |
|
2613 | 2533 | [util.pathto(cwd, x) for x in n] |
|
2614 |
for n in repo. |
|
|
2615 |
|
|
|
2616 | ||
|
2617 | changetypes = [('modified', 'M', modified), | |
|
2534 | for n in repo.status(files=files, match=matchfn, | |
|
2535 | list_ignored=all or opts['ignored'], | |
|
2536 | list_clean=all or opts['clean'])] | |
|
2537 | ||
|
2538 | changetypes = (('modified', 'M', modified), | |
|
2618 | 2539 | ('added', 'A', added), |
|
2619 | 2540 | ('removed', 'R', removed), |
|
2620 | 2541 | ('deleted', '!', deleted), |
|
2621 | 2542 | ('unknown', '?', unknown), |
|
2622 |
('ignored', 'I', ignored) |
|
|
2543 | ('ignored', 'I', ignored)) | |
|
2544 | ||
|
2545 | explicit_changetypes = changetypes + (('clean', 'C', clean),) | |
|
2623 | 2546 | |
|
2624 | 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 | 2551 | or changetypes): |
|
2628 | 2552 | if opts['no_status']: |
|
2629 | 2553 | format = "%%s%s" % end |
@@ -2632,7 +2556,7 b' def status(ui, repo, *pats, **opts):' | |||
|
2632 | 2556 | |
|
2633 | 2557 | for f in changes: |
|
2634 | 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 | 2560 | and opt == 'added' and repo.dirstate.copies.has_key(f)): |
|
2637 | 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 | 2569 | very useful to compare different revision, to go back to significant |
|
2646 | 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 | 2574 | To facilitate version control, distribution, and merging of tags, |
|
2651 | 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 | 2577 | necessary. The file '.hg/localtags' is used for local tags (not |
|
2654 | 2578 | shared among repositories). |
|
2655 | 2579 | """ |
|
2656 |
if name |
|
|
2657 |
raise util.Abort(_("the name ' |
|
|
2580 | if name in ['tip', '.']: | |
|
2581 | raise util.Abort(_("the name '%s' is reserved") % name) | |
|
2658 | 2582 | if rev_ is not None: |
|
2659 | 2583 | ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " |
|
2660 | 2584 | "please use 'hg tag [-r REV] NAME' instead\n")) |
@@ -2665,7 +2589,12 b' def tag(ui, repo, name, rev_=None, **opt' | |||
|
2665 | 2589 | if rev_: |
|
2666 | 2590 | r = hex(repo.lookup(rev_)) |
|
2667 | 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 | 2599 | repo.tag(name, r, opts['local'], opts['message'], opts['user'], |
|
2671 | 2600 | opts['date']) |
@@ -2701,7 +2630,7 b' def tip(ui, repo, **opts):' | |||
|
2701 | 2630 | br = repo.branchlookup([n]) |
|
2702 | 2631 | show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) |
|
2703 | 2632 | if opts['patch']: |
|
2704 |
|
|
|
2633 | patch.diff(repo, repo.changelog.parents(n)[0], n) | |
|
2705 | 2634 | |
|
2706 | 2635 | def unbundle(ui, repo, fname, **opts): |
|
2707 | 2636 | """apply a changegroup file |
@@ -2730,7 +2659,8 b' def unbundle(ui, repo, fname, **opts):' | |||
|
2730 | 2659 | raise util.Abort(_("%s: unknown bundle compression type") |
|
2731 | 2660 | % fname) |
|
2732 | 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 | 2664 | return postincoming(ui, repo, modheads, opts['update']) |
|
2735 | 2665 | |
|
2736 | 2666 | def undo(ui, repo): |
@@ -2745,7 +2675,7 b' def undo(ui, repo):' | |||
|
2745 | 2675 | repo.rollback() |
|
2746 | 2676 | |
|
2747 | 2677 | def update(ui, repo, node=None, merge=False, clean=False, force=None, |
|
2748 |
branch=None |
|
|
2678 | branch=None): | |
|
2749 | 2679 | """update or merge working directory |
|
2750 | 2680 | |
|
2751 | 2681 | Update the working directory to the specified revision. |
@@ -2760,13 +2690,17 b' def update(ui, repo, node=None, merge=Fa' | |||
|
2760 | 2690 | By default, update will refuse to run if doing so would require |
|
2761 | 2691 | merging or discarding local changes. |
|
2762 | 2692 | """ |
|
2693 | node = _lookup(repo, node, branch) | |
|
2763 | 2694 | if merge: |
|
2764 | 2695 | ui.warn(_('(the -m/--merge option is deprecated; ' |
|
2765 | 2696 | 'use the merge command instead)\n')) |
|
2766 | return doupdate(ui, repo, node, merge, clean, force, branch, **opts) | |
|
2767 | ||
|
2768 | def doupdate(ui, repo, node=None, merge=False, clean=False, force=None, | |
|
2769 | branch=None, **opts): | |
|
2697 | return hg.merge(repo, node, force=force) | |
|
2698 | elif clean: | |
|
2699 | return hg.clean(repo, node) | |
|
2700 | else: | |
|
2701 | return hg.update(repo, node) | |
|
2702 | ||
|
2703 | def _lookup(repo, node, branch=None): | |
|
2770 | 2704 | if branch: |
|
2771 | 2705 | br = repo.branchlookup(branch=branch) |
|
2772 | 2706 | found = [] |
@@ -2774,19 +2708,19 b' def doupdate(ui, repo, node=None, merge=' | |||
|
2774 | 2708 | if branch in br[x]: |
|
2775 | 2709 | found.append(x) |
|
2776 | 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 | 2712 | for x in found: |
|
2779 |
show_changeset(ui, repo, |
|
|
2780 |
re |
|
|
2713 | show_changeset(ui, repo, {}).show(changenode=x, brinfo=br) | |
|
2714 | raise util.Abort("") | |
|
2781 | 2715 | if len(found) == 1: |
|
2782 | 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 | 2719 | else: |
|
2785 |
ui. |
|
|
2786 | return 1 | |
|
2720 | raise util.Abort(_("branch %s not found\n") % (branch)) | |
|
2787 | 2721 | else: |
|
2788 | 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 | 2725 | def verify(ui, repo): |
|
2792 | 2726 | """verify the integrity of the repository |
@@ -2798,7 +2732,7 b' def verify(ui, repo):' | |||
|
2798 | 2732 | the changelog, manifest, and tracked files, as well as the |
|
2799 | 2733 | integrity of their crosslinks and indices. |
|
2800 | 2734 | """ |
|
2801 |
return |
|
|
2735 | return hg.verify(repo) | |
|
2802 | 2736 | |
|
2803 | 2737 | # Command options and aliases are listed here, alphabetically |
|
2804 | 2738 | |
@@ -2919,6 +2853,7 b' table = {' | |||
|
2919 | 2853 | ('a', 'text', None, _('treat all files as text')), |
|
2920 | 2854 | ('p', 'show-function', None, |
|
2921 | 2855 | _('show which function each change is in')), |
|
2856 | ('g', 'git', None, _('use git extended diff format')), | |
|
2922 | 2857 | ('w', 'ignore-all-space', None, |
|
2923 | 2858 | _('ignore white space when comparing lines')), |
|
2924 | 2859 | ('b', 'ignore-space-change', None, |
@@ -2943,6 +2878,8 b' table = {' | |||
|
2943 | 2878 | (grep, |
|
2944 | 2879 | [('0', 'print0', None, _('end fields with NUL')), |
|
2945 | 2880 | ('', 'all', None, _('print all revisions that match')), |
|
2881 | ('f', 'follow', None, | |
|
2882 | _('follow changeset history, or file history across copies and renames')), | |
|
2946 | 2883 | ('i', 'ignore-case', None, _('ignore case when matching')), |
|
2947 | 2884 | ('l', 'files-with-matches', None, |
|
2948 | 2885 | _('print only filenames and revs that match')), |
@@ -2979,7 +2916,7 b' table = {' | |||
|
2979 | 2916 | ('n', 'newest-first', None, _('show newest record first')), |
|
2980 | 2917 | ('', 'bundle', '', _('file to store the bundles into')), |
|
2981 | 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 | 2920 | ('', 'template', '', _('display with template')), |
|
2984 | 2921 | ('e', 'ssh', '', _('specify ssh command to use')), |
|
2985 | 2922 | ('', 'remotecmd', '', |
@@ -3005,6 +2942,10 b' table = {' | |||
|
3005 | 2942 | "^log|history": |
|
3006 | 2943 | (log, |
|
3007 | 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 | 2949 | ('k', 'keyword', [], _('search for a keyword')), |
|
3009 | 2950 | ('l', 'limit', '', _('limit number of changes displayed')), |
|
3010 | 2951 | ('r', 'rev', [], _('show the specified revision or range')), |
@@ -3012,6 +2953,7 b' table = {' | |||
|
3012 | 2953 | ('', 'style', '', _('display using template map file')), |
|
3013 | 2954 | ('m', 'only-merges', None, _('show only merges')), |
|
3014 | 2955 | ('p', 'patch', None, _('show patch')), |
|
2956 | ('P', 'prune', [], _('do not display revision or any of its ancestors')), | |
|
3015 | 2957 | ('', 'template', '', _('display with template')), |
|
3016 | 2958 | ('I', 'include', [], _('include names matching the given patterns')), |
|
3017 | 2959 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
@@ -3038,9 +2980,10 b' table = {' | |||
|
3038 | 2980 | "^parents": |
|
3039 | 2981 | (parents, |
|
3040 | 2982 | [('b', 'branches', None, _('show branches')), |
|
2983 | ('r', 'rev', '', _('show parents from the specified rev')), | |
|
3041 | 2984 | ('', 'style', '', _('display using template map file')), |
|
3042 | 2985 | ('', 'template', '', _('display with template'))], |
|
3043 | _('hg parents [-b] [REV]')), | |
|
2986 | _('hg parents [-b] [-r REV] [FILE]')), | |
|
3044 | 2987 | "paths": (paths, [], _('hg paths [NAME]')), |
|
3045 | 2988 | "^pull": |
|
3046 | 2989 | (pull, |
@@ -3049,7 +2992,7 b' table = {' | |||
|
3049 | 2992 | ('e', 'ssh', '', _('specify ssh command to use')), |
|
3050 | 2993 | ('f', 'force', None, |
|
3051 | 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 | 2996 | ('', 'remotecmd', '', |
|
3054 | 2997 | _('specify hg command to run on the remote side'))], |
|
3055 | 2998 | _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), |
@@ -3117,10 +3060,12 b' table = {' | |||
|
3117 | 3060 | _('hg serve [OPTION]...')), |
|
3118 | 3061 | "^status|st": |
|
3119 | 3062 | (status, |
|
3120 |
[(' |
|
|
3063 | [('A', 'all', None, _('show status of all files')), | |
|
3064 | ('m', 'modified', None, _('show only modified files')), | |
|
3121 | 3065 | ('a', 'added', None, _('show only added files')), |
|
3122 | 3066 | ('r', 'removed', None, _('show only removed files')), |
|
3123 | 3067 | ('d', 'deleted', None, _('show only deleted (but tracked) files')), |
|
3068 | ('c', 'clean', None, _('show only files without changes')), | |
|
3124 | 3069 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), |
|
3125 | 3070 | ('i', 'ignored', None, _('show ignored files')), |
|
3126 | 3071 | ('n', 'no-status', None, _('hide status prefix')), |
@@ -3286,24 +3231,16 b' def findext(name):' | |||
|
3286 | 3231 | try: |
|
3287 | 3232 | return sys.modules[external[name]] |
|
3288 | 3233 | except KeyError: |
|
3289 | dotname = '.' + name | |
|
3290 | 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 | 3236 | return sys.modules[v] |
|
3293 | 3237 | raise KeyError(name) |
|
3294 | 3238 | |
|
3295 | def dispatch(args): | |
|
3296 | for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |
|
3297 | num = getattr(signal, name, None) | |
|
3298 | if num: signal.signal(num, catchterm) | |
|
3299 | ||
|
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(): | |
|
3239 | def load_extensions(ui): | |
|
3240 | added = [] | |
|
3241 | for ext_name, load_from_name in ui.extensions(): | |
|
3242 | if ext_name in external: | |
|
3243 | continue | |
|
3307 | 3244 | try: |
|
3308 | 3245 | if load_from_name: |
|
3309 | 3246 | # the module will be loaded in sys.modules |
@@ -3323,23 +3260,36 b' def dispatch(args):' | |||
|
3323 | 3260 | except ImportError: |
|
3324 | 3261 | mod = importh(ext_name) |
|
3325 | 3262 | external[ext_name] = mod.__name__ |
|
3263 | added.append((mod, ext_name)) | |
|
3326 | 3264 | except (util.SignalInterrupt, KeyboardInterrupt): |
|
3327 | 3265 | raise |
|
3328 | 3266 | except Exception, inst: |
|
3329 |
u.warn(_("*** failed to import extension %s: %s\n") % |
|
|
3330 | if u.print_exc(): | |
|
3267 | ui.warn(_("*** failed to import extension %s: %s\n") % | |
|
3268 | (ext_name, inst)) | |
|
3269 | if ui.print_exc(): | |
|
3331 | 3270 | return 1 |
|
3332 | 3271 | |
|
3333 | for name in external.itervalues(): | |
|
3334 | mod = sys.modules[name] | |
|
3272 | for mod, name in added: | |
|
3335 | 3273 | uisetup = getattr(mod, 'uisetup', None) |
|
3336 | 3274 | if uisetup: |
|
3337 | uisetup(u) | |
|
3275 | uisetup(ui) | |
|
3338 | 3276 | cmdtable = getattr(mod, 'cmdtable', {}) |
|
3339 | 3277 | for t in cmdtable: |
|
3340 | 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 | 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 | 3294 | try: |
|
3345 | 3295 | cmd, func, args, options, cmdoptions = parse(u, args) |
@@ -3391,6 +3341,7 b' def dispatch(args):' | |||
|
3391 | 3341 | mod = sys.modules[name] |
|
3392 | 3342 | if hasattr(mod, 'reposetup'): |
|
3393 | 3343 | mod.reposetup(u, repo) |
|
3344 | hg.repo_setup_hooks.append(mod.reposetup) | |
|
3394 | 3345 | except hg.RepoError: |
|
3395 | 3346 | if cmd not in optionalrepo.split(): |
|
3396 | 3347 | raise |
@@ -3398,6 +3349,11 b' def dispatch(args):' | |||
|
3398 | 3349 | else: |
|
3399 | 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 | 3357 | try: |
|
3402 | 3358 | if options['profile']: |
|
3403 | 3359 | import hotshot, hotshot.stats |
@@ -1,6 +1,6 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -11,9 +11,8 b' class changectx(object):' | |||
|
11 | 11 | def __init__(self, repo, changeid): |
|
12 | 12 | """changeid is a revision number, node, or tag""" |
|
13 | 13 | self._repo = repo |
|
14 | self._id = changeid | |
|
15 | 14 | |
|
16 |
self._node = self._repo.lookup( |
|
|
15 | self._node = self._repo.lookup(changeid) | |
|
17 | 16 | self._rev = self._repo.changelog.rev(self._node) |
|
18 | 17 | |
|
19 | 18 | def changeset(self): |
@@ -74,39 +73,40 b' class filectx(object):' | |||
|
74 | 73 | fileid can be a file revision or node.""" |
|
75 | 74 | self._repo = repo |
|
76 | 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 | 80 | # if given a changeset id, go ahead and look up the file |
|
82 |
self._change |
|
|
83 | node, flag = self._repo.manifest.find(self._changeset[0], path) | |
|
81 | self._changeid = changeid | |
|
82 | self._changectx = self.changectx() | |
|
84 | 83 | self._filelog = self._repo.file(self._path) |
|
85 | self._filenode = node | |
|
86 |
el |
|
|
84 | self._filenode = self._changectx.filenode(self._path) | |
|
85 | else: | |
|
87 | 86 | # else be lazy |
|
88 | 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 | 90 | self._filerev = self._filelog.rev(self._filenode) |
|
91 | 91 | |
|
92 |
def change |
|
|
92 | def changectx(self): | |
|
93 | 93 | try: |
|
94 |
return self._change |
|
|
94 | return self._changectx | |
|
95 | 95 | except AttributeError: |
|
96 |
self._change |
|
|
97 |
return self._change |
|
|
96 | self._changectx = changectx(self._repo, self._changeid) | |
|
97 | return self._changectx | |
|
98 | 98 | |
|
99 | 99 | def filerev(self): return self._filerev |
|
100 | 100 | def filenode(self): return self._filenode |
|
101 | 101 | def filelog(self): return self._filelog |
|
102 | 102 | |
|
103 |
def rev(self): return self.change |
|
|
104 |
def node(self): return self.change |
|
|
105 |
def user(self): return self.change |
|
|
106 |
def date(self): return self.change |
|
|
107 |
def files(self): return self.change |
|
|
108 |
def description(self): return self.change |
|
|
109 |
def manifest(self): return self.change |
|
|
103 | def rev(self): return self.changectx().rev() | |
|
104 | def node(self): return self.changectx().node() | |
|
105 | def user(self): return self.changectx().user() | |
|
106 | def date(self): return self.changectx().date() | |
|
107 | def files(self): return self.changectx().files() | |
|
108 | def description(self): return self.changectx().description() | |
|
109 | def manifest(self): return self.changectx().manifest() | |
|
110 | 110 | |
|
111 | 111 | def data(self): return self._filelog.read(self._filenode) |
|
112 | 112 | def metadata(self): return self._filelog.readmeta(self._filenode) |
@@ -96,6 +96,7 b' def demandload(scope, modules):' | |||
|
96 | 96 | |
|
97 | 97 | foo import foo |
|
98 | 98 | foo bar import foo, bar |
|
99 | foo@bar import foo as bar | |
|
99 | 100 | foo.bar import foo.bar |
|
100 | 101 | foo:bar from foo import bar |
|
101 | 102 | foo:bar,quux from foo import bar, quux |
@@ -108,6 +109,9 b' def demandload(scope, modules):' | |||
|
108 | 109 | mod = mod[:col] |
|
109 | 110 | else: |
|
110 | 111 | fromlist = [] |
|
112 | as = None | |
|
113 | if '@' in mod: | |
|
114 | mod, as = mod.split("@") | |
|
111 | 115 | importer = _importer(scope, mod, fromlist) |
|
112 | 116 | if fromlist: |
|
113 | 117 | for name in fromlist: |
@@ -126,4 +130,6 b' def demandload(scope, modules):' | |||
|
126 | 130 | continue |
|
127 | 131 | else: |
|
128 | 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 | 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 | 6 | This software may be used and distributed according to the terms |
|
7 | 7 | of the GNU General Public License, incorporated herein by reference. |
@@ -10,7 +10,7 b' of the GNU General Public License, incor' | |||
|
10 | 10 | from node import * |
|
11 | 11 | from i18n import gettext as _ |
|
12 | 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 | 15 | class dirstate(object): |
|
16 | 16 | format = ">cllll" |
@@ -22,6 +22,7 b' class dirstate(object):' | |||
|
22 | 22 | self.ui = ui |
|
23 | 23 | self.map = None |
|
24 | 24 | self.pl = None |
|
25 | self.dirs = None | |
|
25 | 26 | self.copies = {} |
|
26 | 27 | self.ignorefunc = None |
|
27 | 28 | self.blockignore = False |
@@ -197,6 +198,38 b' class dirstate(object):' | |||
|
197 | 198 | def copied(self, file): |
|
198 | 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 | 233 | def update(self, files, state, **kw): |
|
201 | 234 | ''' current states: |
|
202 | 235 | n normal |
@@ -207,10 +240,16 b' class dirstate(object):' | |||
|
207 | 240 | if not files: return |
|
208 | 241 | self.lazyread() |
|
209 | 242 | self.markdirty() |
|
243 | if state == "a": | |
|
244 | self.initdirs() | |
|
245 | self.checkshadows(files) | |
|
210 | 246 | for f in files: |
|
211 | 247 | if state == "r": |
|
212 | 248 | self.map[f] = ('r', 0, 0, 0) |
|
249 | self.updatedirs(f, -1) | |
|
213 | 250 | else: |
|
251 | if state == "a": | |
|
252 | self.updatedirs(f, 1) | |
|
214 | 253 | s = os.lstat(self.wjoin(f)) |
|
215 | 254 | st_size = kw.get('st_size', s.st_size) |
|
216 | 255 | st_mtime = kw.get('st_mtime', s.st_mtime) |
@@ -222,9 +261,11 b' class dirstate(object):' | |||
|
222 | 261 | if not files: return |
|
223 | 262 | self.lazyread() |
|
224 | 263 | self.markdirty() |
|
264 | self.initdirs() | |
|
225 | 265 | for f in files: |
|
226 | 266 | try: |
|
227 | 267 | del self.map[f] |
|
268 | self.updatedirs(f, -1) | |
|
228 | 269 | except KeyError: |
|
229 | 270 | self.ui.warn(_("not in dirstate: %s!\n") % f) |
|
230 | 271 | pass |
@@ -232,14 +273,15 b' class dirstate(object):' | |||
|
232 | 273 | def clear(self): |
|
233 | 274 | self.map = {} |
|
234 | 275 | self.copies = {} |
|
276 | self.dirs = None | |
|
235 | 277 | self.markdirty() |
|
236 | 278 | |
|
237 | 279 | def rebuild(self, parent, files): |
|
238 | 280 | self.clear() |
|
239 | 281 | umask = os.umask(0) |
|
240 | 282 | os.umask(umask) |
|
241 |
for f |
|
|
242 |
if |
|
|
283 | for f in files: | |
|
284 | if files.execf(f): | |
|
243 | 285 | self.map[f] = ('n', ~umask, -1, 0) |
|
244 | 286 | else: |
|
245 | 287 | self.map[f] = ('n', ~umask & 0666, -1, 0) |
@@ -344,6 +386,10 b' class dirstate(object):' | |||
|
344 | 386 | # directly by this function, but might be modified by your statmatch call. |
|
345 | 387 | # |
|
346 | 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 | 393 | # recursion free walker, faster than os.walk. |
|
348 | 394 | def findfiles(s): |
|
349 | 395 | work = [s] |
@@ -352,7 +398,7 b' class dirstate(object):' | |||
|
352 | 398 | names = os.listdir(top) |
|
353 | 399 | names.sort() |
|
354 | 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 | 402 | if nd == '.': |
|
357 | 403 | nd = '' |
|
358 | 404 | else: |
@@ -434,15 +480,16 b' class dirstate(object):' | |||
|
434 | 480 | if not seen(k) and (statmatch(k, None)): |
|
435 | 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 | 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 | 489 | try: |
|
443 | 490 | type_, mode, size, time = self[fn] |
|
444 | 491 | except KeyError: |
|
445 |
if |
|
|
492 | if list_ignored and self.ignore(fn): | |
|
446 | 493 | ignored.append(fn) |
|
447 | 494 | else: |
|
448 | 495 | unknown.append(fn) |
@@ -473,6 +520,8 b' class dirstate(object):' | |||
|
473 | 520 | modified.append(fn) |
|
474 | 521 | elif time != st.st_mtime: |
|
475 | 522 | lookup.append(fn) |
|
523 | elif list_clean: | |
|
524 | clean.append(fn) | |
|
476 | 525 | elif type_ == 'm': |
|
477 | 526 | modified.append(fn) |
|
478 | 527 | elif type_ == 'a': |
@@ -480,4 +529,5 b' class dirstate(object):' | |||
|
480 | 529 | elif type_ == 'r': |
|
481 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -65,6 +65,26 b' class filelog(revlog):' | |||
|
65 | 65 | return (m["copy"], bin(m["copyrev"])) |
|
66 | 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 | 88 | def annotate(self, node): |
|
69 | 89 | |
|
70 | 90 | def decorate(text, rev): |
@@ -76,31 +96,59 b' class filelog(revlog):' | |||
|
76 | 96 | return child |
|
77 | 97 | |
|
78 | 98 | # find all ancestors |
|
79 | needed = {node:1} | |
|
80 |
|
|
|
99 | needed = {(self, node):1} | |
|
100 | files = [self] | |
|
101 | visit = [(self, node)] | |
|
81 | 102 | while visit: |
|
82 | n = visit.pop(0) | |
|
83 |
|
|
|
84 |
|
|
|
85 |
|
|
|
86 | visit.append(p) | |
|
103 | f, n = visit.pop(0) | |
|
104 | rn = f.renamed(n) | |
|
105 | if rn: | |
|
106 | f, n = rn | |
|
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 | 119 | else: |
|
88 | 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 | |
|
92 | visit = [ (self.rev(n), n) for n in needed.keys() ] | |
|
93 | visit.sort() | |
|
123 | # sort by revision (per file) which is a topological order | |
|
124 | visit = [] | |
|
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 | 129 | hist = {} |
|
95 | 130 | |
|
96 |
for |
|
|
97 | curr = decorate(self.read(n), self.linkrev(n)) | |
|
98 | for p in self.parents(n): | |
|
131 | for i in range(len(visit)): | |
|
132 | r, f, n = visit[i] | |
|
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 | 147 | if p != nullid: |
|
100 | 148 | curr = pair(hist[p], curr) |
|
101 | 149 | # trim the history of unneeded revs |
|
102 | needed[p] -= 1 | |
|
103 | if not needed[p]: | |
|
150 | needed[(f, p)] -= 1 | |
|
151 | if not needed[(f, p)]: | |
|
104 | 152 | del hist[p] |
|
105 | 153 | hist[n] = curr |
|
106 | 154 |
@@ -1,6 +1,7 b'' | |||
|
1 | 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 | 6 | # This software may be used and distributed according to the terms |
|
6 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -10,69 +11,56 b' from repo import *' | |||
|
10 | 11 | from demandload import * |
|
11 | 12 | from i18n import gettext as _ |
|
12 | 13 | demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") |
|
13 | demandload(globals(), "errno lock os shutil util") | |
|
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://")) | |
|
14 | demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify") | |
|
30 | 15 | |
|
31 |
def local |
|
|
32 | if path.startswith('file:'): | |
|
33 | path = path[5:] | |
|
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://")) | |
|
16 | def _local(path): | |
|
17 | return (os.path.isfile(path and util.drop_scheme('file', path)) and | |
|
18 | bundlerepo or localrepo) | |
|
48 | 19 | |
|
49 | 20 | schemes = { |
|
50 | 'bundle': bundle, | |
|
51 |
'file': local |
|
|
52 |
'hg': h |
|
|
53 | 'http': lambda ui, path: httprepo.httprepository(ui, path), | |
|
54 | 'https': lambda ui, path: httprepo.httpsrepository(ui, path), | |
|
55 |
'old-http': |
|
|
56 |
'ssh': ssh |
|
|
57 |
'static-http': static |
|
|
21 | 'bundle': bundlerepo, | |
|
22 | 'file': _local, | |
|
23 | 'hg': httprepo, | |
|
24 | 'http': httprepo, | |
|
25 | 'https': httprepo, | |
|
26 | 'old-http': statichttprepo, | |
|
27 | 'ssh': sshrepo, | |
|
28 | 'static-http': statichttprepo, | |
|
58 | 29 | } |
|
59 | 30 | |
|
60 | def repository(ui, path=None, create=0): | |
|
61 |
scheme = |
|
|
31 | def _lookup(path): | |
|
32 | scheme = 'file' | |
|
62 | 33 | if path: |
|
63 | 34 | c = path.find(':') |
|
64 | 35 | if c > 0: |
|
65 |
scheme = |
|
|
66 | else: | |
|
67 | path = '' | |
|
68 | ctor = scheme or schemes['file'] | |
|
69 | if create: | |
|
36 | scheme = path[:c] | |
|
37 | thing = schemes.get(scheme) or schemes['file'] | |
|
38 | try: | |
|
39 | return thing(path) | |
|
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 | 46 | try: |
|
71 | return ctor(ui, path, create) | |
|
72 |
except |
|
|
73 | raise util.Abort(_('cannot create new repository over "%s" protocol') % | |
|
74 | scheme) | |
|
75 | return ctor(ui, path) | |
|
47 | return _lookup(repo).islocal(repo) | |
|
48 | except AttributeError: | |
|
49 | return False | |
|
50 | return repo.local() | |
|
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 | 65 | def clone(ui, source, dest=None, pull=False, rev=None, update=True, |
|
78 | 66 | stream=False): |
@@ -90,7 +78,9 b' def clone(ui, source, dest=None, pull=Fa' | |||
|
90 | 78 | If an exception is raised, the partly cloned/updated destination |
|
91 | 79 | repository will be deleted. |
|
92 | 80 | |
|
93 |
|
|
|
81 | Arguments: | |
|
82 | ||
|
83 | source: repository object or URL | |
|
94 | 84 | |
|
95 | 85 | dest: URL of destination repository to create (defaults to base |
|
96 | 86 | name of source repository) |
@@ -105,8 +95,24 b' def clone(ui, source, dest=None, pull=Fa' | |||
|
105 | 95 | update: update working directory after clone completes, if |
|
106 | 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 | 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 | 117 | if os.path.exists(dest): |
|
112 | 118 | raise util.Abort(_("destination '%s' already exists"), dest) |
@@ -121,8 +127,6 b' def clone(ui, source, dest=None, pull=Fa' | |||
|
121 | 127 | if self.dir_: |
|
122 | 128 | self.rmtree(self.dir_, True) |
|
123 | 129 | |
|
124 | src_repo = repository(ui, source) | |
|
125 | ||
|
126 | 130 | dest_repo = None |
|
127 | 131 | try: |
|
128 | 132 | dest_repo = repository(ui, dest) |
@@ -133,7 +137,7 b' def clone(ui, source, dest=None, pull=Fa' | |||
|
133 | 137 | dest_path = None |
|
134 | 138 | dir_cleanup = None |
|
135 | 139 | if dest_repo.local(): |
|
136 | dest_path = os.path.realpath(dest) | |
|
140 | dest_path = os.path.realpath(dest_repo.root) | |
|
137 | 141 | dir_cleanup = DirCleanup(dest_path) |
|
138 | 142 | |
|
139 | 143 | abspath = source |
@@ -202,8 +206,31 b' def clone(ui, source, dest=None, pull=Fa' | |||
|
202 | 206 | dest_lock.release() |
|
203 | 207 | |
|
204 | 208 | if update: |
|
205 |
|
|
|
209 | _merge.update(dest_repo, dest_repo.changelog.tip()) | |
|
206 | 210 | if dir_cleanup: |
|
207 | 211 | dir_cleanup.close() |
|
208 | 212 | |
|
209 | 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 | 1 | # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod |
|
2 | 2 | # |
|
3 | 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 | 6 | # This software may be used and distributed according to the terms |
|
7 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | # hgweb/hgweb_mod.py - Web interface for a repository. |
|
2 | 2 | # |
|
3 | 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 | 6 | # This software may be used and distributed according to the terms |
|
7 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -11,7 +11,7 b' import os.path' | |||
|
11 | 11 | import mimetypes |
|
12 | 12 | from mercurial.demandload import demandload |
|
13 | 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 | 15 | demandload(globals(), "mercurial:templater") |
|
16 | 16 | demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") |
|
17 | 17 | from mercurial.node import * |
@@ -37,6 +37,7 b' class hgweb(object):' | |||
|
37 | 37 | self.mtime = -1 |
|
38 | 38 | self.reponame = name |
|
39 | 39 | self.archives = 'zip', 'gz', 'bz2' |
|
40 | self.stripecount = 1 | |
|
40 | 41 | self.templatepath = self.repo.ui.config("web", "templates", |
|
41 | 42 | templater.templatepath()) |
|
42 | 43 | |
@@ -46,6 +47,8 b' class hgweb(object):' | |||
|
46 | 47 | self.mtime = mtime |
|
47 | 48 | self.repo = hg.repository(self.repo.ui, self.repo.root) |
|
48 | 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 | 52 | self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) |
|
50 | 53 | self.allowpull = self.repo.ui.configbool("web", "allowpull", True) |
|
51 | 54 | |
@@ -126,39 +129,29 b' class hgweb(object):' | |||
|
126 | 129 | date1 = util.datestr(change1[2]) |
|
127 | 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 | 133 | if files: |
|
131 | 134 | modified, added, removed = map(lambda x: filterfiles(files, x), |
|
132 | 135 | (modified, added, removed)) |
|
133 | 136 | |
|
134 |
diffopts = self.repo.ui |
|
|
135 | showfunc = diffopts['showfunc'] | |
|
136 | ignorews = diffopts['ignorews'] | |
|
137 | ignorewsamount = diffopts['ignorewsamount'] | |
|
138 | ignoreblanklines = diffopts['ignoreblanklines'] | |
|
137 | diffopts = patch.diffopts(self.repo.ui) | |
|
139 | 138 | for f in modified: |
|
140 | 139 | to = r.file(f).read(mmap1[f]) |
|
141 | 140 | tn = r.file(f).read(mmap2[f]) |
|
142 | 141 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
143 | showfunc=showfunc, ignorews=ignorews, | |
|
144 | ignorewsamount=ignorewsamount, | |
|
145 | ignoreblanklines=ignoreblanklines), f, tn) | |
|
142 | opts=diffopts), f, tn) | |
|
146 | 143 | for f in added: |
|
147 | 144 | to = None |
|
148 | 145 | tn = r.file(f).read(mmap2[f]) |
|
149 | 146 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
150 | showfunc=showfunc, ignorews=ignorews, | |
|
151 | ignorewsamount=ignorewsamount, | |
|
152 | ignoreblanklines=ignoreblanklines), f, tn) | |
|
147 | opts=diffopts), f, tn) | |
|
153 | 148 | for f in removed: |
|
154 | 149 | to = r.file(f).read(mmap1[f]) |
|
155 | 150 | tn = None |
|
156 | 151 | yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
|
157 | showfunc=showfunc, ignorews=ignorews, | |
|
158 | ignorewsamount=ignorewsamount, | |
|
159 | ignoreblanklines=ignoreblanklines), f, tn) | |
|
152 | opts=diffopts), f, tn) | |
|
160 | 153 | |
|
161 | def changelog(self, pos): | |
|
154 | def changelog(self, pos, shortlog=False): | |
|
162 | 155 | def changenav(**map): |
|
163 | 156 | def seq(factor, maxchanges=None): |
|
164 | 157 | if maxchanges: |
@@ -173,8 +166,9 b' class hgweb(object):' | |||
|
173 | 166 | |
|
174 | 167 | l = [] |
|
175 | 168 | last = 0 |
|
176 | for f in seq(1, self.maxchanges): | |
|
177 |
|
|
|
169 | maxchanges = shortlog and self.maxshortchanges or self.maxchanges | |
|
170 | for f in seq(1, maxchanges): | |
|
171 | if f < maxchanges or f <= last: | |
|
178 | 172 | continue |
|
179 | 173 | if f > count: |
|
180 | 174 | break |
@@ -219,14 +213,15 b' class hgweb(object):' | |||
|
219 | 213 | for e in l: |
|
220 | 214 | yield e |
|
221 | 215 | |
|
216 | maxchanges = shortlog and self.maxshortchanges or self.maxchanges | |
|
222 | 217 | cl = self.repo.changelog |
|
223 | 218 | mf = cl.read(cl.tip())[0] |
|
224 | 219 | count = cl.count() |
|
225 |
start = max(0, pos - |
|
|
226 |
end = min(count, start + |
|
|
220 | start = max(0, pos - maxchanges + 1) | |
|
221 | end = min(count, start + maxchanges) | |
|
227 | 222 | pos = end - 1 |
|
228 | 223 | |
|
229 | yield self.t('changelog', | |
|
224 | yield self.t(shortlog and 'shortlog' or 'changelog', | |
|
230 | 225 | changenav=changenav, |
|
231 | 226 | manifest=hex(mf), |
|
232 | 227 | rev=pos, changesets=count, entries=changelist, |
@@ -265,7 +260,7 b' class hgweb(object):' | |||
|
265 | 260 | hn = hex(n) |
|
266 | 261 | |
|
267 | 262 | yield self.t('searchentry', |
|
268 |
parity=count |
|
|
263 | parity=self.stripes(count), | |
|
269 | 264 | author=changes[1], |
|
270 | 265 | parent=self.siblings(cl.parents(n), cl.rev), |
|
271 | 266 | child=self.siblings(cl.children(n), cl.rev), |
@@ -376,7 +371,7 b' class hgweb(object):' | |||
|
376 | 371 | for l, t in enumerate(text.splitlines(1)): |
|
377 | 372 | yield {"line": t, |
|
378 | 373 | "linenumber": "% 6d" % (l + 1), |
|
379 |
"parity": l |
|
|
374 | "parity": self.stripes(l)} | |
|
380 | 375 | |
|
381 | 376 | yield self.t("filerevision", |
|
382 | 377 | file=f, |
@@ -393,7 +388,7 b' class hgweb(object):' | |||
|
393 | 388 | parent=self.siblings(fl.parents(n), fl.rev, file=f), |
|
394 | 389 | child=self.siblings(fl.children(n), fl.rev, file=f), |
|
395 | 390 | rename=self.renamelink(fl, n), |
|
396 |
permissions=self.repo.manifest.read |
|
|
391 | permissions=self.repo.manifest.read(mfn).execf(f)) | |
|
397 | 392 | |
|
398 | 393 | def fileannotate(self, f, node): |
|
399 | 394 | bcache = {} |
@@ -409,7 +404,7 b' class hgweb(object):' | |||
|
409 | 404 | mfn = cs[0] |
|
410 | 405 | |
|
411 | 406 | def annotate(**map): |
|
412 |
parity = |
|
|
407 | parity = 0 | |
|
413 | 408 | last = None |
|
414 | 409 | for r, l in fl.annotate(n): |
|
415 | 410 | try: |
@@ -447,7 +442,7 b' class hgweb(object):' | |||
|
447 | 442 | rename=self.renamelink(fl, n), |
|
448 | 443 | parent=self.siblings(fl.parents(n), fl.rev, file=f), |
|
449 | 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 | 447 | def manifest(self, mnode, path): |
|
453 | 448 | man = self.repo.manifest |
@@ -457,7 +452,6 b' class hgweb(object):' | |||
|
457 | 452 | rev = man.rev(mn) |
|
458 | 453 | changerev = man.linkrev(mn) |
|
459 | 454 | node = self.repo.changelog.node(changerev) |
|
460 | mff = man.readflags(mn) | |
|
461 | 455 | |
|
462 | 456 | files = {} |
|
463 | 457 | |
@@ -489,10 +483,10 b' class hgweb(object):' | |||
|
489 | 483 | yield {"file": full, |
|
490 | 484 | "manifest": mnode, |
|
491 | 485 | "filenode": hex(fnode), |
|
492 | "parity": parity, | |
|
486 | "parity": self.stripes(parity), | |
|
493 | 487 | "basename": f, |
|
494 |
"permissions": mf |
|
|
495 |
parity = 1 |
|
|
488 | "permissions": mf.execf(full)} | |
|
489 | parity += 1 | |
|
496 | 490 | |
|
497 | 491 | def dirlist(**map): |
|
498 | 492 | parity = 0 |
@@ -503,11 +497,11 b' class hgweb(object):' | |||
|
503 | 497 | if fnode: |
|
504 | 498 | continue |
|
505 | 499 | |
|
506 | yield {"parity": parity, | |
|
500 | yield {"parity": self.stripes(parity), | |
|
507 | 501 | "path": os.path.join(path, f), |
|
508 | 502 | "manifest": mnode, |
|
509 | 503 | "basename": f[:-1]} |
|
510 |
parity = 1 |
|
|
504 | parity += 1 | |
|
511 | 505 | |
|
512 | 506 | yield self.t("manifest", |
|
513 | 507 | manifest=mnode, |
@@ -530,12 +524,12 b' class hgweb(object):' | |||
|
530 | 524 | parity = 0 |
|
531 | 525 | for k,n in i: |
|
532 | 526 | if notip and k == "tip": continue |
|
533 | yield {"parity": parity, | |
|
527 | yield {"parity": self.stripes(parity), | |
|
534 | 528 | "tag": k, |
|
535 | 529 | "tagmanifest": hex(cl.read(n)[0]), |
|
536 | 530 | "date": cl.read(n)[2], |
|
537 | 531 | "node": hex(n)} |
|
538 |
parity = 1 |
|
|
532 | parity += 1 | |
|
539 | 533 | |
|
540 | 534 | yield self.t("tags", |
|
541 | 535 | manifest=hex(mf), |
@@ -565,12 +559,12 b' class hgweb(object):' | |||
|
565 | 559 | t = c[2] |
|
566 | 560 | |
|
567 | 561 | yield self.t("tagentry", |
|
568 | parity = parity, | |
|
562 | parity = self.stripes(parity), | |
|
569 | 563 | tag = k, |
|
570 | 564 | node = hex(n), |
|
571 | 565 | date = t, |
|
572 | 566 | tagmanifest = hex(m)) |
|
573 |
parity = 1 |
|
|
567 | parity += 1 | |
|
574 | 568 | |
|
575 | 569 | def changelist(**map): |
|
576 | 570 | parity = 0 |
@@ -609,7 +603,8 b' class hgweb(object):' | |||
|
609 | 603 | lastchange = (0, 0), # FIXME |
|
610 | 604 | manifest = hex(mf), |
|
611 | 605 | tags = tagentries, |
|
612 |
shortlog = changelist |
|
|
606 | shortlog = changelist, | |
|
607 | archives=self.archivelist("tip")) | |
|
613 | 608 | |
|
614 | 609 | def filediff(self, file, changeset): |
|
615 | 610 | cl = self.repo.changelog |
@@ -689,6 +684,7 b' class hgweb(object):' | |||
|
689 | 684 | def expand_form(form): |
|
690 | 685 | shortcuts = { |
|
691 | 686 | 'cl': [('cmd', ['changelog']), ('rev', None)], |
|
687 | 'sl': [('cmd', ['shortlog']), ('rev', None)], | |
|
692 | 688 | 'cs': [('cmd', ['changeset']), ('node', None)], |
|
693 | 689 | 'f': [('cmd', ['file']), ('filenode', None)], |
|
694 | 690 | 'fl': [('cmd', ['filelog']), ('filenode', None)], |
@@ -752,6 +748,13 b' class hgweb(object):' | |||
|
752 | 748 | else: |
|
753 | 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 | 758 | def do_changelog(self, req): |
|
756 | 759 | hi = self.repo.changelog.count() - 1 |
|
757 | 760 | if req.form.has_key('rev'): |
@@ -764,6 +767,18 b' class hgweb(object):' | |||
|
764 | 767 | |
|
765 | 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 | 782 | def do_changeset(self, req): |
|
768 | 783 | req.write(self.changeset(req.form['node'][0])) |
|
769 | 784 | |
@@ -895,9 +910,13 b' class hgweb(object):' | |||
|
895 | 910 | # require ssl by default, auth info cannot be sniffed and |
|
896 | 911 | # replayed |
|
897 | 912 | ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) |
|
898 | if ssl_req and not req.env.get('HTTPS'): | |
|
899 | bail(_('ssl required\n')) | |
|
900 | return | |
|
913 | if ssl_req: | |
|
914 | if not req.env.get('HTTPS'): | |
|
915 | bail(_('ssl required\n')) | |
|
916 | return | |
|
917 | proto = 'https' | |
|
918 | else: | |
|
919 | proto = 'http' | |
|
901 | 920 | |
|
902 | 921 | # do not allow push unless explicitly allowed |
|
903 | 922 | if not self.check_perm(req, 'push', False): |
@@ -943,7 +962,9 b' class hgweb(object):' | |||
|
943 | 962 | sys.stdout = cStringIO.StringIO() |
|
944 | 963 | |
|
945 | 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 | 968 | finally: |
|
948 | 969 | val = sys.stdout.getvalue() |
|
949 | 970 | sys.stdout = old_stdout |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories. |
|
2 | 2 | # |
|
3 | 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 | 6 | # This software may be used and distributed according to the terms |
|
7 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | # hgweb/request.py - An http request from either CGI or the standalone server. |
|
2 | 2 | # |
|
3 | 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 | 6 | # This software may be used and distributed according to the terms |
|
7 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | # hgweb/server.py - The standalone hg web server. |
|
2 | 2 | # |
|
3 | 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 | 6 | # This software may be used and distributed according to the terms |
|
7 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -198,6 +198,7 b' def create_server(ui, repo):' | |||
|
198 | 198 | self.webdirmaker = hgwebdir |
|
199 | 199 | self.repoviewmaker = hgweb |
|
200 | 200 | self.reqmaker = wsgiapplication(self.make_handler) |
|
201 | self.daemon_threads = True | |
|
201 | 202 | |
|
202 | 203 | def make_handler(self): |
|
203 | 204 | if self.webdir_conf: |
@@ -1,6 +1,6 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,7 b'' | |||
|
1 | 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 | 6 | # This software may be used and distributed according to the terms |
|
6 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -115,6 +116,7 b' else:' | |||
|
115 | 116 | |
|
116 | 117 | class httprepository(remoterepository): |
|
117 | 118 | def __init__(self, ui, path): |
|
119 | self.path = path | |
|
118 | 120 | self.caps = None |
|
119 | 121 | scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) |
|
120 | 122 | if query or frag: |
@@ -124,8 +126,8 b' class httprepository(remoterepository):' | |||
|
124 | 126 | host, port, user, passwd = netlocsplit(netloc) |
|
125 | 127 | |
|
126 | 128 | # urllib cannot handle URLs with embedded user or passwd |
|
127 | self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), | |
|
128 | urlpath, '', '')) | |
|
129 | self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), | |
|
130 | urlpath, '', '')) | |
|
129 | 131 | self.ui = ui |
|
130 | 132 | |
|
131 | 133 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') |
@@ -189,6 +191,9 b' class httprepository(remoterepository):' | |||
|
189 | 191 | opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] |
|
190 | 192 | urllib2.install_opener(opener) |
|
191 | 193 | |
|
194 | def url(self): | |
|
195 | return self.path | |
|
196 | ||
|
192 | 197 | # look up capabilities only when needed |
|
193 | 198 | |
|
194 | 199 | def get_caps(self): |
@@ -213,7 +218,7 b' class httprepository(remoterepository):' | |||
|
213 | 218 | q = {"cmd": cmd} |
|
214 | 219 | q.update(args) |
|
215 | 220 | qs = urllib.urlencode(q) |
|
216 | cu = "%s?%s" % (self.url, qs) | |
|
221 | cu = "%s?%s" % (self._url, qs) | |
|
217 | 222 | try: |
|
218 | 223 | resp = urllib2.urlopen(urllib2.Request(cu, data, headers)) |
|
219 | 224 | except urllib2.HTTPError, inst: |
@@ -234,13 +239,13 b' class httprepository(remoterepository):' | |||
|
234 | 239 | not proto.startswith('text/plain') and \ |
|
235 | 240 | not proto.startswith('application/hg-changegroup'): |
|
236 | 241 | raise hg.RepoError(_("'%s' does not appear to be an hg repository") % |
|
237 | self.url) | |
|
242 | self._url) | |
|
238 | 243 | |
|
239 | 244 | if proto.startswith('application/mercurial'): |
|
240 | 245 | version = proto[22:] |
|
241 | 246 | if float(version) > 0.1: |
|
242 | 247 | raise hg.RepoError(_("'%s' uses newer protocol %s") % |
|
243 | (self.url, version)) | |
|
248 | (self._url, version)) | |
|
244 | 249 | |
|
245 | 250 | return resp |
|
246 | 251 | |
@@ -335,3 +340,13 b' class httpsrepository(httprepository):' | |||
|
335 | 340 | raise util.Abort(_('Python support for SSL and HTTPS ' |
|
336 | 341 | 'is not installed')) |
|
337 | 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 | 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 | 6 | This software may be used and distributed according to the terms |
|
7 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -83,6 +83,9 b' class localrepository(repo.repository):' | |||
|
83 | 83 | |
|
84 | 84 | self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) |
|
85 | 85 | |
|
86 | def url(self): | |
|
87 | return 'file:' + self.root | |
|
88 | ||
|
86 | 89 | def hook(self, name, throw=False, **args): |
|
87 | 90 | def callhook(hname, funcname): |
|
88 | 91 | '''call python hook. hook is callable object, looked up as |
@@ -195,7 +198,7 b' class localrepository(repo.repository):' | |||
|
195 | 198 | self.hook('tag', node=node, tag=name, local=local) |
|
196 | 199 | return |
|
197 | 200 | |
|
198 |
for x in self. |
|
|
201 | for x in self.status()[:5]: | |
|
199 | 202 | if '.hgtags' in x: |
|
200 | 203 | raise util.Abort(_('working copy of .hgtags is changed ' |
|
201 | 204 | '(please commit .hgtags manually)')) |
@@ -289,6 +292,10 b' class localrepository(repo.repository):' | |||
|
289 | 292 | try: |
|
290 | 293 | return self.tags()[key] |
|
291 | 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 | 299 | try: |
|
293 | 300 | return self.changelog.lookup(key) |
|
294 | 301 | except: |
@@ -463,8 +470,7 b' class localrepository(repo.repository):' | |||
|
463 | 470 | p2 = p2 or self.dirstate.parents()[1] or nullid |
|
464 | 471 | c1 = self.changelog.read(p1) |
|
465 | 472 | c2 = self.changelog.read(p2) |
|
466 | m1 = self.manifest.read(c1[0]) | |
|
467 | mf1 = self.manifest.readflags(c1[0]) | |
|
473 | m1 = self.manifest.read(c1[0]).copy() | |
|
468 | 474 | m2 = self.manifest.read(c2[0]) |
|
469 | 475 | changed = [] |
|
470 | 476 | |
@@ -477,36 +483,32 b' class localrepository(repo.repository):' | |||
|
477 | 483 | wlock = self.wlock() |
|
478 | 484 | l = self.lock() |
|
479 | 485 | tr = self.transaction() |
|
480 | mm = m1.copy() | |
|
481 | mfm = mf1.copy() | |
|
482 | 486 | linkrev = self.changelog.count() |
|
483 | 487 | for f in files: |
|
484 | 488 | try: |
|
485 | 489 | t = self.wread(f) |
|
486 |
|
|
|
490 | m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f))) | |
|
487 | 491 | r = self.file(f) |
|
488 | mfm[f] = tm | |
|
489 | 492 | |
|
490 | 493 | (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) |
|
491 | 494 | if entry: |
|
492 |
m |
|
|
495 | m1[f] = entry | |
|
493 | 496 | continue |
|
494 | 497 | |
|
495 |
m |
|
|
498 | m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2) | |
|
496 | 499 | changed.append(f) |
|
497 | 500 | if update_dirstate: |
|
498 | 501 | self.dirstate.update([f], "n") |
|
499 | 502 | except IOError: |
|
500 | 503 | try: |
|
501 |
del m |
|
|
502 | del mfm[f] | |
|
504 | del m1[f] | |
|
503 | 505 | if update_dirstate: |
|
504 | 506 | self.dirstate.forget([f]) |
|
505 | 507 | except: |
|
506 | 508 | # deleted from p2? |
|
507 | 509 | pass |
|
508 | 510 | |
|
509 |
mnode = self.manifest.add(m |
|
|
511 | mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0]) | |
|
510 | 512 | user = user or self.ui.username() |
|
511 | 513 | n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date) |
|
512 | 514 | tr.close() |
@@ -530,15 +532,14 b' class localrepository(repo.repository):' | |||
|
530 | 532 | else: |
|
531 | 533 | self.ui.warn(_("%s not tracked!\n") % f) |
|
532 | 534 | else: |
|
533 |
modified, added, removed, deleted, unknown = self. |
|
|
535 | modified, added, removed, deleted, unknown = self.status(match=match)[:5] | |
|
534 | 536 | commit = modified + added |
|
535 | 537 | remove = removed |
|
536 | 538 | |
|
537 | 539 | p1, p2 = self.dirstate.parents() |
|
538 | 540 | c1 = self.changelog.read(p1) |
|
539 | 541 | c2 = self.changelog.read(p2) |
|
540 | m1 = self.manifest.read(c1[0]) | |
|
541 | mf1 = self.manifest.readflags(c1[0]) | |
|
542 | m1 = self.manifest.read(c1[0]).copy() | |
|
542 | 543 | m2 = self.manifest.read(c2[0]) |
|
543 | 544 | |
|
544 | 545 | if not commit and not remove and not force and p2 == nullid: |
@@ -564,7 +565,7 b' class localrepository(repo.repository):' | |||
|
564 | 565 | for f in commit: |
|
565 | 566 | self.ui.note(f + "\n") |
|
566 | 567 | try: |
|
567 |
m |
|
|
568 | m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f))) | |
|
568 | 569 | t = self.wread(f) |
|
569 | 570 | except IOError: |
|
570 | 571 | self.ui.warn(_("trouble committing %s!\n") % f) |
@@ -591,12 +592,11 b' class localrepository(repo.repository):' | |||
|
591 | 592 | changed.append(f) |
|
592 | 593 | |
|
593 | 594 | # update manifest |
|
594 | m1 = m1.copy() | |
|
595 | 595 | m1.update(new) |
|
596 | 596 | for f in remove: |
|
597 | 597 | if f in m1: |
|
598 | 598 | del m1[f] |
|
599 |
mn = self.manifest.add(m1 |
|
|
599 | mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], | |
|
600 | 600 | (new, remove)) |
|
601 | 601 | |
|
602 | 602 | # add changeset |
@@ -658,9 +658,9 b' class localrepository(repo.repository):' | |||
|
658 | 658 | for src, fn in self.dirstate.walk(files, match, badmatch=badmatch): |
|
659 | 659 | yield src, fn |
|
660 | 660 | |
|
661 |
def |
|
|
662 |
wlock=None, |
|
|
663 |
"""return |
|
|
661 | def status(self, node1=None, node2=None, files=[], match=util.always, | |
|
662 | wlock=None, list_ignored=False, list_clean=False): | |
|
663 | """return status of files between two nodes or node and working directory | |
|
664 | 664 | |
|
665 | 665 | If node1 is None, use the first dirstate parent instead. |
|
666 | 666 | If node2 is None, compare node1 with working directory. |
@@ -668,8 +668,7 b' class localrepository(repo.repository):' | |||
|
668 | 668 | |
|
669 | 669 | def fcmp(fn, mf): |
|
670 | 670 | t1 = self.wread(fn) |
|
671 |
|
|
|
672 | return cmp(t1, t2) | |
|
671 | return self.file(fn).cmp(mf.get(fn, nullid), t1) | |
|
673 | 672 | |
|
674 | 673 | def mfmatches(node): |
|
675 | 674 | change = self.changelog.read(node) |
@@ -679,7 +678,9 b' class localrepository(repo.repository):' | |||
|
679 | 678 | del mf[fn] |
|
680 | 679 | return mf |
|
681 | 680 | |
|
682 |
modified, added, removed, deleted, unknown |
|
|
681 | modified, added, removed, deleted, unknown = [], [], [], [], [] | |
|
682 | ignored, clean = [], [] | |
|
683 | ||
|
683 | 684 | compareworking = False |
|
684 | 685 | if not node1 or (not node2 and node1 == self.dirstate.parents()[0]): |
|
685 | 686 | compareworking = True |
@@ -697,8 +698,9 b' class localrepository(repo.repository):' | |||
|
697 | 698 | wlock = self.wlock(wait=0) |
|
698 | 699 | except lock.LockException: |
|
699 | 700 | wlock = None |
|
700 |
lookup, modified, added, removed, deleted, unknown, |
|
|
701 |
self.dirstate. |
|
|
701 | (lookup, modified, added, removed, deleted, unknown, | |
|
702 | ignored, clean) = self.dirstate.status(files, match, | |
|
703 | list_ignored, list_clean) | |
|
702 | 704 | |
|
703 | 705 | # are we comparing working dir against its parent? |
|
704 | 706 | if compareworking: |
@@ -721,12 +723,11 b' class localrepository(repo.repository):' | |||
|
721 | 723 | del mf2[f] |
|
722 | 724 | else: |
|
723 | 725 | # we are comparing two revisions |
|
724 | deleted, unknown, ignored = [], [], [] | |
|
725 | 726 | mf2 = mfmatches(node2) |
|
726 | 727 | |
|
727 | 728 | if not compareworking: |
|
728 | 729 | # flush lists from dirstate before comparing manifests |
|
729 | modified, added = [], [] | |
|
730 | modified, added, clean = [], [], [] | |
|
730 | 731 | |
|
731 | 732 | # make sure to sort the files so we talk to the disk in a |
|
732 | 733 | # reasonable order |
@@ -736,6 +737,8 b' class localrepository(repo.repository):' | |||
|
736 | 737 | if mf1.has_key(fn): |
|
737 | 738 | if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)): |
|
738 | 739 | modified.append(fn) |
|
740 | elif list_clean: | |
|
741 | clean.append(fn) | |
|
739 | 742 | del mf1[fn] |
|
740 | 743 | else: |
|
741 | 744 | added.append(fn) |
@@ -743,12 +746,9 b' class localrepository(repo.repository):' | |||
|
743 | 746 | removed = mf1.keys() |
|
744 | 747 | |
|
745 | 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 | 750 | l.sort() |
|
748 | if show_ignored is None: | |
|
749 | return (modified, added, removed, deleted, unknown) | |
|
750 | else: | |
|
751 | return (modified, added, removed, deleted, unknown, ignored) | |
|
751 | return (modified, added, removed, deleted, unknown, ignored, clean) | |
|
752 | 752 | |
|
753 | 753 | def add(self, list, wlock=None): |
|
754 | 754 | if not wlock: |
@@ -798,7 +798,6 b' class localrepository(repo.repository):' | |||
|
798 | 798 | def undelete(self, list, wlock=None): |
|
799 | 799 | p = self.dirstate.parents()[0] |
|
800 | 800 | mn = self.changelog.read(p)[0] |
|
801 | mf = self.manifest.readflags(mn) | |
|
802 | 801 | m = self.manifest.read(mn) |
|
803 | 802 | if not wlock: |
|
804 | 803 | wlock = self.wlock() |
@@ -808,7 +807,7 b' class localrepository(repo.repository):' | |||
|
808 | 807 | else: |
|
809 | 808 | t = self.file(f).read(m[f]) |
|
810 | 809 | self.wwrite(f, t) |
|
811 |
util.set_exec(self.wjoin(f), m |
|
|
810 | util.set_exec(self.wjoin(f), m.execf(f)) | |
|
812 | 811 | self.dirstate.update([f], "n") |
|
813 | 812 | |
|
814 | 813 | def copy(self, source, dest, wlock=None): |
@@ -1159,22 +1158,29 b' class localrepository(repo.repository):' | |||
|
1159 | 1158 | else: |
|
1160 | 1159 | return subset |
|
1161 | 1160 | |
|
1162 | def pull(self, remote, heads=None, force=False): | |
|
1163 | l = self.lock() | |
|
1161 | def pull(self, remote, heads=None, force=False, lock=None): | |
|
1162 | mylock = False | |
|
1163 | if not lock: | |
|
1164 | lock = self.lock() | |
|
1165 | mylock = True | |
|
1164 | 1166 | |
|
1165 | fetch = self.findincoming(remote, force=force) | |
|
1166 | if fetch == [nullid]: | |
|
1167 | self.ui.status(_("requesting all changes\n")) | |
|
1167 | try: | |
|
1168 | fetch = self.findincoming(remote, force=force) | |
|
1169 | if fetch == [nullid]: | |
|
1170 | self.ui.status(_("requesting all changes\n")) | |
|
1168 | 1171 | |
|
1169 | if not fetch: | |
|
1170 | self.ui.status(_("no changes found\n")) | |
|
1171 | return 0 | |
|
1172 | if not fetch: | |
|
1173 | self.ui.status(_("no changes found\n")) | |
|
1174 | return 0 | |
|
1172 | 1175 | |
|
1173 | if heads is None: | |
|
1174 | cg = remote.changegroup(fetch, 'pull') | |
|
1175 | else: | |
|
1176 | cg = remote.changegroupsubset(fetch, heads, 'pull') | |
|
1177 | return self.addchangegroup(cg, 'pull') | |
|
1176 | if heads is None: | |
|
1177 | cg = remote.changegroup(fetch, 'pull') | |
|
1178 | else: | |
|
1179 | cg = remote.changegroupsubset(fetch, heads, 'pull') | |
|
1180 | return self.addchangegroup(cg, 'pull', remote.url()) | |
|
1181 | finally: | |
|
1182 | if mylock: | |
|
1183 | lock.release() | |
|
1178 | 1184 | |
|
1179 | 1185 | def push(self, remote, force=False, revs=None): |
|
1180 | 1186 | # there are two ways to push to remote repo: |
@@ -1230,7 +1236,7 b' class localrepository(repo.repository):' | |||
|
1230 | 1236 | ret = self.prepush(remote, force, revs) |
|
1231 | 1237 | if ret[0] is not None: |
|
1232 | 1238 | cg, remote_heads = ret |
|
1233 | return remote.addchangegroup(cg, 'push') | |
|
1239 | return remote.addchangegroup(cg, 'push', self.url()) | |
|
1234 | 1240 | return ret[1] |
|
1235 | 1241 | |
|
1236 | 1242 | def push_unbundle(self, remote, force, revs): |
@@ -1583,7 +1589,7 b' class localrepository(repo.repository):' | |||
|
1583 | 1589 | |
|
1584 | 1590 | return util.chunkbuffer(gengroup()) |
|
1585 | 1591 | |
|
1586 | def addchangegroup(self, source, srctype): | |
|
1592 | def addchangegroup(self, source, srctype, url): | |
|
1587 | 1593 | """add changegroup to repo. |
|
1588 | 1594 | returns number of heads modified or added + 1.""" |
|
1589 | 1595 | |
@@ -1597,7 +1603,7 b' class localrepository(repo.repository):' | |||
|
1597 | 1603 | if not source: |
|
1598 | 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 | 1608 | changesets = files = revisions = 0 |
|
1603 | 1609 | |
@@ -1664,544 +1670,21 b' class localrepository(repo.repository):' | |||
|
1664 | 1670 | |
|
1665 | 1671 | if changesets > 0: |
|
1666 | 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 | 1676 | tr.close() |
|
1670 | 1677 | |
|
1671 | 1678 | if changesets > 0: |
|
1672 | 1679 | self.hook("changegroup", node=hex(self.changelog.node(cor+1)), |
|
1673 | source=srctype) | |
|
1680 | source=srctype, url=url) | |
|
1674 | 1681 | |
|
1675 | 1682 | for i in range(cor + 1, cnr + 1): |
|
1676 | 1683 | self.hook("incoming", node=hex(self.changelog.node(i)), |
|
1677 | source=srctype) | |
|
1684 | source=srctype, url=url) | |
|
1678 | 1685 | |
|
1679 | 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 | 1689 | def stream_in(self, remote): |
|
2207 | 1690 | fp = remote.stream_out() |
@@ -2227,7 +1710,7 b' class localrepository(repo.repository):' | |||
|
2227 | 1710 | util.bytecount(total_bytes / elapsed))) |
|
2228 | 1711 | self.reload() |
|
2229 | 1712 | return len(self.heads()) + 1 |
|
2230 | ||
|
1713 | ||
|
2231 | 1714 | def clone(self, remote, heads=[], stream=False): |
|
2232 | 1715 | '''clone remote repository. |
|
2233 | 1716 | |
@@ -2256,3 +1739,8 b' def aftertrans(base):' | |||
|
2256 | 1739 | os.path.join(p, "undo.dirstate")) |
|
2257 | 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 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,6 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -10,6 +10,31 b' from i18n import gettext as _' | |||
|
10 | 10 | from demandload import * |
|
11 | 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 | 38 | class manifest(revlog): |
|
14 | 39 | def __init__(self, opener, defversion=REVLOGV0): |
|
15 | 40 | self.mapcache = None |
@@ -18,26 +43,18 b' class manifest(revlog):' | |||
|
18 | 43 | defversion) |
|
19 | 44 | |
|
20 | 45 | def read(self, node): |
|
21 |
if node == nullid: return |
|
|
46 | if node == nullid: return manifestdict() # don't upset local cache | |
|
22 | 47 | if self.mapcache and self.mapcache[0] == node: |
|
23 | 48 | return self.mapcache[1] |
|
24 | 49 | text = self.revision(node) |
|
25 | map = {} | |
|
26 | flag = {} | |
|
27 | 50 | self.listcache = array.array('c', text) |
|
28 | 51 | lines = text.splitlines(1) |
|
52 | mapping = manifestdict() | |
|
29 | 53 | for l in lines: |
|
30 | 54 | (f, n) = l.split('\0') |
|
31 |
map |
|
|
32 | flag[f] = (n[40:-1] == "x") | |
|
33 | self.mapcache = (node, map, flag) | |
|
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] | |
|
55 | mapping.rawset(f, n) | |
|
56 | self.mapcache = (node, mapping) | |
|
57 | return mapping | |
|
41 | 58 | |
|
42 | 59 | def diff(self, a, b): |
|
43 | 60 | return mdiff.textdiff(str(a), str(b)) |
@@ -86,7 +103,7 b' class manifest(revlog):' | |||
|
86 | 103 | '''look up entry for a single file efficiently. |
|
87 | 104 | return (node, flag) pair if found, (None, None) if not.''' |
|
88 | 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 | 107 | text = self.revision(node) |
|
91 | 108 | start, end = self._search(text, f) |
|
92 | 109 | if start == end: |
@@ -95,7 +112,7 b' class manifest(revlog):' | |||
|
95 | 112 | f, n = l.split('\0') |
|
96 | 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 | 116 | changed=None): |
|
100 | 117 | # apply the changes collected during the bisect loop to our addlist |
|
101 | 118 | # return a delta suitable for addrevision |
@@ -123,9 +140,7 b' class manifest(revlog):' | |||
|
123 | 140 | |
|
124 | 141 | # if this is changed to support newlines in filenames, |
|
125 | 142 | # be sure to check the templates/ dir again (especially *-raw.tmpl) |
|
126 | text = ["%s\000%s%s\n" % | |
|
127 | (f, hex(map[f]), flags[f] and "x" or '') | |
|
128 | for f in files] | |
|
143 | text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files] | |
|
129 | 144 | self.listcache = array.array('c', "".join(text)) |
|
130 | 145 | cachedelta = None |
|
131 | 146 | else: |
@@ -151,8 +166,7 b' class manifest(revlog):' | |||
|
151 | 166 | # bs will either be the index of the item or the insert point |
|
152 | 167 | start, end = self._search(addbuf, f, start) |
|
153 | 168 | if w[1] == 0: |
|
154 | l = "%s\000%s%s\n" % (f, hex(map[f]), | |
|
155 | flags[f] and "x" or '') | |
|
169 | l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) | |
|
156 | 170 | else: |
|
157 | 171 | l = "" |
|
158 | 172 | if start == end and w[1] == 1: |
@@ -183,6 +197,6 b' class manifest(revlog):' | |||
|
183 | 197 | |
|
184 | 198 | n = self.addrevision(buffer(self.listcache), transaction, link, p1, \ |
|
185 | 199 | p2, cachedelta) |
|
186 |
self.mapcache = (n, map |
|
|
200 | self.mapcache = (n, map) | |
|
187 | 201 | |
|
188 | 202 | return n |
@@ -1,6 +1,6 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -19,14 +19,41 b' def splitnewlines(text):' | |||
|
19 | 19 | lines[-1] = lines[-1][:-1] |
|
20 | 20 | return lines |
|
21 | 21 | |
|
22 | def unidiff(a, ad, b, bd, fn, r=None, text=False, | |
|
23 | showfunc=False, ignorews=False, ignorewsamount=False, | |
|
24 | ignoreblanklines=False): | |
|
22 | class diffopts(object): | |
|
23 | '''context is the number of context lines | |
|
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 | 53 | if not a and not b: return "" |
|
27 | 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 | 57 | l = ['Binary file %s has changed\n' % fn] |
|
31 | 58 | elif not a: |
|
32 | 59 | b = splitnewlines(b) |
@@ -49,10 +76,7 b' def unidiff(a, ad, b, bd, fn, r=None, te' | |||
|
49 | 76 | else: |
|
50 | 77 | al = splitnewlines(a) |
|
51 | 78 | bl = splitnewlines(b) |
|
52 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, | |
|
53 | showfunc=showfunc, ignorews=ignorews, | |
|
54 | ignorewsamount=ignorewsamount, | |
|
55 | ignoreblanklines=ignoreblanklines)) | |
|
79 | l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts)) | |
|
56 | 80 | if not l: return "" |
|
57 | 81 | # difflib uses a space, rather than a tab |
|
58 | 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 | 96 | # t1 and t2 are the text to be diffed |
|
73 | 97 | # l1 and l2 are the text broken up into lines |
|
74 | 98 | # header1 and header2 are the filenames for the diff output |
|
75 | # context is the number of context lines | |
|
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): | |
|
99 | def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts): | |
|
82 | 100 | def contextend(l, len): |
|
83 | ret = l + context | |
|
101 | ret = l + opts.context | |
|
84 | 102 | if ret > len: |
|
85 | 103 | ret = len |
|
86 | 104 | return ret |
|
87 | 105 | |
|
88 | 106 | def contextstart(l): |
|
89 | ret = l - context | |
|
107 | ret = l - opts.context | |
|
90 | 108 | if ret < 0: |
|
91 | 109 | return 0 |
|
92 | 110 | return ret |
@@ -101,7 +119,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||
|
101 | 119 | blen = b2 - bstart + aend - a2 |
|
102 | 120 | |
|
103 | 121 | func = "" |
|
104 | if showfunc: | |
|
122 | if opts.showfunc: | |
|
105 | 123 | # walk backwards from the start of the context |
|
106 | 124 | # to find a line starting with an alphanumeric char. |
|
107 | 125 | for x in xrange(astart, -1, -1): |
@@ -119,14 +137,14 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||
|
119 | 137 | |
|
120 | 138 | header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] |
|
121 | 139 | |
|
122 | if showfunc: | |
|
140 | if opts.showfunc: | |
|
123 | 141 | funcre = re.compile('\w') |
|
124 | if ignorewsamount: | |
|
142 | if opts.ignorewsamount: | |
|
125 | 143 | wsamountre = re.compile('[ \t]+') |
|
126 | 144 | wsappendedre = re.compile(' \n') |
|
127 | if ignoreblanklines: | |
|
145 | if opts.ignoreblanklines: | |
|
128 | 146 | wsblanklinesre = re.compile('\n') |
|
129 | if ignorews: | |
|
147 | if opts.ignorews: | |
|
130 | 148 | wsre = re.compile('[ \t]') |
|
131 | 149 | |
|
132 | 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 | 177 | if not old and not new: |
|
160 | 178 | continue |
|
161 | 179 | |
|
162 | if ignoreblanklines: | |
|
180 | if opts.ignoreblanklines: | |
|
163 | 181 | wsold = wsblanklinesre.sub('', "".join(old)) |
|
164 | 182 | wsnew = wsblanklinesre.sub('', "".join(new)) |
|
165 | 183 | if wsold == wsnew: |
|
166 | 184 | continue |
|
167 | 185 | |
|
168 | if ignorewsamount: | |
|
186 | if opts.ignorewsamount: | |
|
169 | 187 | wsold = wsamountre.sub(' ', "".join(old)) |
|
170 | 188 | wsold = wsappendedre.sub('\n', wsold) |
|
171 | 189 | wsnew = wsamountre.sub(' ', "".join(new)) |
@@ -173,7 +191,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||
|
173 | 191 | if wsold == wsnew: |
|
174 | 192 | continue |
|
175 | 193 | |
|
176 | if ignorews: | |
|
194 | if opts.ignorews: | |
|
177 | 195 | wsold = wsre.sub('', "".join(old)) |
|
178 | 196 | wsnew = wsre.sub('', "".join(new)) |
|
179 | 197 | if wsold == wsnew: |
@@ -184,7 +202,7 b' def bunidiff(t1, t2, l1, l2, header1, he' | |||
|
184 | 202 | prev = None |
|
185 | 203 | if hunk: |
|
186 | 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 | 206 | prev = hunk |
|
189 | 207 | astart = hunk[1] |
|
190 | 208 | bstart = hunk[3] |
@@ -14,7 +14,7 b'' | |||
|
14 | 14 | allocation of intermediate Python objects. Working memory is about 2x |
|
15 | 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 | 19 | This software may be used and distributed according to the terms |
|
20 | 20 | of the GNU General Public License, incorporated herein by reference. |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | """ |
|
2 | 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 | 6 | This software may be used and distributed according to the terms |
|
7 | 7 | of the GNU General Public License, incorporated herein by reference. |
@@ -2,7 +2,7 b'' | |||
|
2 | 2 | # Used for the py2exe distutil. |
|
3 | 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 | 7 | # This software may be used and distributed according to the terms |
|
8 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,6 +1,7 b'' | |||
|
1 | 1 | # repo.py - repository base classes for mercurial |
|
2 | 2 | # |
|
3 | 3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |
|
4 | 5 | # |
|
5 | 6 | # This software may be used and distributed according to the terms |
|
6 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -4,7 +4,7 b' revlog.py - storage back-end for mercuri' | |||
|
4 | 4 | This provides efficient delta storage with O(1) retrieve and append |
|
5 | 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 | 9 | This software may be used and distributed according to the terms |
|
10 | 10 | of the GNU General Public License, incorporated herein by reference. |
@@ -469,7 +469,8 b' class revlog(object):' | |||
|
469 | 469 | return self.nodemap[node] |
|
470 | 470 | except KeyError: |
|
471 | 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 | 474 | def parents(self, node): |
|
474 | 475 | if node == nullid: return (nullid, nullid) |
|
475 | 476 | r = self.rev(node) |
@@ -743,13 +744,8 b' class revlog(object):' | |||
|
743 | 744 | |
|
744 | 745 | def lookup(self, id): |
|
745 | 746 | """locate a node based on revision number or subset of hex nodeid""" |
|
746 | if id in self.nodemap: | |
|
747 | return id | |
|
748 | 747 | if type(id) == type(0): |
|
749 |
re |
|
|
750 | if rev < 0: rev = self.count() + rev | |
|
751 | if rev < 0 or rev >= self.count(): return None | |
|
752 | return self.node(rev) | |
|
748 | return self.node(id) | |
|
753 | 749 | try: |
|
754 | 750 | rev = int(id) |
|
755 | 751 | if str(rev) != id: raise ValueError |
@@ -762,10 +758,26 b' class revlog(object):' | |||
|
762 | 758 | if hex(n).startswith(id): |
|
763 | 759 | c.append(n) |
|
764 | 760 | if len(c) > 1: raise RevlogError(_("Ambiguous identifier")) |
|
765 | if len(c) < 1: raise RevlogError(_("No match found")) | |
|
766 | return c[0] | |
|
761 | if len(c) == 1: 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 | 782 | def diff(self, a, b): |
|
771 | 783 | """return a delta between two revisions""" |
@@ -1,6 +1,6 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 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 | 14 | class sshrepository(remoterepository): |
|
15 | 15 | def __init__(self, ui, path, create=0): |
|
16 | self.url = path | |
|
16 | self._url = path | |
|
17 | 17 | self.ui = ui |
|
18 | 18 | |
|
19 | 19 | m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path) |
@@ -48,6 +48,9 b' class sshrepository(remoterepository):' | |||
|
48 | 48 | |
|
49 | 49 | self.validate_repo(ui, sshcmd, args, remotecmd) |
|
50 | 50 | |
|
51 | def url(self): | |
|
52 | return self._url | |
|
53 | ||
|
51 | 54 | def validate_repo(self, ui, sshcmd, args, remotecmd): |
|
52 | 55 | cmd = '%s %s "%s -R %s serve --stdio"' |
|
53 | 56 | cmd = cmd % (sshcmd, args, remotecmd, self.path) |
@@ -180,7 +183,7 b' class sshrepository(remoterepository):' | |||
|
180 | 183 | return 1 |
|
181 | 184 | return int(r) |
|
182 | 185 | |
|
183 | def addchangegroup(self, cg, source): | |
|
186 | def addchangegroup(self, cg, source, url): | |
|
184 | 187 | d = self.call("addchangegroup") |
|
185 | 188 | if d: |
|
186 | 189 | raise hg.RepoError(_("push refused: %s") % d) |
@@ -201,3 +204,5 b' class sshrepository(remoterepository):' | |||
|
201 | 204 | |
|
202 | 205 | def stream_out(self): |
|
203 | 206 | return self.do_cmd('stream_out') |
|
207 | ||
|
208 | instance = sshrepository |
@@ -1,6 +1,7 b'' | |||
|
1 | 1 | # sshserver.py - ssh protocol server support for mercurial |
|
2 | 2 | # |
|
3 | 3 | # Copyright 2005 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |
|
4 | 5 | # |
|
5 | 6 | # This software may be used and distributed according to the terms |
|
6 | 7 | # of the GNU General Public License, incorporated herein by reference. |
@@ -117,9 +118,13 b' class sshserver(object):' | |||
|
117 | 118 | return |
|
118 | 119 | |
|
119 | 120 | self.respond("") |
|
120 | r = self.repo.addchangegroup(self.fin, 'serve') | |
|
121 | r = self.repo.addchangegroup(self.fin, 'serve', self.client_url()) | |
|
121 | 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 | 128 | def do_unbundle(self): |
|
124 | 129 | their_heads = self.getarg()[1].split() |
|
125 | 130 | |
@@ -159,7 +164,7 b' class sshserver(object):' | |||
|
159 | 164 | # push can proceed |
|
160 | 165 | |
|
161 | 166 | fp.seek(0) |
|
162 | r = self.repo.addchangegroup(fp, 'serve') | |
|
167 | r = self.repo.addchangegroup(fp, 'serve', self.client_url()) | |
|
163 | 168 | self.respond(str(r)) |
|
164 | 169 | finally: |
|
165 | 170 | if not was_locked: |
@@ -2,14 +2,15 b'' | |||
|
2 | 2 | # |
|
3 | 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 | 7 | # This software may be used and distributed according to the terms |
|
8 | 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 | 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 | 15 | class rangereader(httprangereader.httprangereader): |
|
15 | 16 | def read(self, size=None): |
@@ -30,6 +31,7 b' def opener(base):' | |||
|
30 | 31 | |
|
31 | 32 | class statichttprepository(localrepo.localrepository): |
|
32 | 33 | def __init__(self, ui, path): |
|
34 | self._url = path | |
|
33 | 35 | self.path = (path + "/.hg") |
|
34 | 36 | self.ui = ui |
|
35 | 37 | self.revlogversion = 0 |
@@ -41,8 +43,22 b' class statichttprepository(localrepo.loc' | |||
|
41 | 43 | self.encodepats = None |
|
42 | 44 | self.decodepats = None |
|
43 | 45 | |
|
46 | def url(self): | |
|
47 | return 'static-' + self._url | |
|
48 | ||
|
44 | 49 | def dev(self): |
|
45 | 50 | return -1 |
|
46 | 51 | |
|
47 | 52 | def local(self): |
|
48 | 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 | 241 | return text.replace('\n', '<br/>\n') |
|
242 | 242 | |
|
243 | 243 | def obfuscate(text): |
|
244 | text = unicode(text, 'utf-8', 'replace') | |
|
244 | 245 | return ''.join(['&#%d;' % ord(c) for c in text]) |
|
245 | 246 | |
|
246 | 247 | def domain(author): |
@@ -458,7 +459,7 b' class changeset_templater(object):' | |||
|
458 | 459 | yield x |
|
459 | 460 | |
|
460 | 461 | if self.ui.debugflag: |
|
461 |
files = self.repo. |
|
|
462 | files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
|
462 | 463 | def showfiles(**args): |
|
463 | 464 | for x in showlist('file', files[0], **args): yield x |
|
464 | 465 | def showadds(**args): |
@@ -6,7 +6,7 b'' | |||
|
6 | 6 | # effectively log-structured, this should amount to simply truncating |
|
7 | 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 | 11 | # This software may be used and distributed according to the terms |
|
12 | 12 | # of the GNU General Public License, incorporated herein by reference. |
@@ -1,22 +1,24 b'' | |||
|
1 | 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 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | 7 | |
|
8 | 8 | from i18n import gettext as _ |
|
9 | 9 | from demandload import * |
|
10 |
demandload(globals(), "errno getpass os re s |
|
|
11 | demandload(globals(), "ConfigParser templater traceback util") | |
|
10 | demandload(globals(), "errno getpass os re socket sys tempfile") | |
|
11 | demandload(globals(), "ConfigParser mdiff templater traceback util") | |
|
12 | 12 | |
|
13 | 13 | class ui(object): |
|
14 | 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 | 17 | self.overlay = {} |
|
17 | 18 | if parentui is None: |
|
18 | 19 | # this is the parent of all ui children |
|
19 | 20 | self.parentui = None |
|
21 | self.readhooks = list(readhooks) | |
|
20 | 22 | self.cdata = ConfigParser.SafeConfigParser() |
|
21 | 23 | self.readconfig(util.rcpath()) |
|
22 | 24 | |
@@ -34,6 +36,7 b' class ui(object):' | |||
|
34 | 36 | else: |
|
35 | 37 | # parentui may point to an ui object which is already a child |
|
36 | 38 | self.parentui = parentui.parentui or parentui |
|
39 | self.readhooks = list(parentui.readhooks or readhooks) | |
|
37 | 40 | parent_cdata = self.parentui.cdata |
|
38 | 41 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
39 | 42 | # make interpolation work |
@@ -78,6 +81,8 b' class ui(object):' | |||
|
78 | 81 | for name, path in self.configitems("paths"): |
|
79 | 82 | if path and "://" not in path and not os.path.isabs(path): |
|
80 | 83 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
84 | for hook in self.readhooks: | |
|
85 | hook(self) | |
|
81 | 86 | |
|
82 | 87 | def setconfig(self, section, name, val): |
|
83 | 88 | self.overlay[(section, name)] = val |
@@ -169,17 +174,6 b' class ui(object):' | |||
|
169 | 174 | result[key.lower()] = value |
|
170 | 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 | 177 | def username(self): |
|
184 | 178 | """Return default username to be used in commits. |
|
185 | 179 | |
@@ -197,7 +191,7 b' class ui(object):' | |||
|
197 | 191 | user = os.environ.get("EMAIL") |
|
198 | 192 | if user is None: |
|
199 | 193 | try: |
|
200 |
user = '%s@%s' % ( |
|
|
194 | user = '%s@%s' % (util.getuser(), socket.getfqdn()) | |
|
201 | 195 | except KeyError: |
|
202 | 196 | raise util.Abort(_("Please specify a username.")) |
|
203 | 197 | return user |
@@ -217,12 +211,6 b' class ui(object):' | |||
|
217 | 211 | path = self.config("paths", default) |
|
218 | 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 | 214 | def write(self, *args): |
|
227 | 215 | if self.header: |
|
228 | 216 | if self.header != self.prev_header: |
@@ -298,62 +286,6 b' class ui(object):' | |||
|
298 | 286 | |
|
299 | 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 | 289 | def print_exc(self): |
|
358 | 290 | '''print exception traceback if traceback printing enabled. |
|
359 | 291 | only to call in exception handler. returns true if traceback |
@@ -2,6 +2,8 b'' | |||
|
2 | 2 | util.py - Mercurial utility functions and platform specfic implementations |
|
3 | 3 | |
|
4 | 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 | 8 | This software may be used and distributed according to the terms |
|
7 | 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 | 15 | from i18n import gettext as _ |
|
14 | 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 | 18 | demandload(globals(), "os threading time") |
|
17 | 19 | |
|
18 | 20 | # used by parsedate |
@@ -93,23 +95,6 b' def find_in_path(name, path, default=Non' | |||
|
93 | 95 | return p_name |
|
94 | 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 | 98 | def binary(s): |
|
114 | 99 | """return true if a string is binary data using diff's heuristic""" |
|
115 | 100 | if s and '\0' in s[:4096]: |
@@ -510,6 +495,20 b' def is_win_9x():' | |||
|
510 | 495 | except AttributeError: |
|
511 | 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 | 512 | # Platform specific variants |
|
514 | 513 | if os.name == 'nt': |
|
515 | 514 | demandload(globals(), "msvcrt") |
@@ -593,6 +592,9 b" if os.name == 'nt':" | |||
|
593 | 592 | def samestat(s1, s2): |
|
594 | 593 | return False |
|
595 | 594 | |
|
595 | def shellquote(s): | |
|
596 | return '"%s"' % s.replace('"', '\\"') | |
|
597 | ||
|
596 | 598 | def explain_exit(code): |
|
597 | 599 | return _("exited with status %d") % code, code |
|
598 | 600 | |
@@ -682,6 +684,9 b' else:' | |||
|
682 | 684 | else: |
|
683 | 685 | raise |
|
684 | 686 | |
|
687 | def shellquote(s): | |
|
688 | return "'%s'" % s.replace("'", "'\\''") | |
|
689 | ||
|
685 | 690 | def testpid(pid): |
|
686 | 691 | '''return False if pid dead, True if running or not sure''' |
|
687 | 692 | try: |
@@ -982,3 +987,11 b' def bytecount(nbytes):' | |||
|
982 | 987 | if nbytes >= divisor * multiplier: |
|
983 | 988 | return format % (nbytes / float(divisor)) |
|
984 | 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 | 297 | win32file.SetEndOfFile(self.handle) |
|
298 | 298 | except pywintypes.error, err: |
|
299 | 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 | 2 | # Author(s): |
|
3 | 3 | # Thomas Arendsen Hein <thomas@intevation.de> |
|
4 | 4 | # |
@@ -20,7 +20,7 b'' | |||
|
20 | 20 | </div> |
|
21 | 21 | |
|
22 | 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 | 24 | <br/> |
|
25 | 25 | #changenav%naventry#<br/> |
|
26 | 26 | </div> |
@@ -6,6 +6,7 b'' | |||
|
6 | 6 | <body> |
|
7 | 7 | |
|
8 | 8 | <div class="buttons"> |
|
9 | <a href="?sl=#rev#">shortlog</a> | |
|
9 | 10 | <a href="?cmd=tags">tags</a> |
|
10 | 11 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
11 | 12 | #archives%archiveentry# |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=#rev#">changelog</a> |
|
8 | <a href="?sl=#rev#">shortlog</a> | |
|
8 | 9 | <a href="?cmd=tags">tags</a> |
|
9 | 10 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
10 | 11 | <a href="?cs=#node|short#;style=raw">raw</a> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div class="title">#file|escape#</div> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=#rev#">changelog</a> |
|
8 | <a href="?sl=#rev#">shortlog</a> | |
|
8 | 9 | <a href="?tags=">tags</a> |
|
9 | 10 | <a href="?cs=#node|short#">changeset</a> |
|
10 | 11 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=#rev#">changelog</a> |
|
8 | <a href="?sl=#rev#">shortlog</a> | |
|
8 | 9 | <a href="?tags=">tags</a> |
|
9 | 10 | <a href="?cs=#node|short#">changeset</a> |
|
10 | 11 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div class="title" >#file|urlescape#</div> |
@@ -8,6 +8,7 b'' | |||
|
8 | 8 | |
|
9 | 9 | <div class="buttons"> |
|
10 | 10 | <a href="?cl=tip">changelog</a> |
|
11 | <a href="?sl=tip">shortlog</a> | |
|
11 | 12 | <a href="?tags=">tags</a> |
|
12 | 13 | <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> |
|
13 | 14 | <a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div class="title">#file|escape#</div> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=#rev#">changelog</a> |
|
8 | <a href="?sl=#rev#">shortlog</a> | |
|
8 | 9 | <a href="?tags=">tags</a> |
|
9 | 10 | <a href="?cs=#node|short#">changeset</a> |
|
10 | 11 | <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | </div> |
|
15 | 15 | |
|
16 | 16 | <div class="title" >#path|escape#</div> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=#rev#">changelog</a> |
|
8 | <a href="?sl=#rev#">shortlog</a> | |
|
8 | 9 | <a href="?tags=">tags</a> |
|
9 | 10 | <a href="?cs=#node|short#">changeset</a> |
|
10 | 11 | #archives%archiveentry# |
@@ -3,7 +3,10 b' header = header.tmpl' | |||
|
3 | 3 | footer = footer.tmpl |
|
4 | 4 | search = search.tmpl |
|
5 | 5 | changelog = changelog.tmpl |
|
6 | shortlog = shortlog.tmpl | |
|
7 | shortlogentry = shortlogentry.tmpl | |
|
6 | 8 | naventry = '<a href="?cl=#rev#">#label|escape#</a> ' |
|
9 | navshortentry = '<a href="?sl=#rev#">#label|escape#</a> ' | |
|
7 | 10 | filedifflink = '<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> ' |
|
8 | 11 | filenodelink = '<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> ' |
|
9 | 12 | fileellipses = '...' |
@@ -1,6 +1,6 b'' | |||
|
1 | 1 | #header# |
|
2 | 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 | 4 | </div> |
|
5 | 5 | |
|
6 | 6 | <h2>searching for #query|escape#</h2> |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | <div class="buttons"> |
|
7 | 7 | <a href="?cl=tip">changelog</a> |
|
8 | <a href="?sl=tip">shortlog</a> | |
|
8 | 9 | <a href="?tags=">tags</a> |
|
9 | 10 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
10 | 11 | </div> |
@@ -1,13 +1,32 b'' | |||
|
1 | 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 | 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 | 26 | </div> |
|
8 | 27 | |
|
9 | 28 | <table cellspacing="0"> |
|
10 | #entries# | |
|
29 | #entries%shortlogentry# | |
|
11 | 30 | </table> |
|
12 | 31 | |
|
13 | 32 | #footer# |
@@ -57,6 +57,12 b' pre { margin: 0; }' | |||
|
57 | 57 | .logEntry th.age, .logEntry th.firstline { font-weight: bold; } |
|
58 | 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 | 66 | /* Tag entries */ |
|
61 | 67 | #tagEntries { list-style: none; margin: 0; padding: 0; } |
|
62 | 68 | #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; } |
@@ -9,7 +9,8 b'' | |||
|
9 | 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 | 10 | </div> |
|
11 | 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 | 14 | </div> |
|
14 | 15 | |
|
15 | 16 | <div class="title"> </div> |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 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 | 14 | <br/> |
|
15 | 15 | </div> |
|
16 | 16 |
@@ -7,6 +7,7 b'' | |||
|
7 | 7 | |
|
8 | 8 | <div class="buttons"> |
|
9 | 9 | <a href="?cl=tip">changelog</a> |
|
10 | <a href="?sl=tip">shortlog</a> | |
|
10 | 11 | <a href="?mf=#manifest|short#;path=/">manifest</a> |
|
11 | 12 | <a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a> |
|
12 | 13 | </div> |
@@ -28,6 +28,6 b' writing tests:' | |||
|
28 | 28 | |
|
29 | 29 | - diff will show the current time |
|
30 | 30 | |
|
31 |
use hg diff | sed "s/\( |
|
|
32 | dates | |
|
33 | ||
|
31 | use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
32 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |
|
33 | to strip dates |
@@ -25,7 +25,7 b' parser = optparse.OptionParser("%prog [o' | |||
|
25 | 25 | parser.add_option("-v", "--verbose", action="store_true", |
|
26 | 26 | help="output verbose messages") |
|
27 | 27 | parser.add_option("-t", "--timeout", type="int", |
|
28 | help="output verbose messages") | |
|
28 | help="kill errant tests after TIMEOUT seconds") | |
|
29 | 29 | parser.add_option("-c", "--cover", action="store_true", |
|
30 | 30 | help="print a test coverage report") |
|
31 | 31 | parser.add_option("-s", "--cover_stdlib", action="store_true", |
@@ -201,6 +201,11 b' def run(cmd):' | |||
|
201 | 201 | return ret, splitnewlines(output) |
|
202 | 202 | |
|
203 | 203 | def run_one(test): |
|
204 | '''tristate output: | |
|
205 | None -> skipped | |
|
206 | True -> passed | |
|
207 | False -> failed''' | |
|
208 | ||
|
204 | 209 | vlog("# Test", test) |
|
205 | 210 | if not verbose: |
|
206 | 211 | sys.stdout.write('.') |
@@ -217,15 +222,28 b' def run_one(test):' | |||
|
217 | 222 | os.mkdir(tmpd) |
|
218 | 223 | os.chdir(tmpd) |
|
219 | 224 | |
|
220 | if test.endswith(".py"): | |
|
221 | cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test)) | |
|
222 | else: | |
|
223 | cmd = '"%s"' % (os.path.join(TESTDIR, test)) | |
|
225 | lctest = test.lower() | |
|
224 | 226 | |
|
225 | # To reliably get the error code from batch files on WinXP, | |
|
226 | # the "cmd /c call" prefix is needed. Grrr | |
|
227 |
if |
|
|
227 | if lctest.endswith('.py'): | |
|
228 | cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test)) | |
|
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 | 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 | 248 | if options.timeout > 0: |
|
231 | 249 | signal.alarm(options.timeout) |
@@ -244,7 +262,7 b' def run_one(test):' | |||
|
244 | 262 | ref_out = splitnewlines(f.read()) |
|
245 | 263 | f.close() |
|
246 | 264 | else: |
|
247 |
ref_out = [ |
|
|
265 | ref_out = [] | |
|
248 | 266 | if out != ref_out: |
|
249 | 267 | diffret = 1 |
|
250 | 268 | print "\nERROR: %s output changed" % (test) |
@@ -330,16 +348,23 b' try:' | |||
|
330 | 348 | |
|
331 | 349 | tests = 0 |
|
332 | 350 | failed = 0 |
|
351 | skipped = 0 | |
|
333 | 352 | |
|
334 | 353 | if len(args) == 0: |
|
335 | 354 | args = os.listdir(".") |
|
336 | 355 | for test in args: |
|
337 |
if test.startswith("test-") and |
|
|
338 | if not run_one(test): | |
|
356 | if (test.startswith("test-") and '~' not in test and | |
|
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 | 363 | failed += 1 |
|
340 | 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 | 368 | if coverage: |
|
344 | 369 | output_coverage() |
|
345 | 370 | except KeyboardInterrupt: |
@@ -27,7 +27,7 b' adding b' | |||
|
27 | 27 | reverting a |
|
28 | 28 | changeset 3:4cbb1e70196a backs out changeset 1:22bca4c721e5 |
|
29 | 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 | 31 | b: No such file or directory |
|
32 | 32 | adding a |
|
33 | 33 | adding b |
@@ -30,14 +30,20 b' cd ..' | |||
|
30 | 30 | hg init empty |
|
31 | 31 | hg -R test bundle full.hg empty |
|
32 | 32 | hg -R test unbundle full.hg |
|
33 | hg -R empty unbundle full.hg | |
|
34 | 33 | hg -R empty heads |
|
35 | 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 | 41 | rm -rf empty |
|
38 | 42 | hg init empty |
|
39 | 43 | cd empty |
|
40 | 44 | hg -R bundle://../full.hg log |
|
45 | echo '[hooks]' >> .hg/hgrc | |
|
46 | echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc | |
|
41 | 47 | #doesn't work (yet ?) |
|
42 | 48 | #hg -R bundle://../full.hg verify |
|
43 | 49 | hg pull bundle://../full.hg |
@@ -11,28 +11,34 b' adding manifests' | |||
|
11 | 11 | adding file changes |
|
12 | 12 | added 0 changesets with 0 changes to 4 files |
|
13 | 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 | 29 | adding changesets |
|
15 | 30 | adding manifests |
|
16 | 31 | adding file changes |
|
17 | 32 | added 9 changesets with 7 changes to 4 files (+1 heads) |
|
18 | 33 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
19 | changeset: 8:836ac62537ab | |
|
20 | tag: tip | |
|
21 | parent: 3:ac69c658229d | |
|
22 | user: test | |
|
23 | date: Mon Jan 12 13:46:40 1970 +0000 | |
|
24 | summary: 0.3m | |
|
25 | ||
|
26 | changeset: 7:80fe151401c2 | |
|
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 | |
|
34 | rolling back last transaction | |
|
35 | pulling from ../full.hg | |
|
36 | requesting all changes | |
|
37 | adding changesets | |
|
38 | adding manifests | |
|
39 | adding file changes | |
|
40 | added 9 changesets with 7 changes to 4 files (+1 heads) | |
|
41 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
|
36 | 42 | changeset: 8:836ac62537ab |
|
37 | 43 | tag: tip |
|
38 | 44 | parent: 3:ac69c658229d |
@@ -81,6 +87,7 b' user: test' | |||
|
81 | 87 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
82 | 88 | summary: 0.0 |
|
83 | 89 | |
|
90 | changegroup: u=bundle:../full.hg | |
|
84 | 91 | pulling from bundle://../full.hg |
|
85 | 92 | requesting all changes |
|
86 | 93 | adding changesets |
@@ -45,7 +45,7 b' hg --cwd c head -v' | |||
|
45 | 45 | hg --cwd b tip --verbose |
|
46 | 46 | |
|
47 | 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 | 49 | hg --cwd c --config '' tip -q |
|
50 | 50 | hg --cwd c --config a.b tip -q |
|
51 | 51 | hg --cwd c --config a tip -q |
@@ -18,6 +18,13 b' head -n 3 port > port1' | |||
|
18 | 18 | mv port1 port |
|
19 | 19 | hg commit -m 4 -u spam -d '4 0' |
|
20 | 20 | hg grep port port |
|
21 | echo 'FIXME: history is wrong here' | |
|
22 | 21 | hg grep --all -nu port port |
|
23 | 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 | 1 | port:4:export |
|
2 | 2 | port:4:vaportight |
|
3 | 3 | port:4:import/export |
|
4 | FIXME: history is wrong here | |
|
5 |
port: |
|
|
6 | port:1:2:+:eggs:vaportight | |
|
7 |
port: |
|
|
8 |
port: |
|
|
9 |
port: |
|
|
4 | port:4:4:-:spam:import/export | |
|
5 | port:3:4:+:eggs:import/export | |
|
6 | port:2:1:-:spam:import | |
|
7 | port:2:2:-:spam:export | |
|
8 | port:2:1:+:spam:export | |
|
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 | 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 | 178 | -r --rev revision |
|
179 | 179 | -a --text treat all files as text |
|
180 | 180 | -p --show-function show which function each change is in |
|
181 | -g --git use git extended diff format | |
|
181 | 182 | -w --ignore-all-space ignore white space when comparing lines |
|
182 | 183 | -b --ignore-space-change ignore changes in the amount of white space |
|
183 | 184 | -B --ignore-blank-lines ignore changes whose lines are all blank |
@@ -187,13 +188,15 b' hg status [OPTION]... [FILE]...' | |||
|
187 | 188 | |
|
188 | 189 | show changed files in the working directory |
|
189 | 190 | |
|
190 |
Show |
|
|
191 | given, only files that match are shown. | |
|
191 | Show status of files in the repository. If names are given, only | |
|
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 | 195 | The codes used to show the status of files are: |
|
194 | 196 | M = modified |
|
195 | 197 | A = added |
|
196 | 198 | R = removed |
|
199 | C = clean | |
|
197 | 200 | ! = deleted, but still tracked |
|
198 | 201 | ? = not tracked |
|
199 | 202 | I = ignored (not shown by default) |
@@ -203,10 +206,12 b' aliases: st' | |||
|
203 | 206 | |
|
204 | 207 | options: |
|
205 | 208 | |
|
209 | -A --all show status of all files | |
|
206 | 210 | -m --modified show only modified files |
|
207 | 211 | -a --added show only added files |
|
208 | 212 | -r --removed show only removed files |
|
209 | 213 | -d --deleted show only deleted (but tracked) files |
|
214 | -c --clean show only files without changes | |
|
210 | 215 | -u --unknown show only unknown (not tracked) files |
|
211 | 216 | -i --ignored show ignored files |
|
212 | 217 | -n --no-status hide status prefix |
@@ -17,9 +17,9 b' cd ../b' | |||
|
17 | 17 | |
|
18 | 18 | # changegroup hooks can see env vars |
|
19 | 19 | echo '[hooks]' > .hg/hgrc |
|
20 | echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc | |
|
21 | echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc | |
|
22 | echo 'incoming = echo incoming hook: n=$HG_NODE' >> .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 u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc | |
|
22 | echo 'incoming = echo incoming hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc | |
|
23 | 23 | |
|
24 | 24 | # pretxncommit and commit hooks can see both parents of merge |
|
25 | 25 | cd ../a |
@@ -22,11 +22,11 b' pretxncommit hook: n=4c52fb2e402287dd5dc' | |||
|
22 | 22 | 3:4c52fb2e4022 |
|
23 | 23 | commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2 |
|
24 | 24 | commit hook b |
|
25 | prechangegroup hook | |
|
26 | changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 | |
|
27 | incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 | |
|
28 | incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb | |
|
29 | incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 | |
|
25 | prechangegroup hook: u=file: | |
|
26 | changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: | |
|
27 | incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: | |
|
28 | incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file: | |
|
29 | incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file: | |
|
30 | 30 | pulling from ../a |
|
31 | 31 | searching for changes |
|
32 | 32 | adding changesets |
@@ -4,22 +4,31 b' hg init test' | |||
|
4 | 4 | cd test |
|
5 | 5 | echo foo>foo |
|
6 | 6 | hg commit -A -d '0 0' -m 1 |
|
7 | hg --config server.uncompressed=True serve -p 20059 -d --pid-file=hg1.pid | |
|
8 | cat hg1.pid >> $DAEMON_PIDS | |
|
9 | hg serve -p 20060 -d --pid-file=hg2.pid | |
|
10 | cat hg2.pid >> $DAEMON_PIDS | |
|
7 | hg --config server.uncompressed=True serve -p 20059 -d --pid-file=../hg1.pid | |
|
8 | hg serve -p 20060 -d --pid-file=../hg2.pid | |
|
11 | 9 | cd .. |
|
10 | cat hg1.pid hg2.pid >> $DAEMON_PIDS | |
|
12 | 11 | |
|
13 | 12 | echo % clone via stream |
|
14 | 13 | http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ |
|
15 | 14 | sed -e 's/[0-9][0-9.]*/XXX/g' |
|
16 | cd copy | |
|
17 | hg verify | |
|
15 | hg verify -R copy | |
|
18 | 16 | |
|
19 | 17 | echo % try to clone via stream, should use pull instead |
|
20 | 18 | http_proxy= hg clone --uncompressed http://localhost:20060/ copy2 |
|
21 | 19 | |
|
22 | 20 | echo % clone via pull |
|
23 | 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 | 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 | 28 | crosschecking files in changesets and manifests |
|
29 | 29 | checking files |
|
30 | 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 | 1 | #!/bin/sh |
|
2 | 2 | |
|
3 | 3 | hg init a |
|
4 | mkdir a/d1 | |
|
5 | mkdir a/d1/d2 | |
|
4 | 6 | echo line 1 > a/a |
|
7 | echo line 1 > a/d1/d2/a | |
|
5 | 8 | hg --cwd a ci -d '0 0' -Ama |
|
6 | 9 | |
|
7 | 10 | echo line 2 >> a/a |
@@ -69,7 +72,7 b' rm -rf b' | |||
|
69 | 72 | |
|
70 | 73 | echo % plain diff in email, no subject, no message body, should fail |
|
71 | 74 | hg clone -r0 a b |
|
72 |
grep -v '^ |
|
|
75 | egrep -v '^(Subject|email)' msg.patch | hg --cwd b import - | |
|
73 | 76 | rm -rf b |
|
74 | 77 | |
|
75 | 78 | echo % hg export in email, should use patch header |
@@ -79,3 +82,20 b' python mkmsg.py | hg --cwd b import -' | |||
|
79 | 82 | hg --cwd b tip | grep second |
|
80 | 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 | 1 | adding a |
|
2 | adding d1/d2/a | |
|
2 | 3 | % import exported patch |
|
3 | 4 | requesting all changes |
|
4 | 5 | adding changesets |
|
5 | 6 | adding manifests |
|
6 | 7 | adding file changes |
|
7 |
added 1 changesets with |
|
|
8 |
|
|
|
8 | added 1 changesets with 2 changes to 2 files | |
|
9 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
9 | 10 | applying ../tip.patch |
|
10 | patching file a | |
|
11 | 11 | % message should be same |
|
12 | 12 | summary: second change |
|
13 | 13 | % committer should be same |
@@ -17,10 +17,9 b' requesting all changes' | |||
|
17 | 17 | adding changesets |
|
18 | 18 | adding manifests |
|
19 | 19 | adding file changes |
|
20 |
added 1 changesets with |
|
|
21 |
|
|
|
20 | added 1 changesets with 2 changes to 2 files | |
|
21 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
22 | 22 | applying ../tip.patch |
|
23 | patching file a | |
|
24 | 23 | transaction abort! |
|
25 | 24 | rollback completed |
|
26 | 25 | % import of plain diff should be ok with message |
@@ -28,38 +27,34 b' requesting all changes' | |||
|
28 | 27 | adding changesets |
|
29 | 28 | adding manifests |
|
30 | 29 | adding file changes |
|
31 |
added 1 changesets with |
|
|
32 |
|
|
|
30 | added 1 changesets with 2 changes to 2 files | |
|
31 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
33 | 32 | applying ../tip.patch |
|
34 | patching file a | |
|
35 | 33 | % import from stdin |
|
36 | 34 | requesting all changes |
|
37 | 35 | adding changesets |
|
38 | 36 | adding manifests |
|
39 | 37 | adding file changes |
|
40 |
added 1 changesets with |
|
|
41 |
|
|
|
38 | added 1 changesets with 2 changes to 2 files | |
|
39 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
42 | 40 | applying patch from stdin |
|
43 | patching file a | |
|
44 | 41 | % override commit message |
|
45 | 42 | requesting all changes |
|
46 | 43 | adding changesets |
|
47 | 44 | adding manifests |
|
48 | 45 | adding file changes |
|
49 |
added 1 changesets with |
|
|
50 |
|
|
|
46 | added 1 changesets with 2 changes to 2 files | |
|
47 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
51 | 48 | applying patch from stdin |
|
52 | patching file a | |
|
53 | 49 | summary: override |
|
54 | 50 | % plain diff in email, subject, message body |
|
55 | 51 | requesting all changes |
|
56 | 52 | adding changesets |
|
57 | 53 | adding manifests |
|
58 | 54 | adding file changes |
|
59 |
added 1 changesets with |
|
|
60 |
|
|
|
55 | added 1 changesets with 2 changes to 2 files | |
|
56 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
61 | 57 | applying ../msg.patch |
|
62 | patching file a | |
|
63 | 58 | user: email patcher |
|
64 | 59 | summary: email patch |
|
65 | 60 | % plain diff in email, no subject, message body |
@@ -67,28 +62,25 b' requesting all changes' | |||
|
67 | 62 | adding changesets |
|
68 | 63 | adding manifests |
|
69 | 64 | adding file changes |
|
70 |
added 1 changesets with |
|
|
71 |
|
|
|
65 | added 1 changesets with 2 changes to 2 files | |
|
66 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
72 | 67 | applying patch from stdin |
|
73 | patching file a | |
|
74 | 68 | % plain diff in email, subject, no message body |
|
75 | 69 | requesting all changes |
|
76 | 70 | adding changesets |
|
77 | 71 | adding manifests |
|
78 | 72 | adding file changes |
|
79 |
added 1 changesets with |
|
|
80 |
|
|
|
73 | added 1 changesets with 2 changes to 2 files | |
|
74 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
81 | 75 | applying patch from stdin |
|
82 | patching file a | |
|
83 | 76 | % plain diff in email, no subject, no message body, should fail |
|
84 | 77 | requesting all changes |
|
85 | 78 | adding changesets |
|
86 | 79 | adding manifests |
|
87 | 80 | adding file changes |
|
88 |
added 1 changesets with |
|
|
89 |
|
|
|
81 | added 1 changesets with 2 changes to 2 files | |
|
82 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
90 | 83 | applying patch from stdin |
|
91 | patching file a | |
|
92 | 84 | transaction abort! |
|
93 | 85 | rollback completed |
|
94 | 86 | % hg export in email, should use patch header |
@@ -96,8 +88,20 b' requesting all changes' | |||
|
96 | 88 | adding changesets |
|
97 | 89 | adding manifests |
|
98 | 90 | adding file changes |
|
99 |
added 1 changesets with |
|
|
100 |
|
|
|
91 | added 1 changesets with 2 changes to 2 files | |
|
92 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
101 | 93 | applying patch from stdin |
|
102 | patching file a | |
|
103 | 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 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
2 | 2 | removing b |
|
3 | this update spans a branch affecting the following files: | |
|
4 | b | |
|
5 | aborting update spanning branches! | |
|
6 | (use 'hg merge' to merge across branches or 'hg update -C' to lose changes) | |
|
3 | abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes |
@@ -22,7 +22,7 b' added 1 changesets with 1 changes to 1 f' | |||
|
22 | 22 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
23 | 23 | merge: warning: conflicts during merge |
|
24 | 24 | resolving manifests |
|
25 | force False allow True moddirstate True linear False | |
|
25 | overwrite None branchmerge True partial False linear False | |
|
26 | 26 | ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20 |
|
27 | 27 | test.txt versions differ, resolve |
|
28 | 28 | merging test.txt |
@@ -36,13 +36,19 b' kill `cat hg.pid`' | |||
|
36 | 36 | |
|
37 | 37 | echo % expect success |
|
38 | 38 | echo 'allow_push = *' >> .hg/hgrc |
|
39 | echo '[hooks]' >> .hg/hgrc | |
|
40 | echo 'changegroup = echo changegroup: u=$HG_URL >> $HGTMP/urls' >> .hg/hgrc | |
|
39 | 41 | hg serve -p 20059 -d --pid-file=hg.pid |
|
40 | 42 | cat hg.pid >> $DAEMON_PIDS |
|
41 | 43 | hg --cwd ../test2 push http://localhost:20059/ |
|
42 | 44 | kill `cat hg.pid` |
|
43 | 45 | hg rollback |
|
44 | 46 | |
|
47 | sed 's/\(remote:http.*\):.*/\1/' $HGTMP/urls | |
|
48 | ||
|
45 | 49 | echo % expect authorization error: all users denied |
|
50 | echo '[web]' > .hg/hgrc | |
|
51 | echo 'push_ssl = false' >> .hg/hgrc | |
|
46 | 52 | echo 'deny_push = *' >> .hg/hgrc |
|
47 | 53 | hg serve -p 20059 -d --pid-file=hg.pid |
|
48 | 54 | cat hg.pid >> $DAEMON_PIDS |
@@ -20,6 +20,7 b' adding manifests' | |||
|
20 | 20 | adding file changes |
|
21 | 21 | added 1 changesets with 1 changes to 1 files |
|
22 | 22 | rolling back last transaction |
|
23 | changegroup: u=remote:http | |
|
23 | 24 | % expect authorization error: all users denied |
|
24 | 25 | pushing to http://localhost:20059/ |
|
25 | 26 | searching for changes |
@@ -17,6 +17,8 b' if [ ! -x dummyssh ] ; then' | |||
|
17 | 17 | exit -1 |
|
18 | 18 | fi |
|
19 | 19 | |
|
20 | SSH_CLIENT='127.0.0.1 1 2' | |
|
21 | export SSH_CLIENT | |
|
20 | 22 | echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog |
|
21 | 23 | $2 |
|
22 | 24 | EOF |
@@ -29,6 +31,8 b' echo this > foo' | |||
|
29 | 31 | hg ci -A -m "init" -d "1000000 0" foo |
|
30 | 32 | echo '[server]' > .hg/hgrc |
|
31 | 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 | 37 | cd .. |
|
34 | 38 | |
@@ -46,6 +50,9 b' echo "# verify"' | |||
|
46 | 50 | cd local |
|
47 | 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 | 56 | echo "# empty default pull" |
|
50 | 57 | hg paths |
|
51 | 58 | hg pull -e ../dummyssh |
@@ -83,5 +83,7 b' Got arguments 1:user@dummy 2:hg -R remot' | |||
|
83 | 83 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
84 | 84 | Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5: |
|
85 | 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 | 87 | Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: |
|
87 | 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 | 37 | cd local |
|
38 | 38 | hg verify |
|
39 | 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 | 48 | http_proxy= hg pull |
|
41 | 49 | |
|
42 | 50 | kill $! |
@@ -19,6 +19,12 b' crosschecking files in changesets and ma' | |||
|
19 | 19 | checking files |
|
20 | 20 | 1 files, 1 changesets, 1 total revisions |
|
21 | 21 | foo |
|
22 | adding quux | |
|
23 | changegroup: u=static-http://localhost:20059/remote | |
|
22 | 24 | pulling from static-http://localhost:20059/remote |
|
23 | 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 | 35 | hg copy modified copied |
|
36 | 36 | echo "hg status -C:" |
|
37 | 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 | 108 | R removed |
|
109 | 109 | ! deleted |
|
110 | 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 | 19 | cat .hgtags |
|
20 | 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 | 27 | hg tag -l 'xx |
|
23 | 28 | newline' |
|
24 | 29 | hg tag -l 'xx:xx' |
@@ -25,5 +25,8 b" use of 'hg tag NAME [REV]' is deprecated" | |||
|
25 | 25 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah |
|
26 | 26 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0 |
|
27 | 27 | c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1 |
|
28 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
|
29 | 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar | |
|
30 | c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1 | |
|
28 | 31 | abort: '\n' cannot be used in a tag name |
|
29 | 32 | abort: ':' cannot be used in a tag name |
@@ -15,7 +15,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||
|
15 | 15 | summary: 1 |
|
16 | 16 | |
|
17 | 17 | resolving manifests |
|
18 | force None allow None moddirstate True linear True | |
|
18 | overwrite False branchmerge False partial False linear True | |
|
19 | 19 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e |
|
20 | 20 | a versions differ, resolve |
|
21 | 21 | remote created b |
@@ -31,7 +31,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||
|
31 | 31 | summary: 2 |
|
32 | 32 | |
|
33 | 33 | resolving manifests |
|
34 | force None allow None moddirstate True linear True | |
|
34 | overwrite False branchmerge False partial False linear True | |
|
35 | 35 | ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c |
|
36 | 36 | remote deleted b |
|
37 | 37 | removing b |
@@ -41,7 +41,7 b' user: test' | |||
|
41 | 41 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
42 | 42 | summary: 1 |
|
43 | 43 | |
|
44 |
abort: there is nothing to merge |
|
|
44 | abort: there is nothing to merge - use "hg update" instead | |
|
45 | 45 | failed |
|
46 | 46 | changeset: 0:33aaa84a386b |
|
47 | 47 | user: test |
@@ -49,7 +49,7 b' date: Mon Jan 12 13:46:40 1970 +0' | |||
|
49 | 49 | summary: 1 |
|
50 | 50 | |
|
51 | 51 | resolving manifests |
|
52 | force None allow None moddirstate True linear True | |
|
52 | overwrite False branchmerge False partial False linear True | |
|
53 | 53 | ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e |
|
54 | 54 | a versions differ, resolve |
|
55 | 55 | remote created b |
@@ -95,21 +95,12 b' user: test' | |||
|
95 | 95 | date: Mon Jan 12 13:46:40 1970 +0000 |
|
96 | 96 | summary: 2 |
|
97 | 97 | |
|
98 | resolving manifests | |
|
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) | |
|
98 | abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes | |
|
108 | 99 | failed |
|
109 | 100 | abort: outstanding uncommitted changes |
|
110 | 101 | failed |
|
111 | 102 | resolving manifests |
|
112 |
|
|
|
103 | overwrite False branchmerge True partial False linear False | |
|
113 | 104 | ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 |
|
114 | 105 | a versions differ, resolve |
|
115 | 106 | b versions differ, resolve |
@@ -40,7 +40,7 b' a' | |||
|
40 | 40 | side1 |
|
41 | 41 | side2 |
|
42 | 42 | resolving manifests |
|
43 | force 1 allow None moddirstate True linear False | |
|
43 | overwrite True branchmerge False partial False linear False | |
|
44 | 44 | ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae |
|
45 | 45 | remote deleted side2, clobbering |
|
46 | 46 | remote deleted side1, clobbering |
General Comments 0
You need to be logged in to leave comments.
Login now