mercurial/obsolete.py
changeset 33143 d09ae850296d
parent 33142 4f49810a1011
child 33144 d0e5bf12f314
equal deleted inserted replaced
33142:4f49810a1011 33143:d09ae850296d
   769     if store and readonly:
   769     if store and readonly:
   770         ui.warn(_('obsolete feature not enabled but %i markers found!\n')
   770         ui.warn(_('obsolete feature not enabled but %i markers found!\n')
   771                 % len(list(store)))
   771                 % len(list(store)))
   772     return store
   772     return store
   773 
   773 
   774 def _filterprunes(markers):
       
   775     """return a set with no prune markers"""
       
   776     return set(m for m in markers if m[1])
       
   777 
       
   778 def exclusivemarkers(repo, nodes):
       
   779     """set of markers relevant to "nodes" but no other locally-known nodes
       
   780 
       
   781     This function compute the set of markers "exclusive" to a locally-known
       
   782     node. This means we walk the markers starting from <nodes> until we reach a
       
   783     locally-known precursors outside of <nodes>. Element of <nodes> with
       
   784     locally-known successors outside of <nodes> are ignored (since their
       
   785     precursors markers are also relevant to these successors).
       
   786 
       
   787     For example:
       
   788 
       
   789         # (A0 rewritten as A1)
       
   790         #
       
   791         # A0 <-1- A1 # Marker "1" is exclusive to A1
       
   792 
       
   793         or
       
   794 
       
   795         # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
       
   796         #
       
   797         # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
       
   798 
       
   799         or
       
   800 
       
   801         # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
       
   802         #
       
   803         #          <-2- A1 # Marker "2" is exclusive to A0,A1
       
   804         #        /
       
   805         # <-1- A0
       
   806         #        \
       
   807         #         <-3- A2 # Marker "3" is exclusive to A0,A2
       
   808         #
       
   809         # in addition:
       
   810         #
       
   811         #  Markers "2,3" are exclusive to A1,A2
       
   812         #  Markers "1,2,3" are exclusive to A0,A1,A2
       
   813 
       
   814         See test/test-obsolete-bundle-strip.t for more examples.
       
   815 
       
   816     An example usage is strip. When stripping a changeset, we also want to
       
   817     strip the markers exclusive to this changeset. Otherwise we would have
       
   818     "dangling"" obsolescence markers from its precursors: Obsolescence markers
       
   819     marking a node as obsolete without any successors available locally.
       
   820 
       
   821     As for relevant markers, the prune markers for children will be followed.
       
   822     Of course, they will only be followed if the pruned children is
       
   823     locally-known. Since the prune markers are relevant to the pruned node.
       
   824     However, while prune markers are considered relevant to the parent of the
       
   825     pruned changesets, prune markers for locally-known changeset (with no
       
   826     successors) are considered exclusive to the pruned nodes. This allows
       
   827     to strip the prune markers (with the rest of the exclusive chain) alongside
       
   828     the pruned changesets.
       
   829     """
       
   830     # running on a filtered repository would be dangerous as markers could be
       
   831     # reported as exclusive when they are relevant for other filtered nodes.
       
   832     unfi = repo.unfiltered()
       
   833 
       
   834     # shortcut to various useful item
       
   835     nm = unfi.changelog.nodemap
       
   836     precursorsmarkers = unfi.obsstore.precursors
       
   837     successormarkers = unfi.obsstore.successors
       
   838     childrenmarkers = unfi.obsstore.children
       
   839 
       
   840     # exclusive markers (return of the function)
       
   841     exclmarkers = set()
       
   842     # we need fast membership testing
       
   843     nodes = set(nodes)
       
   844     # looking for head in the obshistory
       
   845     #
       
   846     # XXX we are ignoring all issues in regard with cycle for now.
       
   847     stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
       
   848     stack.sort()
       
   849     # nodes already stacked
       
   850     seennodes = set(stack)
       
   851     while stack:
       
   852         current = stack.pop()
       
   853         # fetch precursors markers
       
   854         markers = list(precursorsmarkers.get(current, ()))
       
   855         # extend the list with prune markers
       
   856         for mark in successormarkers.get(current, ()):
       
   857             if not mark[1]:
       
   858                 markers.append(mark)
       
   859         # and markers from children (looking for prune)
       
   860         for mark in childrenmarkers.get(current, ()):
       
   861             if not mark[1]:
       
   862                 markers.append(mark)
       
   863         # traverse the markers
       
   864         for mark in markers:
       
   865             if mark in exclmarkers:
       
   866                 # markers already selected
       
   867                 continue
       
   868 
       
   869             # If the markers is about the current node, select it
       
   870             #
       
   871             # (this delay the addition of markers from children)
       
   872             if mark[1] or mark[0] == current:
       
   873                 exclmarkers.add(mark)
       
   874 
       
   875             # should we keep traversing through the precursors?
       
   876             prec = mark[0]
       
   877 
       
   878             # nodes in the stack or already processed
       
   879             if prec in seennodes:
       
   880                 continue
       
   881 
       
   882             # is this a locally known node ?
       
   883             known = prec in nm
       
   884             # if locally-known and not in the <nodes> set the traversal
       
   885             # stop here.
       
   886             if known and prec not in nodes:
       
   887                 continue
       
   888 
       
   889             # do not keep going if there are unselected markers pointing to this
       
   890             # nodes. If we end up traversing these unselected markers later the
       
   891             # node will be taken care of at that point.
       
   892             precmarkers = _filterprunes(successormarkers.get(prec))
       
   893             if precmarkers.issubset(exclmarkers):
       
   894                 seennodes.add(prec)
       
   895                 stack.append(prec)
       
   896 
       
   897     return exclmarkers
       
   898 
       
   899 def commonversion(versions):
   774 def commonversion(versions):
   900     """Return the newest version listed in both versions and our local formats.
   775     """Return the newest version listed in both versions and our local formats.
   901 
   776 
   902     Returns None if no common version exists.
   777     Returns None if no common version exists.
   903     """
   778     """
   969     If <nodes> is specified, only markers "relevant" to those nodes are are
   844     If <nodes> is specified, only markers "relevant" to those nodes are are
   970     returned"""
   845     returned"""
   971     if nodes is None:
   846     if nodes is None:
   972         rawmarkers = repo.obsstore
   847         rawmarkers = repo.obsstore
   973     elif exclusive:
   848     elif exclusive:
   974         rawmarkers = exclusivemarkers(repo, nodes)
   849         rawmarkers = obsutil.exclusivemarkers(repo, nodes)
   975     else:
   850     else:
   976         rawmarkers = repo.obsstore.relevantmarkers(nodes)
   851         rawmarkers = repo.obsstore.relevantmarkers(nodes)
   977 
   852 
   978     for markerdata in rawmarkers:
   853     for markerdata in rawmarkers:
   979         yield marker(repo, markerdata)
   854         yield marker(repo, markerdata)
  1060             mutable = [c.node() for c in foreground if c.mutable()]
   935             mutable = [c.node() for c in foreground if c.mutable()]
  1061             succs.update(allsuccessors(repo.obsstore, mutable))
   936             succs.update(allsuccessors(repo.obsstore, mutable))
  1062             known = (n for n in succs if n in nm)
   937             known = (n for n in succs if n in nm)
  1063             foreground = set(repo.set('%ln::', known))
   938             foreground = set(repo.set('%ln::', known))
  1064     return set(c.node() for c in foreground)
   939     return set(c.node() for c in foreground)
       
   940 
       
   941 def exclusivemarkers(repo, nodes):
       
   942     movemsg = 'obsolete.exclusivemarkers moved to obsutil.exclusivemarkers'
       
   943     repo.ui.deprecwarn(movemsg, '4.3')
       
   944     return obsutil.exclusivemarkers(repo, nodes)
  1065 
   945 
  1066 def successorssets(repo, initialnode, cache=None):
   946 def successorssets(repo, initialnode, cache=None):
  1067     movemsg = 'obsolete.successorssets moved to obsutil.successorssets'
   947     movemsg = 'obsolete.successorssets moved to obsutil.successorssets'
  1068     repo.ui.deprecwarn(movemsg, '4.3')
   948     repo.ui.deprecwarn(movemsg, '4.3')
  1069     return obsutil.successorssets(repo, initialnode, cache=cache)
   949     return obsutil.successorssets(repo, initialnode, cache=cache)