29 |
30 |
30 @eh.command( |
31 @eh.command( |
31 'obslog|olog', |
32 'obslog|olog', |
32 [('G', 'graph', True, _("show the revision DAG")), |
33 [('G', 'graph', True, _("show the revision DAG")), |
33 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')), |
34 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')), |
34 ('a', 'all', False, _('show all related changesets, not only precursors')) |
35 ('a', 'all', False, _('show all related changesets, not only precursors')), |
|
36 ('p', 'patch', False, _('show the patch between two obs versions')) |
35 ] + commands.formatteropts, |
37 ] + commands.formatteropts, |
36 _('hg olog [OPTION]... [REV]')) |
38 _('hg olog [OPTION]... [REV]')) |
37 def cmdobshistory(ui, repo, *revs, **opts): |
39 def cmdobshistory(ui, repo, *revs, **opts): |
38 """show the obsolescence history of the specified revisions. |
40 """show the obsolescence history of the specified revisions. |
39 |
41 |
70 if opts['graph']: |
72 if opts['graph']: |
71 return _debugobshistorygraph(ui, repo, revs, opts) |
73 return _debugobshistorygraph(ui, repo, revs, opts) |
72 |
74 |
73 fm = ui.formatter('debugobshistory', opts) |
75 fm = ui.formatter('debugobshistory', opts) |
74 revs.reverse() |
76 revs.reverse() |
75 _debugobshistoryrevs(fm, repo, revs) |
77 _debugobshistoryrevs(fm, repo, revs, opts) |
76 |
78 |
77 fm.end() |
79 fm.end() |
78 |
80 |
79 class obsmarker_printer(cmdutil.changeset_printer): |
81 class obsmarker_printer(cmdutil.changeset_printer): |
80 """show (available) information about a node |
82 """show (available) information about a node |
95 succs = self.repo.obsstore.successors.get(changenode, ()) |
97 succs = self.repo.obsstore.successors.get(changenode, ()) |
96 succs = sorted(succs) |
98 succs = sorted(succs) |
97 |
99 |
98 markerfm = fm.nested("debugobshistory.markers") |
100 markerfm = fm.nested("debugobshistory.markers") |
99 for successor in succs: |
101 for successor in succs: |
100 _debugobshistorydisplaymarker(markerfm, successor) |
102 _debugobshistorydisplaymarker(markerfm, successor, |
|
103 ctx.node(), self.repo, self.diffopts) |
101 markerfm.end() |
104 markerfm.end() |
102 |
105 |
103 markerfm.plain('\n') |
106 markerfm.plain('\n') |
104 |
|
105 self.hunk[ctx.node()] = self.ui.popbuffer() |
107 self.hunk[ctx.node()] = self.ui.popbuffer() |
106 else: |
108 else: |
107 ### graph output is buffered only |
109 ### graph output is buffered only |
108 msg = 'cannot be used outside of the graphlog (yet)' |
110 msg = 'cannot be used outside of the graphlog (yet)' |
109 raise error.ProgrammingError(msg) |
111 raise error.ProgrammingError(msg) |
111 def flush(self, ctx): |
113 def flush(self, ctx): |
112 ''' changeset_printer has some logic around buffering data |
114 ''' changeset_printer has some logic around buffering data |
113 in self.headers that we don't use |
115 in self.headers that we don't use |
114 ''' |
116 ''' |
115 pass |
117 pass |
|
118 |
|
119 def patchavailable(node, repo, marker): |
|
120 if node not in repo: |
|
121 return False, "context is not local" |
|
122 |
|
123 successors = marker[1] |
|
124 |
|
125 if len(successors) == 0: |
|
126 return False, "no successors" |
|
127 elif len(successors) > 1: |
|
128 return False, "too many successors (%d)" % len(successors) |
|
129 |
|
130 succ = successors[0] |
|
131 |
|
132 if succ not in repo: |
|
133 return False, "succ is unknown locally" |
|
134 |
|
135 # Check that both node and succ have the same parents |
|
136 nodep1, nodep2 = repo[node].p1(), repo[node].p2() |
|
137 succp1, succp2 = repo[succ].p1(), repo[succ].p2() |
|
138 |
|
139 if nodep1 != succp1 or nodep2 != succp2: |
|
140 return False, "changesets rebased" |
|
141 |
|
142 return True, succ |
|
143 |
|
144 def getmarkerpatch(repo, node, succ): |
|
145 # Todo get the ops from the cmd |
|
146 diffopts = patch.diffallopts(repo.ui, {}) |
|
147 matchfn = scmutil.matchall(repo) |
|
148 |
|
149 repo.ui.pushbuffer() |
|
150 cmdutil.diffordiffstat(repo.ui, repo, diffopts, node, succ, |
|
151 match=matchfn, stat=False) |
|
152 buffer = repo.ui.popbuffer() |
|
153 |
|
154 # Indent the buffer a little |
|
155 splitted = buffer.splitlines(True) |
|
156 splitted = [' %s' % line for line in splitted] |
|
157 return "".join(splitted) |
116 |
158 |
117 class missingchangectx(object): |
159 class missingchangectx(object): |
118 ''' a minimal object mimicking changectx for change contexts |
160 ''' a minimal object mimicking changectx for change contexts |
119 references by obs markers but not available locally ''' |
161 references by obs markers but not available locally ''' |
120 |
162 |
275 nodes.append(succnodeid) |
317 nodes.append(succnodeid) |
276 |
318 |
277 return sorted(seen), nodesucc, nodeprec |
319 return sorted(seen), nodesucc, nodeprec |
278 |
320 |
279 def _debugobshistorygraph(ui, repo, revs, opts): |
321 def _debugobshistorygraph(ui, repo, revs, opts): |
280 displayer = obsmarker_printer(ui, repo.unfiltered(), None, opts, buffered=True) |
322 matchfn = None |
|
323 if opts.get('patch'): |
|
324 matchfn = scmutil.matchall(repo) |
|
325 |
|
326 displayer = obsmarker_printer(ui, repo.unfiltered(), matchfn, opts, buffered=True) |
281 edges = graphmod.asciiedges |
327 edges = graphmod.asciiedges |
282 walker = _obshistorywalker(repo.unfiltered(), revs, opts.get('all', False)) |
328 walker = _obshistorywalker(repo.unfiltered(), revs, opts.get('all', False)) |
283 cmdutil.displaygraph(ui, repo, walker, displayer, edges) |
329 cmdutil.displaygraph(ui, repo, walker, displayer, edges) |
284 |
330 |
285 def _debugobshistoryrevs(fm, repo, revs): |
331 def _debugobshistoryrevs(fm, repo, revs, opts): |
286 """ Display the obsolescence history for revset |
332 """ Display the obsolescence history for revset |
287 """ |
333 """ |
288 precursors = repo.obsstore.precursors |
334 precursors = repo.obsstore.precursors |
289 successors = repo.obsstore.successors |
335 successors = repo.obsstore.successors |
290 nodec = repo.changelog.node |
336 nodec = repo.changelog.node |
300 |
346 |
301 succs = successors.get(ctxnode, ()) |
347 succs = successors.get(ctxnode, ()) |
302 |
348 |
303 markerfm = fm.nested("debugobshistory.markers") |
349 markerfm = fm.nested("debugobshistory.markers") |
304 for successor in sorted(succs): |
350 for successor in sorted(succs): |
305 _debugobshistorydisplaymarker(markerfm, successor) |
351 _debugobshistorydisplaymarker(markerfm, successor, ctxnode, repo, opts) |
306 markerfm.end() |
352 markerfm.end() |
307 |
353 |
308 precs = precursors.get(ctxnode, ()) |
354 precs = precursors.get(ctxnode, ()) |
309 for p in sorted(precs): |
355 for p in sorted(precs): |
310 # Only show nodes once |
356 # Only show nodes once |
339 fm.startitem() |
385 fm.startitem() |
340 fm.write('debugobshistory.node', '%s', hexnode, |
386 fm.write('debugobshistory.node', '%s', hexnode, |
341 label="evolve.node evolve.missing_change_ctx") |
387 label="evolve.node evolve.missing_change_ctx") |
342 fm.plain('\n') |
388 fm.plain('\n') |
343 |
389 |
344 def _debugobshistorydisplaymarker(fm, marker): |
390 def _debugobshistorydisplaymarker(fm, marker, node, repo, opts): |
345 succnodes = marker[1] |
391 succnodes = marker[1] |
346 date = marker[4] |
392 date = marker[4] |
347 metadata = dict(marker[3]) |
393 metadata = dict(marker[3]) |
348 |
394 |
349 fm.startitem() |
395 fm.startitem() |
402 shortsnodes = (nodemod.short(succnode) for succnode in sorted(succnodes)) |
448 shortsnodes = (nodemod.short(succnode) for succnode in sorted(succnodes)) |
403 nodes = fm.formatlist(shortsnodes, 'debugobshistory.succnodes', sep=', ') |
449 nodes = fm.formatlist(shortsnodes, 'debugobshistory.succnodes', sep=', ') |
404 fm.write('debugobshistory.succnodes', '%s', nodes, |
450 fm.write('debugobshistory.succnodes', '%s', nodes, |
405 label="evolve.node") |
451 label="evolve.node") |
406 |
452 |
|
453 # Patch display |
|
454 if opts.get('patch'): |
|
455 _patchavailable = patchavailable(node, repo, marker) |
|
456 |
|
457 if _patchavailable[0]: |
|
458 patch = getmarkerpatch(repo, node, _patchavailable[1]) |
|
459 else: |
|
460 patch = " (No patch available yet, %s)" % _patchavailable[1] |
|
461 if patch: |
|
462 fm.plain("\n") |
|
463 # should be in json too |
|
464 fm.plain(patch) |
|
465 |
407 fm.plain("\n") |
466 fm.plain("\n") |
408 |
467 |
409 # logic around storing and using effect flags |
468 # logic around storing and using effect flags |
410 DESCCHANGED = 1 << 0 # action changed the description |
469 DESCCHANGED = 1 << 0 # action changed the description |
411 METACHANGED = 1 << 1 # action change the meta |
470 METACHANGED = 1 << 1 # action change the meta |