154
144
except errors.NoSuchRevision:
155
145
raise InstallFailed([self._last_revision])
147
def _fetch_revision_texts(self, revs):
148
self.to_repository.revision_store.copy_multi(
149
self.from_repository.revision_store,
157
153
def _fetch_weave_texts(self, revs):
158
texts_pb = bzrlib.ui.ui_factory.nested_progress_bar()
160
file_ids = self.from_repository.fileids_altered_by_revision_ids(revs)
162
num_file_ids = len(file_ids)
163
for file_id, required_versions in file_ids.items():
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, version_ids=required_versions)
173
# we don't need *all* of this data anymore, but we dont know
174
# what we do. This cache clearing will result in a new read
175
# of the knit data when we do the checkout, but probably we
176
# want to emit the needed data on the fly rather than at the
178
# the from weave should know not to cache data being joined,
179
# but its ok to ask it to clear.
180
from_weave.clear_cache()
181
to_weave.clear_cache()
154
file_ids = self.from_repository.fileid_involved_by_set(revs)
156
num_file_ids = len(file_ids)
157
for file_id in file_ids:
158
self.pb.update("merge weaves", count, num_file_ids)
160
to_weave = self.to_weaves.get_weave_or_empty(file_id,
161
self.to_repository.get_transaction())
162
from_weave = self.from_weaves.get_weave(file_id,
163
self.from_repository.get_transaction())
165
if to_weave.numversions() > 0:
166
# destination has contents, must merge
168
to_weave.join(from_weave)
169
except errors.WeaveParentMismatch:
170
to_weave.reweave(from_weave)
172
# destination is empty, just replace it
173
to_weave = from_weave.copy()
175
self.to_weaves.put_weave(file_id, to_weave,
176
self.to_repository.get_transaction())
185
179
def _fetch_inventory_weave(self, revs):
186
pb = bzrlib.ui.ui_factory.nested_progress_bar()
188
pb.update("fetch inventory", 0, 2)
189
to_weave = self.to_control.get_weave('inventory',
190
self.to_repository.get_transaction())
192
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
180
self.pb.update("inventory fetch", 0, 2)
181
from_weave = self.from_repository.get_inventory_weave()
182
to_weave = self.to_repository.get_inventory_weave()
183
self.pb.update("inventory fetch", 1, 2)
184
to_weave = self.to_control.get_weave('inventory',
185
self.to_repository.get_transaction())
186
self.pb.update("inventory fetch", 2, 2)
188
if to_weave.numversions() > 0:
189
# destination has contents, must merge
194
# just merge, this is optimisable and its means we don't
195
# copy unreferenced data such as not-needed inventories.
196
pb.update("fetch inventory", 1, 3)
197
from_weave = self.from_repository.get_inventory_weave()
198
pb.update("fetch inventory", 2, 3)
199
# we fetch only the referenced inventories because we do not
200
# know for unselected inventories whether all their required
201
# texts are present in the other repository - it could be
203
to_weave.join(from_weave, pb=child_pb, msg='merge inventory',
211
class GenericRepoFetcher(RepoFetcher):
212
"""This is a generic repo to repo fetcher.
214
This makes minimal assumptions about repo layout and contents.
215
It triggers a reconciliation after fetching to ensure integrity.
218
def _fetch_revision_texts(self, revs):
219
"""Fetch revision object texts"""
220
rev_pb = bzrlib.ui.ui_factory.nested_progress_bar()
222
to_txn = self.to_transaction = self.to_repository.get_transaction()
225
to_store = self.to_repository._revision_store
227
pb = bzrlib.ui.ui_factory.nested_progress_bar()
229
pb.update('copying revisions', count, total)
231
sig_text = self.from_repository.get_signature_text(rev)
232
to_store.add_revision_signature_text(rev, sig_text, to_txn)
233
except errors.NoSuchRevision:
236
to_store.add_revision(self.from_repository.get_revision(rev),
241
# fixup inventory if needed:
242
# this is expensive because we have no inverse index to current ghosts.
243
# but on local disk its a few seconds and sftp push is already insane.
245
# FIXME: repository should inform if this is needed.
246
self.to_repository.reconcile()
251
class KnitRepoFetcher(RepoFetcher):
252
"""This is a knit format repository specific fetcher.
254
This differs from the GenericRepoFetcher by not doing a
255
reconciliation after copying, and using knit joining to
259
def _fetch_revision_texts(self, revs):
260
# may need to be a InterRevisionStore call here.
261
from_transaction = self.from_repository.get_transaction()
262
to_transaction = self.to_repository.get_transaction()
263
to_sf = self.to_repository._revision_store.get_signature_file(
265
from_sf = self.from_repository._revision_store.get_signature_file(
267
to_sf.join(from_sf, version_ids=revs, ignore_missing=True)
268
to_rf = self.to_repository._revision_store.get_revision_file(
270
from_rf = self.from_repository._revision_store.get_revision_file(
272
to_rf.join(from_rf, version_ids=revs)
191
to_weave.join(from_weave, pb=self.pb, msg='merge inventory')
192
except errors.WeaveParentMismatch:
193
to_weave.reweave(from_weave, pb=self.pb, msg='reweave inventory')
195
# destination is empty, just replace it
196
to_weave = from_weave.copy()
198
self.to_control.put_weave('inventory', to_weave,
199
self.to_repository.get_transaction())
275
204
class Fetcher(object):
276
"""Backwards compatibility glue for branch.fetch()."""
278
@deprecated_method(zero_eight)
205
"""Pull revisions and texts from one branch to another.
207
This doesn't update the destination's history; that can be done
208
separately if desired.
211
If set, pull only up to this revision_id.
215
last_revision -- if last_revision
216
is given it will be that, otherwise the last revision of
219
count_copied -- number of revisions copied
221
count_weaves -- number of file weaves copied
279
223
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
280
"""Please see branch.fetch()."""
281
to_branch.fetch(from_branch, last_revision, pb)
224
if to_branch.base == from_branch.base:
225
raise Exception("can't fetch from a branch to itself %s, %s" %
226
(from_branch.base, to_branch.base))
228
self.to_branch = to_branch
229
self.from_branch = from_branch
230
self._last_revision = last_revision
232
self.pb = bzrlib.ui.ui_factory.progress_bar()
235
self.from_branch.lock_read()
237
self.to_branch.lock_write()
241
self.to_branch.unlock()
243
self.from_branch.unlock()
246
self._find_last_revision()
247
repo_fetcher = RepoFetcher(to_repository=self.to_branch.repository,
248
from_repository=self.from_branch.repository,
250
last_revision=self._last_revision)
251
self.failed_revisions = repo_fetcher.failed_revisions
252
self.count_copied = repo_fetcher.count_copied
253
self.count_total = repo_fetcher.count_total
254
self.count_weaves = repo_fetcher.count_weaves
255
self.copied_file_ids = repo_fetcher.copied_file_ids
257
def _find_last_revision(self):
258
"""Find the limiting source revision.
260
Every ancestor of that revision will be merged across.
262
Returns the revision_id, or returns None if there's no history
263
in the source branch."""
264
if self._last_revision:
266
self.pb.update('get source history')
267
from_history = self.from_branch.revision_history()
268
self.pb.update('get destination history')
270
self._last_revision = from_history[-1]
272
# no history in the source branch
273
self._last_revision = NULL_REVISION