143
154
except errors.NoSuchRevision:
144
155
raise InstallFailed([self._last_revision])
146
def _fetch_revision_texts(self, revs):
147
self.to_repository.revision_store.copy_multi(
148
self.from_repository.revision_store,
152
157
def _fetch_weave_texts(self, revs):
153
file_ids = self.from_repository.fileid_involved_by_set(revs)
155
num_file_ids = len(file_ids)
156
for file_id in file_ids:
157
self.pb.update("merge weaves", count, num_file_ids)
159
to_weave = self.to_weaves.get_weave_or_empty(file_id,
160
self.to_repository.get_transaction())
161
from_weave = self.from_weaves.get_weave(file_id,
162
self.from_repository.get_transaction())
164
if to_weave.numversions() > 0:
165
# destination has contents, must merge
158
texts_pb = bzrlib.ui.ui_factory.nested_progress_bar()
160
file_ids = self.from_repository.fileid_involved_by_set(revs)
162
num_file_ids = len(file_ids)
163
for file_id in file_ids:
164
texts_pb.update("fetch texts", count, num_file_ids)
166
to_weave = self.to_weaves.get_weave_or_empty(file_id,
167
self.to_repository.get_transaction())
168
from_weave = self.from_weaves.get_weave(file_id,
169
self.from_repository.get_transaction())
170
# we fetch all the texts, because texts do
171
# not reference anything, and its cheap enough
172
to_weave.join(from_weave)
176
def _fetch_inventory_weave(self, revs):
177
pb = bzrlib.ui.ui_factory.nested_progress_bar()
179
pb.update("fetch inventory", 0, 2)
180
to_weave = self.to_control.get_weave('inventory',
181
self.to_repository.get_transaction())
183
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
185
# just merge, this is optimisable and its means we dont
186
# copy unreferenced data such as not-needed inventories.
187
pb.update("fetch inventory", 1, 3)
188
from_weave = self.from_repository.get_inventory_weave()
189
pb.update("fetch inventory", 2, 3)
190
# we fetch only the referenced inventories because we do not
191
# know for unselected inventories whether all their required
192
# texts are present in the other repository - it could be
194
to_weave.join(from_weave, pb=child_pb, msg='merge inventory',
202
class GenericRepoFetcher(RepoFetcher):
203
"""This is a generic repo to repo fetcher.
205
This makes minimal assumptions about repo layout and contents.
206
It triggers a reconciliation after fetching to ensure integrity.
209
def _fetch_revision_texts(self, revs):
210
"""Fetch revision object texts"""
211
rev_pb = bzrlib.ui.ui_factory.nested_progress_bar()
213
to_txn = self.to_transaction = self.to_repository.get_transaction()
216
to_store = self.to_repository._revision_store
218
pb = bzrlib.ui.ui_factory.nested_progress_bar()
167
to_weave.join(from_weave)
168
except errors.WeaveParentMismatch:
169
to_weave.reweave(from_weave)
171
# destination is empty, just replace it
172
to_weave = from_weave.copy()
174
self.to_weaves.put_weave(file_id, to_weave,
175
self.to_repository.get_transaction())
178
def _fetch_inventory_weave(self, revs):
179
self.pb.update("inventory fetch", 0, 2)
180
from_weave = self.from_repository.get_inventory_weave()
181
to_weave = self.to_repository.get_inventory_weave()
182
self.pb.update("inventory fetch", 1, 2)
183
to_weave = self.to_control.get_weave('inventory',
184
self.to_repository.get_transaction())
185
self.pb.update("inventory fetch", 2, 2)
187
if to_weave.numversions() > 0:
188
# destination has contents, must merge
190
to_weave.join(from_weave, pb=self.pb, msg='merge inventory')
191
except errors.WeaveParentMismatch:
192
to_weave.reweave(from_weave, pb=self.pb, msg='reweave inventory')
194
# destination is empty, just replace it
195
to_weave = from_weave.copy()
197
self.to_control.put_weave('inventory', to_weave,
198
self.to_repository.get_transaction())
220
pb.update('copying revisions', count, total)
222
sig_text = self.from_repository.get_signature_text(rev)
223
to_store.add_revision_signature_text(rev, sig_text, to_txn)
224
except errors.NoSuchRevision:
227
to_store.add_revision(self.from_repository.get_revision(rev),
232
# fixup inventory if needed:
233
# this is expensive because we have no inverse index to current ghosts.
234
# but on local disk its a few seconds and sftp push is already insane.
236
# FIXME: repository should inform if this is needed.
237
self.to_repository.reconcile()
242
class KnitRepoFetcher(RepoFetcher):
243
"""This is a knit format repository specific fetcher.
245
This differs from the GenericRepoFetcher by not doing a
246
reconciliation after copying, and using knit joining to
250
def _fetch_revision_texts(self, revs):
251
# may need to be a InterRevisionStore call here.
252
from_transaction = self.from_repository.get_transaction()
253
to_transaction = self.to_repository.get_transaction()
254
to_sf = self.to_repository._revision_store.get_signature_file(
256
from_sf = self.from_repository._revision_store.get_signature_file(
258
to_sf.join(from_sf, version_ids=revs, ignore_missing=True)
259
to_rf = self.to_repository._revision_store.get_revision_file(
261
from_rf = self.from_repository._revision_store.get_revision_file(
263
to_rf.join(from_rf, version_ids=revs)
203
266
class Fetcher(object):
204
"""Pull revisions and texts from one branch to another.
206
This doesn't update the destination's history; that can be done
207
separately if desired.
210
If set, pull only up to this revision_id.
214
last_revision -- if last_revision
215
is given it will be that, otherwise the last revision of
218
count_copied -- number of revisions copied
220
count_weaves -- number of file weaves copied
267
"""Backwards compatability glue for branch.fetch()."""
269
@deprecated_method(zero_eight)
222
270
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
223
if to_branch.base == from_branch.base:
224
raise Exception("can't fetch from a branch to itself %s, %s" %
225
(from_branch.base, to_branch.base))
227
self.to_branch = to_branch
228
self.from_branch = from_branch
229
self._last_revision = last_revision
231
self.pb = bzrlib.ui.ui_factory.progress_bar()
234
self.from_branch.lock_read()
236
self.to_branch.lock_write()
240
self.to_branch.unlock()
242
self.from_branch.unlock()
245
self._find_last_revision()
246
repo_fetcher = RepoFetcher(to_repository=self.to_branch.repository,
247
from_repository=self.from_branch.repository,
249
last_revision=self._last_revision)
250
self.failed_revisions = repo_fetcher.failed_revisions
251
self.count_copied = repo_fetcher.count_copied
252
self.count_total = repo_fetcher.count_total
253
self.count_weaves = repo_fetcher.count_weaves
254
self.copied_file_ids = repo_fetcher.copied_file_ids
256
def _find_last_revision(self):
257
"""Find the limiting source revision.
259
Every ancestor of that revision will be merged across.
261
Returns the revision_id, or returns None if there's no history
262
in the source branch."""
263
if self._last_revision:
265
self.pb.update('get source history')
266
from_history = self.from_branch.revision_history()
267
self.pb.update('get destination history')
269
self._last_revision = from_history[-1]
271
# no history in the source branch
272
self._last_revision = NULL_REVISION
271
"""Please see branch.fetch()."""
272
to_branch.fetch(from_branch, last_revision, pb)