summaryrefslogtreecommitdiff
path: root/branch_updater.py
diff options
context:
space:
mode:
authorIan Clatworthy <ian.clatworthy@canonical.com>2009-02-18 11:35:04 +1000
committerIan Clatworthy <ian.clatworthy@canonical.com>2009-02-18 11:35:04 +1000
commite16bb637ea63bd6055b6adb420b95d92d466d938 (patch)
treea6f9e99f28a8ee1ca4b02b7c0c2a4500e688b128 /branch_updater.py
parentfe864b9880157b866b44f8dfdbadf677b36c5a5b (diff)
downloadbzr-fastimport-e16bb637ea63bd6055b6adb420b95d92d466d938.tar.gz
move GenericBranchUpdater into its own module
Diffstat (limited to 'branch_updater.py')
-rw-r--r--branch_updater.py176
1 files changed, 176 insertions, 0 deletions
diff --git a/branch_updater.py b/branch_updater.py
new file mode 100644
index 0000000..022ec75
--- /dev/null
+++ b/branch_updater.py
@@ -0,0 +1,176 @@
+# Copyright (C) 2009 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
+
+"""An object that updates a bunch of branches based on data imported."""
+
+
+from bzrlib import bzrdir, errors
+from bzrlib.trace import error, note
+import helpers
+
+
+class BranchUpdater(object):
+
+ def __init__(self, repo, branch, cache_mgr, heads_by_ref, last_ref, tags):
+ """Create an object responsible for updating branches.
+
+ :param heads_by_ref: a dictionary where
+ names are git-style references like refs/heads/master;
+ values are one item lists of commits marks.
+ """
+ self.repo = repo
+ self.branch = branch
+ self.cache_mgr = cache_mgr
+ self.heads_by_ref = heads_by_ref
+ self.last_ref = last_ref
+ self.tags = tags
+
+ def update(self):
+ """Update the Bazaar branches and tips matching the heads.
+
+ If the repository is shared, this routine creates branches
+ as required. If it isn't, warnings are produced about the
+ lost of information.
+
+ :return: updated, lost_heads where
+ updated = the list of branches updated
+ lost_heads = a list of (bazaar-name,revision) for branches that
+ would have been created had the repository been shared
+ """
+ updated = []
+ branch_tips, lost_heads = self._get_matching_branches()
+ for br, tip in branch_tips:
+ if self._update_branch(br, tip):
+ updated.append(br)
+ return updated, lost_heads
+
+ def _get_matching_branches(self):
+ """Get the Bazaar branches.
+
+ :return: default_tip, branch_tips, lost_heads where
+ default_tip = the last commit mark for the default branch
+ branch_tips = a list of (branch,tip) tuples for other branches.
+ lost_heads = a list of (bazaar-name,revision) for branches that
+ would have been created had the repository been shared and
+ everything succeeded
+ """
+ branch_tips = []
+ lost_heads = []
+ ref_names = self.heads_by_ref.keys()
+ if self.branch is not None:
+ trunk = self.select_trunk(ref_names)
+ default_tip = self.heads_by_ref[trunk][0]
+ branch_tips.append((self.branch, default_tip))
+ ref_names.remove(trunk)
+
+ # Convert the reference names into Bazaar speak
+ bzr_names = self._get_bzr_names_from_ref_names(ref_names)
+
+ # Policy for locating branches
+ def dir_under_current(name, ref_name):
+ # Using the Bazaar name, get a directory under the current one
+ return name
+ def dir_sister_branch(name, ref_name):
+ # Using the Bazaar name, get a sister directory to the branch
+ return osutils.pathjoin(self.branch.base, "..", name)
+ if self.branch is not None:
+ dir_policy = dir_sister_branch
+ else:
+ dir_policy = dir_under_current
+
+ # Create/track missing branches
+ shared_repo = self.repo.is_shared()
+ for name in sorted(bzr_names.keys()):
+ ref_name = bzr_names[name]
+ tip = self.heads_by_ref[ref_name][0]
+ if shared_repo:
+ location = dir_policy(name, ref_name)
+ try:
+ br = self.make_branch(location)
+ branch_tips.append((br,tip))
+ continue
+ except errors.BzrError, ex:
+ error("ERROR: failed to create branch %s: %s",
+ location, ex)
+ lost_head = self.cache_mgr.revision_ids[tip]
+ lost_info = (name, lost_head)
+ lost_heads.append(lost_info)
+ return branch_tips, lost_heads
+
+ def select_trunk(self, ref_names):
+ """Given a set of ref names, choose one as the trunk."""
+ for candidate in ['refs/heads/master']:
+ if candidate in ref_names:
+ return candidate
+ # Use the last reference in the import stream
+ return self.last_ref
+
+ def make_branch(self, location):
+ """Make a branch in the repository if not already there."""
+ try:
+ return bzrdir.BzrDir.open(location).open_branch()
+ except errors.NotBranchError, ex:
+ return bzrdir.BzrDir.create_branch_convenience(location)
+
+ def _get_bzr_names_from_ref_names(self, ref_names):
+ """Generate Bazaar branch names from import ref names.
+
+ :return: a dictionary with Bazaar names as keys and
+ the original reference names as values.
+ """
+ bazaar_names = {}
+ for ref_name in sorted(ref_names):
+ parts = ref_name.split('/')
+ if parts[0] == 'refs':
+ parts.pop(0)
+ full_name = "--".join(parts)
+ bazaar_name = parts[-1]
+ if bazaar_name in bazaar_names:
+ if parts[0] == 'remotes':
+ bazaar_name += ".remote"
+ else:
+ bazaar_name = full_name
+ bazaar_names[bazaar_name] = ref_name
+ return bazaar_names
+
+ def _update_branch(self, br, last_mark):
+ """Update a branch with last revision and tag information.
+
+ :return: whether the branch was changed or not
+ """
+ last_rev_id = self.cache_mgr.revision_ids[last_mark]
+ revs = list(self.repo.iter_reverse_revision_history(last_rev_id))
+ revno = len(revs)
+ existing_revno, existing_last_rev_id = br.last_revision_info()
+ changed = False
+ if revno != existing_revno or last_rev_id != existing_last_rev_id:
+ br.set_last_revision_info(revno, last_rev_id)
+ changed = True
+ # apply tags known in this branch
+ my_tags = {}
+ if self.tags:
+ for tag,rev in self.tags.items():
+ if rev in revs:
+ my_tags[tag] = rev
+ if my_tags:
+ br.tags._set_tag_dict(my_tags)
+ changed = True
+ if changed:
+ tagno = len(my_tags)
+ note("\t branch %s now has %d %s and %d %s", br.nick,
+ revno, helpers.single_plural(revno, "revision", "revisions"),
+ tagno, helpers.single_plural(tagno, "tag", "tags"))
+ return changed