62
def greedy_fetch(to_branch, from_branch, revision, pb):
62
def greedy_fetch(to_branch, from_branch, revision=None, pb=None):
63
63
f = Fetcher(to_branch, from_branch, revision, pb)
64
64
return f.count_copied, f.failed_revisions
67
67
class Fetcher(object):
68
"""Pull history from one branch to another.
68
"""Pull revisions and texts from one branch to another.
70
This doesn't update the destination's history; that can be done
71
separately if desired.
71
74
If set, pull only up to this revision_id.
73
def __init__(self, to_branch, from_branch, revision_limit=None, pb=None):
78
last_revision -- if last_revision
79
is given it will be that, otherwise the last revision of
82
count_copied -- number of revisions copied
84
count_texts -- number of file texts copied
86
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
74
87
self.to_branch = to_branch
88
self.to_weaves = to_branch.weave_store
75
89
self.from_branch = from_branch
90
self.from_weaves = from_branch.weave_store
76
91
self.failed_revisions = []
77
92
self.count_copied = 0
78
93
self.count_total = 0
80
96
self.pb = bzrlib.ui.ui_factory.progress_bar()
83
self.revision_limit = self._find_revision_limit(revision_limit)
99
self.last_revision = self._find_last_revision(last_revision)
100
mutter('fetch up to rev {%s}', self.last_revision)
84
101
revs_to_fetch = self._compare_ancestries()
85
102
self._copy_revisions(revs_to_fetch)
103
self.new_ancestry = revs_to_fetch
89
def _find_revision_limit(self, revision_limit):
107
def _find_last_revision(self, last_revision):
90
108
"""Find the limiting source revision.
92
110
Every ancestor of that revision will be merged across.
96
114
self.pb.update('get source history')
97
115
from_history = self.from_branch.revision_history()
98
116
self.pb.update('get destination history')
100
if revision_limit not in from_history:
101
raise NoSuchRevision(self.from_branch, revision_limit)
118
if last_revision not in from_history:
119
raise NoSuchRevision(self.from_branch, last_revision)
103
return revision_limit
104
122
elif from_history:
105
123
return from_history[-1]
113
131
That is, every revision that's in the ancestry of the source
114
132
branch and not in the destination branch."""
115
133
self.pb.update('get source ancestry')
116
self.from_ancestry = self.from_branch.get_ancestry(self.revision_limit)
134
self.from_ancestry = self.from_branch.get_ancestry(self.last_revision)
118
136
dest_last_rev = self.to_branch.last_revision()
119
137
self.pb.update('get destination ancestry')
138
156
for rev_id in revs_to_fetch:
139
157
self.pb.update('fetch revision', i, self.count_total)
140
158
self._copy_one_revision(rev_id)
160
self.count_copied += 1
144
163
def _copy_one_revision(self, rev_id):
155
174
len(rev.parents))
156
175
self._copy_new_texts(rev_id, inv)
157
self.to_branch.weave_store.add_text(INVENTORY_FILEID, rev_id,
158
split_lines(inv_xml), rev.parents)
176
parent_ids = [x.revision_id for x in rev.parents]
177
self.to_weaves.add_text(INVENTORY_FILEID, rev_id,
178
split_lines(inv_xml), parent_ids)
159
179
self.to_branch.revision_store.add(StringIO(rev_xml), rev_id)
177
197
def _copy_one_text(self, rev_id, file_id):
178
198
"""Copy one file text."""
179
from_weave = self.from_branch.weave_store.get_weave(file_id)
199
mutter('copy text version {%s} of file {%s}',
201
from_weave = self.from_weaves.get_weave(file_id)
180
202
from_idx = from_weave.lookup(rev_id)
181
203
from_parents = map(from_weave.idx_to_name, from_weave.parents(from_idx))
182
204
text_lines = from_weave.get(from_idx)
183
to_weave = self.to_branch.weave_store.get_weave_or_empty(file_id)
205
to_weave = self.to_weaves.get_weave_or_empty(file_id)
184
206
to_parents = map(to_weave.lookup, from_parents)
185
207
# it's ok to add even if the text is already there
186
208
to_weave.add(rev_id, to_parents, text_lines)
187
self.to_branch.weave_store.put_weave(file_id, to_weave)
209
self.to_weaves.put_weave(file_id, to_weave)
210
self.count_texts += 1