##// END OF EJS Templates
changeset templater: convert some unnecessary yields to returns
Matt Mackall -
r3648:2801a3ef default
parent child Browse files
Show More
@@ -1,585 +1,585 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), 'os sys')
11 demandload(globals(), 'os sys')
12 demandload(globals(), 'mdiff util templater cStringIO patch')
12 demandload(globals(), 'mdiff util templater cStringIO patch')
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 def revpair(ui, repo, revs):
16 def revpair(ui, repo, revs):
17 '''return pair of nodes, given list of revisions. second item can
17 '''return pair of nodes, given list of revisions. second item can
18 be None, meaning use working dir.'''
18 be None, meaning use working dir.'''
19
19
20 def revfix(repo, val, defval):
20 def revfix(repo, val, defval):
21 if not val and val != 0:
21 if not val and val != 0:
22 val = defval
22 val = defval
23 return repo.lookup(val)
23 return repo.lookup(val)
24
24
25 if not revs:
25 if not revs:
26 return repo.dirstate.parents()[0], None
26 return repo.dirstate.parents()[0], None
27 end = None
27 end = None
28 if len(revs) == 1:
28 if len(revs) == 1:
29 if revrangesep in revs[0]:
29 if revrangesep in revs[0]:
30 start, end = revs[0].split(revrangesep, 1)
30 start, end = revs[0].split(revrangesep, 1)
31 start = revfix(repo, start, 0)
31 start = revfix(repo, start, 0)
32 end = revfix(repo, end, repo.changelog.count() - 1)
32 end = revfix(repo, end, repo.changelog.count() - 1)
33 else:
33 else:
34 start = revfix(repo, revs[0], None)
34 start = revfix(repo, revs[0], None)
35 elif len(revs) == 2:
35 elif len(revs) == 2:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
37 raise util.Abort(_('too many revisions specified'))
37 raise util.Abort(_('too many revisions specified'))
38 start = revfix(repo, revs[0], None)
38 start = revfix(repo, revs[0], None)
39 end = revfix(repo, revs[1], None)
39 end = revfix(repo, revs[1], None)
40 else:
40 else:
41 raise util.Abort(_('too many revisions specified'))
41 raise util.Abort(_('too many revisions specified'))
42 return start, end
42 return start, end
43
43
44 def revrange(ui, repo, revs):
44 def revrange(ui, repo, revs):
45 """Yield revision as strings from a list of revision specifications."""
45 """Yield revision as strings from a list of revision specifications."""
46
46
47 def revfix(repo, val, defval):
47 def revfix(repo, val, defval):
48 if not val and val != 0:
48 if not val and val != 0:
49 return defval
49 return defval
50 return repo.changelog.rev(repo.lookup(val))
50 return repo.changelog.rev(repo.lookup(val))
51
51
52 seen, l = {}, []
52 seen, l = {}, []
53 for spec in revs:
53 for spec in revs:
54 if revrangesep in spec:
54 if revrangesep in spec:
55 start, end = spec.split(revrangesep, 1)
55 start, end = spec.split(revrangesep, 1)
56 start = revfix(repo, start, 0)
56 start = revfix(repo, start, 0)
57 end = revfix(repo, end, repo.changelog.count() - 1)
57 end = revfix(repo, end, repo.changelog.count() - 1)
58 step = start > end and -1 or 1
58 step = start > end and -1 or 1
59 for rev in xrange(start, end+step, step):
59 for rev in xrange(start, end+step, step):
60 if rev in seen:
60 if rev in seen:
61 continue
61 continue
62 seen[rev] = 1
62 seen[rev] = 1
63 l.append(rev)
63 l.append(rev)
64 else:
64 else:
65 rev = revfix(repo, spec, None)
65 rev = revfix(repo, spec, None)
66 if rev in seen:
66 if rev in seen:
67 continue
67 continue
68 seen[rev] = 1
68 seen[rev] = 1
69 l.append(rev)
69 l.append(rev)
70
70
71 return l
71 return l
72
72
73 def make_filename(repo, pat, node,
73 def make_filename(repo, pat, node,
74 total=None, seqno=None, revwidth=None, pathname=None):
74 total=None, seqno=None, revwidth=None, pathname=None):
75 node_expander = {
75 node_expander = {
76 'H': lambda: hex(node),
76 'H': lambda: hex(node),
77 'R': lambda: str(repo.changelog.rev(node)),
77 'R': lambda: str(repo.changelog.rev(node)),
78 'h': lambda: short(node),
78 'h': lambda: short(node),
79 }
79 }
80 expander = {
80 expander = {
81 '%': lambda: '%',
81 '%': lambda: '%',
82 'b': lambda: os.path.basename(repo.root),
82 'b': lambda: os.path.basename(repo.root),
83 }
83 }
84
84
85 try:
85 try:
86 if node:
86 if node:
87 expander.update(node_expander)
87 expander.update(node_expander)
88 if node and revwidth is not None:
88 if node and revwidth is not None:
89 expander['r'] = (lambda:
89 expander['r'] = (lambda:
90 str(repo.changelog.rev(node)).zfill(revwidth))
90 str(repo.changelog.rev(node)).zfill(revwidth))
91 if total is not None:
91 if total is not None:
92 expander['N'] = lambda: str(total)
92 expander['N'] = lambda: str(total)
93 if seqno is not None:
93 if seqno is not None:
94 expander['n'] = lambda: str(seqno)
94 expander['n'] = lambda: str(seqno)
95 if total is not None and seqno is not None:
95 if total is not None and seqno is not None:
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
97 if pathname is not None:
97 if pathname is not None:
98 expander['s'] = lambda: os.path.basename(pathname)
98 expander['s'] = lambda: os.path.basename(pathname)
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
100 expander['p'] = lambda: pathname
100 expander['p'] = lambda: pathname
101
101
102 newname = []
102 newname = []
103 patlen = len(pat)
103 patlen = len(pat)
104 i = 0
104 i = 0
105 while i < patlen:
105 while i < patlen:
106 c = pat[i]
106 c = pat[i]
107 if c == '%':
107 if c == '%':
108 i += 1
108 i += 1
109 c = pat[i]
109 c = pat[i]
110 c = expander[c]()
110 c = expander[c]()
111 newname.append(c)
111 newname.append(c)
112 i += 1
112 i += 1
113 return ''.join(newname)
113 return ''.join(newname)
114 except KeyError, inst:
114 except KeyError, inst:
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
116 inst.args[0])
116 inst.args[0])
117
117
118 def make_file(repo, pat, node=None,
118 def make_file(repo, pat, node=None,
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
120 if not pat or pat == '-':
120 if not pat or pat == '-':
121 return 'w' in mode and sys.stdout or sys.stdin
121 return 'w' in mode and sys.stdout or sys.stdin
122 if hasattr(pat, 'write') and 'w' in mode:
122 if hasattr(pat, 'write') and 'w' in mode:
123 return pat
123 return pat
124 if hasattr(pat, 'read') and 'r' in mode:
124 if hasattr(pat, 'read') and 'r' in mode:
125 return pat
125 return pat
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
127 pathname),
127 pathname),
128 mode)
128 mode)
129
129
130 def matchpats(repo, pats=[], opts={}, head=''):
130 def matchpats(repo, pats=[], opts={}, head=''):
131 cwd = repo.getcwd()
131 cwd = repo.getcwd()
132 if not pats and cwd:
132 if not pats and cwd:
133 opts['include'] = [os.path.join(cwd, i)
133 opts['include'] = [os.path.join(cwd, i)
134 for i in opts.get('include', [])]
134 for i in opts.get('include', [])]
135 opts['exclude'] = [os.path.join(cwd, x)
135 opts['exclude'] = [os.path.join(cwd, x)
136 for x in opts.get('exclude', [])]
136 for x in opts.get('exclude', [])]
137 cwd = ''
137 cwd = ''
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
139 opts.get('exclude'), head)
139 opts.get('exclude'), head)
140
140
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
143 exact = dict.fromkeys(files)
143 exact = dict.fromkeys(files)
144 for src, fn in repo.walk(node=node, files=files, match=matchfn,
144 for src, fn in repo.walk(node=node, files=files, match=matchfn,
145 badmatch=badmatch):
145 badmatch=badmatch):
146 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
146 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
147
147
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
149 if added is None or removed is None:
149 if added is None or removed is None:
150 added, removed = repo.status()[1:3]
150 added, removed = repo.status()[1:3]
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
152 mf = repo.manifest.read(changes[0])
152 mf = repo.manifest.read(changes[0])
153 for a in added:
153 for a in added:
154 aa = repo.wread(a)
154 aa = repo.wread(a)
155 bestscore, bestname = None, None
155 bestscore, bestname = None, None
156 for r in removed:
156 for r in removed:
157 rr = repo.file(r).read(mf[r])
157 rr = repo.file(r).read(mf[r])
158 delta = mdiff.textdiff(aa, rr)
158 delta = mdiff.textdiff(aa, rr)
159 if len(delta) < len(aa):
159 if len(delta) < len(aa):
160 myscore = 1.0 - (float(len(delta)) / len(aa))
160 myscore = 1.0 - (float(len(delta)) / len(aa))
161 if bestscore is None or myscore > bestscore:
161 if bestscore is None or myscore > bestscore:
162 bestscore, bestname = myscore, r
162 bestscore, bestname = myscore, r
163 if bestname and bestscore >= threshold:
163 if bestname and bestscore >= threshold:
164 yield bestname, a, bestscore
164 yield bestname, a, bestscore
165
165
166 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
166 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
167 similarity=None):
167 similarity=None):
168 if dry_run is None:
168 if dry_run is None:
169 dry_run = opts.get('dry_run')
169 dry_run = opts.get('dry_run')
170 if similarity is None:
170 if similarity is None:
171 similarity = float(opts.get('similarity') or 0)
171 similarity = float(opts.get('similarity') or 0)
172 add, remove = [], []
172 add, remove = [], []
173 mapping = {}
173 mapping = {}
174 for src, abs, rel, exact in walk(repo, pats, opts):
174 for src, abs, rel, exact in walk(repo, pats, opts):
175 if src == 'f' and repo.dirstate.state(abs) == '?':
175 if src == 'f' and repo.dirstate.state(abs) == '?':
176 add.append(abs)
176 add.append(abs)
177 mapping[abs] = rel, exact
177 mapping[abs] = rel, exact
178 if repo.ui.verbose or not exact:
178 if repo.ui.verbose or not exact:
179 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
179 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
180 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
180 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
181 remove.append(abs)
181 remove.append(abs)
182 mapping[abs] = rel, exact
182 mapping[abs] = rel, exact
183 if repo.ui.verbose or not exact:
183 if repo.ui.verbose or not exact:
184 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
184 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
185 if not dry_run:
185 if not dry_run:
186 repo.add(add, wlock=wlock)
186 repo.add(add, wlock=wlock)
187 repo.remove(remove, wlock=wlock)
187 repo.remove(remove, wlock=wlock)
188 if similarity > 0:
188 if similarity > 0:
189 for old, new, score in findrenames(repo, add, remove, similarity):
189 for old, new, score in findrenames(repo, add, remove, similarity):
190 oldrel, oldexact = mapping[old]
190 oldrel, oldexact = mapping[old]
191 newrel, newexact = mapping[new]
191 newrel, newexact = mapping[new]
192 if repo.ui.verbose or not oldexact or not newexact:
192 if repo.ui.verbose or not oldexact or not newexact:
193 repo.ui.status(_('recording removal of %s as rename to %s '
193 repo.ui.status(_('recording removal of %s as rename to %s '
194 '(%d%% similar)\n') %
194 '(%d%% similar)\n') %
195 (oldrel, newrel, score * 100))
195 (oldrel, newrel, score * 100))
196 if not dry_run:
196 if not dry_run:
197 repo.copy(old, new, wlock=wlock)
197 repo.copy(old, new, wlock=wlock)
198
198
199 class uibuffer(object):
199 class uibuffer(object):
200 # Implement and delegate some ui protocol. Save hunks of
200 # Implement and delegate some ui protocol. Save hunks of
201 # output for later display in the desired order.
201 # output for later display in the desired order.
202 def __init__(self, ui):
202 def __init__(self, ui):
203 self.ui = ui
203 self.ui = ui
204 self.hunk = {}
204 self.hunk = {}
205 self.header = {}
205 self.header = {}
206 self.quiet = ui.quiet
206 self.quiet = ui.quiet
207 self.verbose = ui.verbose
207 self.verbose = ui.verbose
208 self.debugflag = ui.debugflag
208 self.debugflag = ui.debugflag
209 self.lastheader = None
209 self.lastheader = None
210 def note(self, *args):
210 def note(self, *args):
211 if self.verbose:
211 if self.verbose:
212 self.write(*args)
212 self.write(*args)
213 def status(self, *args):
213 def status(self, *args):
214 if not self.quiet:
214 if not self.quiet:
215 self.write(*args)
215 self.write(*args)
216 def debug(self, *args):
216 def debug(self, *args):
217 if self.debugflag:
217 if self.debugflag:
218 self.write(*args)
218 self.write(*args)
219 def write(self, *args):
219 def write(self, *args):
220 self.hunk.setdefault(self.rev, []).extend(args)
220 self.hunk.setdefault(self.rev, []).extend(args)
221 def write_header(self, *args):
221 def write_header(self, *args):
222 self.header.setdefault(self.rev, []).extend(args)
222 self.header.setdefault(self.rev, []).extend(args)
223 def mark(self, rev):
223 def mark(self, rev):
224 self.rev = rev
224 self.rev = rev
225 def flush(self, rev):
225 def flush(self, rev):
226 if rev in self.header:
226 if rev in self.header:
227 h = "".join(self.header[rev])
227 h = "".join(self.header[rev])
228 if h != self.lastheader:
228 if h != self.lastheader:
229 self.lastheader = h
229 self.lastheader = h
230 self.ui.write(h)
230 self.ui.write(h)
231 del self.header[rev]
231 del self.header[rev]
232 if rev in self.hunk:
232 if rev in self.hunk:
233 self.ui.write("".join(self.hunk[rev]))
233 self.ui.write("".join(self.hunk[rev]))
234 del self.hunk[rev]
234 del self.hunk[rev]
235 return 1
235 return 1
236 return 0
236 return 0
237
237
238 class changeset_printer(object):
238 class changeset_printer(object):
239 '''show changeset information when templating not requested.'''
239 '''show changeset information when templating not requested.'''
240
240
241 def __init__(self, ui, repo, patch, buffered):
241 def __init__(self, ui, repo, patch, buffered):
242 self.ui = ui
242 self.ui = ui
243 self.repo = repo
243 self.repo = repo
244 self.buffered = buffered
244 self.buffered = buffered
245 self.patch = patch
245 self.patch = patch
246 if buffered:
246 if buffered:
247 self.ui = uibuffer(ui)
247 self.ui = uibuffer(ui)
248
248
249 def flush(self, rev):
249 def flush(self, rev):
250 return self.ui.flush(rev)
250 return self.ui.flush(rev)
251
251
252 def show(self, rev=0, changenode=None, brinfo=None, copies=None):
252 def show(self, rev=0, changenode=None, brinfo=None, copies=None):
253 '''show a single changeset or file revision'''
253 '''show a single changeset or file revision'''
254 if self.buffered:
254 if self.buffered:
255 self.ui.mark(rev)
255 self.ui.mark(rev)
256 log = self.repo.changelog
256 log = self.repo.changelog
257 if changenode is None:
257 if changenode is None:
258 changenode = log.node(rev)
258 changenode = log.node(rev)
259 elif not rev:
259 elif not rev:
260 rev = log.rev(changenode)
260 rev = log.rev(changenode)
261
261
262 if self.ui.quiet:
262 if self.ui.quiet:
263 self.ui.write("%d:%s\n" % (rev, short(changenode)))
263 self.ui.write("%d:%s\n" % (rev, short(changenode)))
264 return
264 return
265
265
266 changes = log.read(changenode)
266 changes = log.read(changenode)
267 date = util.datestr(changes[2])
267 date = util.datestr(changes[2])
268 extra = changes[5]
268 extra = changes[5]
269 branch = extra.get("branch")
269 branch = extra.get("branch")
270
270
271 hexfunc = self.ui.debugflag and hex or short
271 hexfunc = self.ui.debugflag and hex or short
272
272
273 parents = log.parentrevs(rev)
273 parents = log.parentrevs(rev)
274 if not self.ui.debugflag:
274 if not self.ui.debugflag:
275 if parents[1] == nullrev:
275 if parents[1] == nullrev:
276 if parents[0] >= rev - 1:
276 if parents[0] >= rev - 1:
277 parents = []
277 parents = []
278 else:
278 else:
279 parents = [parents[0]]
279 parents = [parents[0]]
280 parents = [(p, hexfunc(log.node(p))) for p in parents]
280 parents = [(p, hexfunc(log.node(p))) for p in parents]
281
281
282 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
282 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
283
283
284 if branch:
284 if branch:
285 self.ui.write(_("branch: %s\n") % branch)
285 self.ui.write(_("branch: %s\n") % branch)
286 for tag in self.repo.nodetags(changenode):
286 for tag in self.repo.nodetags(changenode):
287 self.ui.write(_("tag: %s\n") % tag)
287 self.ui.write(_("tag: %s\n") % tag)
288 for parent in parents:
288 for parent in parents:
289 self.ui.write(_("parent: %d:%s\n") % parent)
289 self.ui.write(_("parent: %d:%s\n") % parent)
290
290
291 if brinfo and changenode in brinfo:
291 if brinfo and changenode in brinfo:
292 br = brinfo[changenode]
292 br = brinfo[changenode]
293 self.ui.write(_("branch: %s\n") % " ".join(br))
293 self.ui.write(_("branch: %s\n") % " ".join(br))
294
294
295 if self.ui.debugflag:
295 if self.ui.debugflag:
296 self.ui.write(_("manifest: %d:%s\n") %
296 self.ui.write(_("manifest: %d:%s\n") %
297 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
297 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
298 self.ui.write(_("user: %s\n") % changes[1])
298 self.ui.write(_("user: %s\n") % changes[1])
299 self.ui.write(_("date: %s\n") % date)
299 self.ui.write(_("date: %s\n") % date)
300
300
301 if self.ui.debugflag:
301 if self.ui.debugflag:
302 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
302 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
303 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
303 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
304 files):
304 files):
305 if value:
305 if value:
306 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
306 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
307 elif changes[3] and self.ui.verbose:
307 elif changes[3] and self.ui.verbose:
308 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
308 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
309 if copies and self.ui.verbose:
309 if copies and self.ui.verbose:
310 copies = ['%s (%s)' % c for c in copies]
310 copies = ['%s (%s)' % c for c in copies]
311 self.ui.write(_("copies: %s\n") % ' '.join(copies))
311 self.ui.write(_("copies: %s\n") % ' '.join(copies))
312
312
313 if extra and self.ui.debugflag:
313 if extra and self.ui.debugflag:
314 extraitems = extra.items()
314 extraitems = extra.items()
315 extraitems.sort()
315 extraitems.sort()
316 for key, value in extraitems:
316 for key, value in extraitems:
317 self.ui.write(_("extra: %s=%s\n")
317 self.ui.write(_("extra: %s=%s\n")
318 % (key, value.encode('string_escape')))
318 % (key, value.encode('string_escape')))
319
319
320 description = changes[4].strip()
320 description = changes[4].strip()
321 if description:
321 if description:
322 if self.ui.verbose:
322 if self.ui.verbose:
323 self.ui.write(_("description:\n"))
323 self.ui.write(_("description:\n"))
324 self.ui.write(description)
324 self.ui.write(description)
325 self.ui.write("\n\n")
325 self.ui.write("\n\n")
326 else:
326 else:
327 self.ui.write(_("summary: %s\n") %
327 self.ui.write(_("summary: %s\n") %
328 description.splitlines()[0])
328 description.splitlines()[0])
329 self.ui.write("\n")
329 self.ui.write("\n")
330
330
331 self.showpatch(changenode)
331 self.showpatch(changenode)
332
332
333 def showpatch(self, node):
333 def showpatch(self, node):
334 if self.patch:
334 if self.patch:
335 prev = self.repo.changelog.parents(node)[0]
335 prev = self.repo.changelog.parents(node)[0]
336 patch.diff(self.repo, prev, node, fp=self.ui)
336 patch.diff(self.repo, prev, node, fp=self.ui)
337 self.ui.write("\n")
337 self.ui.write("\n")
338
338
339 class changeset_templater(changeset_printer):
339 class changeset_templater(changeset_printer):
340 '''format changeset information.'''
340 '''format changeset information.'''
341
341
342 def __init__(self, ui, repo, patch, mapfile, buffered):
342 def __init__(self, ui, repo, patch, mapfile, buffered):
343 changeset_printer.__init__(self, ui, repo, patch, buffered)
343 changeset_printer.__init__(self, ui, repo, patch, buffered)
344 self.t = templater.templater(mapfile, templater.common_filters,
344 self.t = templater.templater(mapfile, templater.common_filters,
345 cache={'parent': '{rev}:{node|short} ',
345 cache={'parent': '{rev}:{node|short} ',
346 'manifest': '{rev}:{node|short}',
346 'manifest': '{rev}:{node|short}',
347 'filecopy': '{name} ({source})'})
347 'filecopy': '{name} ({source})'})
348
348
349 def use_template(self, t):
349 def use_template(self, t):
350 '''set template string to use'''
350 '''set template string to use'''
351 self.t.cache['changeset'] = t
351 self.t.cache['changeset'] = t
352
352
353 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
353 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
354 '''show a single changeset or file revision'''
354 '''show a single changeset or file revision'''
355 if self.buffered:
355 if self.buffered:
356 self.ui.mark(rev)
356 self.ui.mark(rev)
357 log = self.repo.changelog
357 log = self.repo.changelog
358 if changenode is None:
358 if changenode is None:
359 changenode = log.node(rev)
359 changenode = log.node(rev)
360 elif not rev:
360 elif not rev:
361 rev = log.rev(changenode)
361 rev = log.rev(changenode)
362
362
363 changes = log.read(changenode)
363 changes = log.read(changenode)
364
364
365 def showlist(name, values, plural=None, **args):
365 def showlist(name, values, plural=None, **args):
366 '''expand set of values.
366 '''expand set of values.
367 name is name of key in template map.
367 name is name of key in template map.
368 values is list of strings or dicts.
368 values is list of strings or dicts.
369 plural is plural of name, if not simply name + 's'.
369 plural is plural of name, if not simply name + 's'.
370
370
371 expansion works like this, given name 'foo'.
371 expansion works like this, given name 'foo'.
372
372
373 if values is empty, expand 'no_foos'.
373 if values is empty, expand 'no_foos'.
374
374
375 if 'foo' not in template map, return values as a string,
375 if 'foo' not in template map, return values as a string,
376 joined by space.
376 joined by space.
377
377
378 expand 'start_foos'.
378 expand 'start_foos'.
379
379
380 for each value, expand 'foo'. if 'last_foo' in template
380 for each value, expand 'foo'. if 'last_foo' in template
381 map, expand it instead of 'foo' for last key.
381 map, expand it instead of 'foo' for last key.
382
382
383 expand 'end_foos'.
383 expand 'end_foos'.
384 '''
384 '''
385 if plural: names = plural
385 if plural: names = plural
386 else: names = name + 's'
386 else: names = name + 's'
387 if not values:
387 if not values:
388 noname = 'no_' + names
388 noname = 'no_' + names
389 if noname in self.t:
389 if noname in self.t:
390 yield self.t(noname, **args)
390 yield self.t(noname, **args)
391 return
391 return
392 if name not in self.t:
392 if name not in self.t:
393 if isinstance(values[0], str):
393 if isinstance(values[0], str):
394 yield ' '.join(values)
394 yield ' '.join(values)
395 else:
395 else:
396 for v in values:
396 for v in values:
397 yield dict(v, **args)
397 yield dict(v, **args)
398 return
398 return
399 startname = 'start_' + names
399 startname = 'start_' + names
400 if startname in self.t:
400 if startname in self.t:
401 yield self.t(startname, **args)
401 yield self.t(startname, **args)
402 vargs = args.copy()
402 vargs = args.copy()
403 def one(v, tag=name):
403 def one(v, tag=name):
404 try:
404 try:
405 vargs.update(v)
405 vargs.update(v)
406 except (AttributeError, ValueError):
406 except (AttributeError, ValueError):
407 try:
407 try:
408 for a, b in v:
408 for a, b in v:
409 vargs[a] = b
409 vargs[a] = b
410 except ValueError:
410 except ValueError:
411 vargs[name] = v
411 vargs[name] = v
412 return self.t(tag, **vargs)
412 return self.t(tag, **vargs)
413 lastname = 'last_' + name
413 lastname = 'last_' + name
414 if lastname in self.t:
414 if lastname in self.t:
415 last = values.pop()
415 last = values.pop()
416 else:
416 else:
417 last = None
417 last = None
418 for v in values:
418 for v in values:
419 yield one(v)
419 yield one(v)
420 if last is not None:
420 if last is not None:
421 yield one(last, tag=lastname)
421 yield one(last, tag=lastname)
422 endname = 'end_' + names
422 endname = 'end_' + names
423 if endname in self.t:
423 if endname in self.t:
424 yield self.t(endname, **args)
424 yield self.t(endname, **args)
425
425
426 def showbranches(**args):
426 def showbranches(**args):
427 branch = changes[5].get("branch")
427 branch = changes[5].get("branch")
428 if branch:
428 if branch:
429 yield showlist('branch', [branch], plural='branches', **args)
429 return showlist('branch', [branch], plural='branches', **args)
430 # add old style branches if requested
430 # add old style branches if requested
431 if brinfo and changenode in brinfo:
431 if brinfo and changenode in brinfo:
432 yield showlist('branch', brinfo[changenode],
432 return showlist('branch', brinfo[changenode],
433 plural='branches', **args)
433 plural='branches', **args)
434
434
435 def showparents(**args):
435 def showparents(**args):
436 parents = [[('rev', log.rev(p)), ('node', hex(p))]
436 parents = [[('rev', log.rev(p)), ('node', hex(p))]
437 for p in log.parents(changenode)
437 for p in log.parents(changenode)
438 if self.ui.debugflag or p != nullid]
438 if self.ui.debugflag or p != nullid]
439 if (not self.ui.debugflag and len(parents) == 1 and
439 if (not self.ui.debugflag and len(parents) == 1 and
440 parents[0][0][1] == rev - 1):
440 parents[0][0][1] == rev - 1):
441 return
441 return
442 return showlist('parent', parents, **args)
442 return showlist('parent', parents, **args)
443
443
444 def showtags(**args):
444 def showtags(**args):
445 return showlist('tag', self.repo.nodetags(changenode), **args)
445 return showlist('tag', self.repo.nodetags(changenode), **args)
446
446
447 def showextras(**args):
447 def showextras(**args):
448 extras = changes[5].items()
448 extras = changes[5].items()
449 extras.sort()
449 extras.sort()
450 for key, value in extras:
450 for key, value in extras:
451 args = args.copy()
451 args = args.copy()
452 args.update(dict(key=key, value=value))
452 args.update(dict(key=key, value=value))
453 yield self.t('extra', **args)
453 yield self.t('extra', **args)
454
454
455 def showcopies(**args):
455 def showcopies(**args):
456 c = [{'name': x[0], 'source': x[1]} for x in copies]
456 c = [{'name': x[0], 'source': x[1]} for x in copies]
457 return showlist('file_copy', c, plural='file_copies', **args)
457 return showlist('file_copy', c, plural='file_copies', **args)
458
458
459 if self.ui.debugflag:
459 if self.ui.debugflag:
460 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
460 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
461 def showfiles(**args):
461 def showfiles(**args):
462 return showlist('file', files[0], **args)
462 return showlist('file', files[0], **args)
463 def showadds(**args):
463 def showadds(**args):
464 return showlist('file_add', files[1], **args)
464 return showlist('file_add', files[1], **args)
465 def showdels(**args):
465 def showdels(**args):
466 return showlist('file_del', files[2], **args)
466 return showlist('file_del', files[2], **args)
467 def showmanifest(**args):
467 def showmanifest(**args):
468 args = args.copy()
468 args = args.copy()
469 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
469 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
470 node=hex(changes[0])))
470 node=hex(changes[0])))
471 return self.t('manifest', **args)
471 return self.t('manifest', **args)
472 else:
472 else:
473 def showfiles(**args):
473 def showfiles(**args):
474 yield showlist('file', changes[3], **args)
474 return showlist('file', changes[3], **args)
475 showadds = ''
475 showadds = ''
476 showdels = ''
476 showdels = ''
477 showmanifest = ''
477 showmanifest = ''
478
478
479 defprops = {
479 defprops = {
480 'author': changes[1],
480 'author': changes[1],
481 'branches': showbranches,
481 'branches': showbranches,
482 'date': changes[2],
482 'date': changes[2],
483 'desc': changes[4],
483 'desc': changes[4],
484 'file_adds': showadds,
484 'file_adds': showadds,
485 'file_dels': showdels,
485 'file_dels': showdels,
486 'files': showfiles,
486 'files': showfiles,
487 'file_copies': showcopies,
487 'file_copies': showcopies,
488 'manifest': showmanifest,
488 'manifest': showmanifest,
489 'node': hex(changenode),
489 'node': hex(changenode),
490 'parents': showparents,
490 'parents': showparents,
491 'rev': rev,
491 'rev': rev,
492 'tags': showtags,
492 'tags': showtags,
493 'extras': showextras,
493 'extras': showextras,
494 }
494 }
495 props = props.copy()
495 props = props.copy()
496 props.update(defprops)
496 props.update(defprops)
497
497
498 try:
498 try:
499 if self.ui.debugflag and 'header_debug' in self.t:
499 if self.ui.debugflag and 'header_debug' in self.t:
500 key = 'header_debug'
500 key = 'header_debug'
501 elif self.ui.quiet and 'header_quiet' in self.t:
501 elif self.ui.quiet and 'header_quiet' in self.t:
502 key = 'header_quiet'
502 key = 'header_quiet'
503 elif self.ui.verbose and 'header_verbose' in self.t:
503 elif self.ui.verbose and 'header_verbose' in self.t:
504 key = 'header_verbose'
504 key = 'header_verbose'
505 elif 'header' in self.t:
505 elif 'header' in self.t:
506 key = 'header'
506 key = 'header'
507 else:
507 else:
508 key = ''
508 key = ''
509 if key:
509 if key:
510 h = templater.stringify(self.t(key, **props))
510 h = templater.stringify(self.t(key, **props))
511 if self.buffered:
511 if self.buffered:
512 self.ui.write_header(h)
512 self.ui.write_header(h)
513 else:
513 else:
514 self.ui.write(h)
514 self.ui.write(h)
515 if self.ui.debugflag and 'changeset_debug' in self.t:
515 if self.ui.debugflag and 'changeset_debug' in self.t:
516 key = 'changeset_debug'
516 key = 'changeset_debug'
517 elif self.ui.quiet and 'changeset_quiet' in self.t:
517 elif self.ui.quiet and 'changeset_quiet' in self.t:
518 key = 'changeset_quiet'
518 key = 'changeset_quiet'
519 elif self.ui.verbose and 'changeset_verbose' in self.t:
519 elif self.ui.verbose and 'changeset_verbose' in self.t:
520 key = 'changeset_verbose'
520 key = 'changeset_verbose'
521 else:
521 else:
522 key = 'changeset'
522 key = 'changeset'
523 self.ui.write(templater.stringify(self.t(key, **props)))
523 self.ui.write(templater.stringify(self.t(key, **props)))
524 self.showpatch(changenode)
524 self.showpatch(changenode)
525 except KeyError, inst:
525 except KeyError, inst:
526 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
526 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
527 inst.args[0]))
527 inst.args[0]))
528 except SyntaxError, inst:
528 except SyntaxError, inst:
529 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
529 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
530
530
531 class stringio(object):
531 class stringio(object):
532 '''wrap cStringIO for use by changeset_templater.'''
532 '''wrap cStringIO for use by changeset_templater.'''
533 def __init__(self):
533 def __init__(self):
534 self.fp = cStringIO.StringIO()
534 self.fp = cStringIO.StringIO()
535
535
536 def write(self, *args):
536 def write(self, *args):
537 for a in args:
537 for a in args:
538 self.fp.write(a)
538 self.fp.write(a)
539
539
540 write_header = write
540 write_header = write
541
541
542 def __getattr__(self, key):
542 def __getattr__(self, key):
543 return getattr(self.fp, key)
543 return getattr(self.fp, key)
544
544
545 def show_changeset(ui, repo, opts, buffered=False):
545 def show_changeset(ui, repo, opts, buffered=False):
546 """show one changeset using template or regular display.
546 """show one changeset using template or regular display.
547
547
548 Display format will be the first non-empty hit of:
548 Display format will be the first non-empty hit of:
549 1. option 'template'
549 1. option 'template'
550 2. option 'style'
550 2. option 'style'
551 3. [ui] setting 'logtemplate'
551 3. [ui] setting 'logtemplate'
552 4. [ui] setting 'style'
552 4. [ui] setting 'style'
553 If all of these values are either the unset or the empty string,
553 If all of these values are either the unset or the empty string,
554 regular display via changeset_printer() is done.
554 regular display via changeset_printer() is done.
555 """
555 """
556 # options
556 # options
557 patch = opts.get('patch')
557 patch = opts.get('patch')
558 tmpl = opts.get('template')
558 tmpl = opts.get('template')
559 mapfile = None
559 mapfile = None
560 if tmpl:
560 if tmpl:
561 tmpl = templater.parsestring(tmpl, quoted=False)
561 tmpl = templater.parsestring(tmpl, quoted=False)
562 else:
562 else:
563 mapfile = opts.get('style')
563 mapfile = opts.get('style')
564 # ui settings
564 # ui settings
565 if not mapfile:
565 if not mapfile:
566 tmpl = ui.config('ui', 'logtemplate')
566 tmpl = ui.config('ui', 'logtemplate')
567 if tmpl:
567 if tmpl:
568 tmpl = templater.parsestring(tmpl)
568 tmpl = templater.parsestring(tmpl)
569 else:
569 else:
570 mapfile = ui.config('ui', 'style')
570 mapfile = ui.config('ui', 'style')
571
571
572 if tmpl or mapfile:
572 if tmpl or mapfile:
573 if mapfile:
573 if mapfile:
574 if not os.path.split(mapfile)[0]:
574 if not os.path.split(mapfile)[0]:
575 mapname = (templater.templatepath('map-cmdline.' + mapfile)
575 mapname = (templater.templatepath('map-cmdline.' + mapfile)
576 or templater.templatepath(mapfile))
576 or templater.templatepath(mapfile))
577 if mapname: mapfile = mapname
577 if mapname: mapfile = mapname
578 try:
578 try:
579 t = changeset_templater(ui, repo, patch, mapfile, buffered)
579 t = changeset_templater(ui, repo, patch, mapfile, buffered)
580 except SyntaxError, inst:
580 except SyntaxError, inst:
581 raise util.Abort(inst.args[0])
581 raise util.Abort(inst.args[0])
582 if tmpl: t.use_template(tmpl)
582 if tmpl: t.use_template(tmpl)
583 return t
583 return t
584 return changeset_printer(ui, repo, patch, buffered)
584 return changeset_printer(ui, repo, patch, buffered)
585
585
General Comments 0
You need to be logged in to leave comments. Login now