Rev 1: Writing a simple plugin for finding the mainline which merged a revision. in http://bzr.arbash-meinel.com/plugins/find_mainline_rev
John Arbash Meinel
john at arbash-meinel.com
Thu Nov 1 19:19:02 GMT 2007
At http://bzr.arbash-meinel.com/plugins/find_mainline_rev
------------------------------------------------------------
revno: 1
revision-id:john at arbash-meinel.com-20071101191856-nq75rlbq0nwzm1tr
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: find_mainline_rev
timestamp: Thu 2007-11-01 14:18:56 -0500
message:
Writing a simple plugin for finding the mainline which merged a revision.
But it looks to be even simpler than I thought.
added:
__init__.py __init__.py-20071101191826-bpibqad1s9oeqw1d-1
-------------- next part --------------
=== added file '__init__.py'
--- a/__init__.py 1970-01-01 00:00:00 +0000
+++ b/__init__.py 2007-11-01 19:18:56 +0000
@@ -0,0 +1,120 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Find the mainline revision which merged a given revision."""
+
+from bzrlib import (
+ branch,
+ commands,
+ option,
+ trace,
+ tsort,
+ )
+
+
+def _find_mainline_rev(a_branch, revision_id):
+ """Find the mainline revision which merged this revision_id."""
+ tip_revision_id = a_branch.last_revision()
+ rev_graph = a_branch.repository.get_revision_graph(tip_revision_id)
+ if revision_id not in rev_graph:
+ return None
+ topo_sorted = tsort.merge_sort(
+ [(node, parents) for node, parents in rev_graph.iteritems()],
+ tip_revision_id, generate_revno=True)
+
+ node_offset = {}
+ nodes = []
+ target_node_offset = None
+
+ # We've checked these nodes already
+ # not_in_ancestry_of = set()
+
+ def _check_in_ancestry(mainline_rev_id):
+ found = False
+ nodes_to_check = [mainline_rev_id]
+ checked_nodes = set()
+
+ while nodes_to_check:
+ node = nodes_to_check.pop()
+ checked_nodes.add(node)
+ for parent in rev_graph[node]:
+ # if parent in not_in_ancestry_of:
+ # # We've checked this one in the past
+ # continue
+ if (parent not in node_offset
+ or node_offset[parent] > target_node_offset):
+ # This parent is too old
+ continue
+ if parent == revision_id:
+ # Found it
+ return True
+ nodes_to_check.append(parent)
+ # if we have gotten this far, then the node is not in the ancestry of
+ # any of the nodes we checked
+ # not_in_ancestry_of.update(checked_nodes)
+ return False
+
+ # topo_sorted starts from the tip and works backwards
+ # this will be the list of all mainline revisions that happen after the
+ # merged revision.
+ mainline_revs = []
+ for num, rev_id, depth, dotted_revno, eo_merge in topo_sorted:
+ node_offset[rev_id] = num
+ if rev_id == revision_id:
+ target_node_offset = num
+ print 'found node at %d' % (num,)
+ if depth == 0:
+ return revision_id
+ break
+ elif depth == 0:
+ mainline_revs.append(rev_id)
+
+ for main_rev_id in reversed(mainline_revs):
+ # We have a mainline node, check if the desired node is in the
+ # ancestry.
+ if _check_in_ancestry(main_rev_id):
+ return main_rev_id
+ assert 'it should have been the last one'
+ trace.warning("somehow we didn't find it in the ancestry,"
+ " even though get_revision_graph said it was.")
+ import pdb; pdb.set_trace()
+ return None
+
+
+class cmd_find_mainline_rev(commands.Command):
+ """Find the mainline revision which merged a given revision."""
+
+ takes_options = ['revision']
+
+ def run(self, revision=None):
+ if revision is None or len(revision) == 0:
+ raise errors.BzrCommandError('You must supply a --revision.')
+ a_branch, relpath = branch.Branch.open_containing('.')
+ a_branch.lock_read()
+ try:
+ revision_id = revision[0].in_history(a_branch).rev_id
+ mainline_revision_id = _find_mainline_rev(a_branch, revision_id)
+ finally:
+ a_branch.unlock()
+ if mainline_revision_id is None:
+ trace.note('Revision not present in ancestry')
+ return 1
+ else:
+ self.outf.write(mainline_revision_id + '\n')
+
+
+commands.register_command(cmd_find_mainline_rev)
+
More information about the bazaar-commits
mailing list