1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
# 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 operator import itemgetter
from bzrlib import bzrdir, errors, osutils, transport
from bzrlib.trace import error, note
from fastimport.helpers import (
single_plural,
)
from bzrlib.plugins.fastimport.helpers import (
best_format_for_objects_in_a_repository,
)
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
self._branch_format = \
best_format_for_objects_in_a_repository(repo)
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 ('trunk' is first)
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: branch_tips, lost_heads where
branch_tips = a list of (branch,tip) tuples for branches. The
first tip is the 'trunk'.
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. If we haven't
# already put the 'trunk' first, do it now.
git_to_bzr_map = {}
for ref_name in ref_names:
git_to_bzr_map[ref_name] = self.cache_mgr.branch_mapper.git_to_bzr(ref_name)
if ref_names and self.branch is None:
trunk = self.select_trunk(ref_names)
git_bzr_items = [(trunk, git_to_bzr_map[trunk])]
del git_to_bzr_map[trunk]
else:
git_bzr_items = []
git_bzr_items.extend(sorted(git_to_bzr_map.items(), key=itemgetter(1)))
# Policy for locating branches
def dir_under_current(name, ref_name):
# Using the Bazaar name, get a directory under the current one
repo_base = self.repo.bzrdir.transport.base
return osutils.pathjoin(repo_base, "..", 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 ref_name, name in git_bzr_items:
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."""
to_transport = transport.get_transport(location)
to_transport.create_prefix()
try:
return bzrdir.BzrDir.open(location).open_branch()
except errors.NotBranchError, ex:
return bzrdir.BzrDir.create_branch_convenience(location,
format=self._branch_format,
possible_transports=[to_transport])
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:
ancestry = self.repo.get_ancestry(last_rev_id)
for tag,rev in self.tags.items():
if rev in ancestry:
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, single_plural(revno, "revision", "revisions"),
tagno, single_plural(tagno, "tag", "tags"))
return changed
|