hgext3rd/evolve/obshistory.py
changeset 2637 49f2741c4dd7
parent 2636 a788967aa800
child 2638 9290f985868c
equal deleted inserted replaced
2636:a788967aa800 2637:49f2741c4dd7
    12 from mercurial import (
    12 from mercurial import (
    13     cmdutil,
    13     cmdutil,
    14     commands,
    14     commands,
    15     error,
    15     error,
    16     graphmod,
    16     graphmod,
       
    17     patch,
    17     obsolete,
    18     obsolete,
    18     node as nodemod,
    19     node as nodemod,
    19     scmutil,
    20     scmutil,
    20 )
    21 )
    21 
    22 
    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