83
73
count_copied -- number of revisions copied
85
This should not be used directory, its essential a object to encapsulate
75
This should not be used directly, it's essential a object to encapsulate
86
76
the logic in InterRepository.fetch().
88
78
def __init__(self, to_repository, from_repository, last_revision=None, pb=None):
89
79
# result variables.
90
80
self.failed_revisions = []
91
81
self.count_copied = 0
92
if to_repository.control_files._transport.base == from_repository.control_files._transport.base:
93
# check that last_revision is in 'from' and then return a no-operation.
94
if last_revision not in (None, NULL_REVISION):
95
from_repository.get_revision(last_revision)
82
if to_repository.has_same_location(from_repository):
83
# repository.fetch should be taking care of this case.
84
raise errors.BzrError('RepoFetcher run '
85
'between two objects at the same location: '
86
'%r and %r' % (to_repository, from_repository))
97
87
self.to_repository = to_repository
98
88
self.from_repository = from_repository
99
89
# must not mutate self._last_revision as its potentially a shared instance
123
120
requested revisions, finally clearing the progress bar.
125
122
self.to_weaves = self.to_repository.weave_store
126
self.to_control = self.to_repository.control_weaves
127
123
self.from_weaves = self.from_repository.weave_store
128
self.from_control = self.from_repository.control_weaves
129
124
self.count_total = 0
130
125
self.file_ids_names = {}
131
pp = ProgressPhase('Fetch phase', 4, self.pb)
126
pp = ProgressPhase('Transferring', 4, self.pb)
134
129
revs = self._revids_to_fetch()
138
self._fetch_weave_texts(revs)
140
self._fetch_inventory_weave(revs)
142
self._fetch_revision_texts(revs)
143
self.count_copied += len(revs)
132
self._fetch_everything_for_revisions(revs, pp)
136
def _fetch_everything_for_revisions(self, revs, pp):
137
"""Fetch all data for the given set of revisions."""
138
# The first phase is "file". We pass the progress bar for it directly
139
# into item_keys_introduced_by, which has more information about how
140
# that phase is progressing than we do. Progress updates for the other
141
# phases are taken care of in this function.
142
# XXX: there should be a clear owner of the progress reporting. Perhaps
143
# item_keys_introduced_by should have a richer API than it does at the
144
# moment, so that it can feed the progress information back to this
147
pb = bzrlib.ui.ui_factory.nested_progress_bar()
149
data_to_fetch = self.from_repository.item_keys_introduced_by(revs, pb)
150
for knit_kind, file_id, revisions in data_to_fetch:
151
if knit_kind != phase:
153
# Make a new progress bar for this phase
156
pb = bzrlib.ui.ui_factory.nested_progress_bar()
157
if knit_kind == "file":
158
self._fetch_weave_text(file_id, revisions)
159
elif knit_kind == "inventory":
161
# Once we've processed all the files, then we generate the root
162
# texts (if necessary), then we process the inventory. It's a
163
# bit distasteful to have knit_kind == "inventory" mean this,
164
# perhaps it should happen on the first non-"file" knit, in case
165
# it's not always inventory?
166
self._generate_root_texts(revs)
167
self._fetch_inventory_weave(revs, pb)
168
elif knit_kind == "signatures":
169
# Nothing to do here; this will be taken care of when
170
# _fetch_revision_texts happens.
172
elif knit_kind == "revisions":
173
self._fetch_revision_texts(revs, pb)
175
raise AssertionError("Unknown knit kind %r" % knit_kind)
179
self.count_copied += len(revs)
147
181
def _revids_to_fetch(self):
182
"""Determines the exact revisions needed from self.from_repository to
183
install self._last_revision in self.to_repository.
185
If no revisions need to be fetched, then this just returns None.
148
187
mutter('fetch up to rev {%s}', self._last_revision)
149
188
if self._last_revision is NULL_REVISION:
150
189
# explicit limit of no revisions needed
196
# XXX: this gets the full graph on both sides, and will make sure
197
# that ghosts are filled whether or not you care about them.
157
198
return self.to_repository.missing_revision_ids(self.from_repository,
158
199
self._last_revision)
159
200
except errors.NoSuchRevision:
160
201
raise InstallFailed([self._last_revision])
162
def _fetch_weave_texts(self, revs):
163
texts_pb = bzrlib.ui.ui_factory.nested_progress_bar()
165
# fileids_altered_by_revision_ids requires reading the inventory
166
# weave, we will need to read the inventory weave again when
167
# all this is done, so enable caching for that specific weave
168
inv_w = self.from_repository.get_inventory_weave()
170
file_ids = self.from_repository.fileids_altered_by_revision_ids(revs)
172
num_file_ids = len(file_ids)
173
for file_id, required_versions in file_ids.items():
174
texts_pb.update("fetch texts", count, num_file_ids)
176
to_weave = self.to_weaves.get_weave_or_empty(file_id,
177
self.to_repository.get_transaction())
178
from_weave = self.from_weaves.get_weave(file_id,
179
self.from_repository.get_transaction())
180
# we fetch all the texts, because texts do
181
# not reference anything, and its cheap enough
182
to_weave.join(from_weave, version_ids=required_versions)
183
# we don't need *all* of this data anymore, but we dont know
184
# what we do. This cache clearing will result in a new read
185
# of the knit data when we do the checkout, but probably we
186
# want to emit the needed data on the fly rather than at the
188
# the from weave should know not to cache data being joined,
189
# but its ok to ask it to clear.
190
from_weave.clear_cache()
191
to_weave.clear_cache()
195
def _fetch_inventory_weave(self, revs):
196
pb = bzrlib.ui.ui_factory.nested_progress_bar()
198
pb.update("fetch inventory", 0, 2)
199
to_weave = self.to_control.get_weave('inventory',
200
self.to_repository.get_transaction())
202
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
204
# just merge, this is optimisable and its means we don't
205
# copy unreferenced data such as not-needed inventories.
206
pb.update("fetch inventory", 1, 3)
207
from_weave = self.from_repository.get_inventory_weave()
208
pb.update("fetch inventory", 2, 3)
209
# we fetch only the referenced inventories because we do not
210
# know for unselected inventories whether all their required
211
# texts are present in the other repository - it could be
213
to_weave.join(from_weave, pb=child_pb, msg='merge inventory',
215
from_weave.clear_cache()
203
def _fetch_weave_text(self, file_id, required_versions):
204
to_weave = self.to_weaves.get_weave_or_empty(file_id,
205
self.to_repository.get_transaction())
206
from_weave = self.from_weaves.get_weave(file_id,
207
self.from_repository.get_transaction())
208
# we fetch all the texts, because texts do
209
# not reference anything, and its cheap enough
210
to_weave.join(from_weave, version_ids=required_versions)
211
# we don't need *all* of this data anymore, but we dont know
212
# what we do. This cache clearing will result in a new read
213
# of the knit data when we do the checkout, but probably we
214
# want to emit the needed data on the fly rather than at the
216
# the from weave should know not to cache data being joined,
217
# but its ok to ask it to clear.
218
from_weave.clear_cache()
219
to_weave.clear_cache()
221
def _fetch_inventory_weave(self, revs, pb):
222
pb.update("fetch inventory", 0, 2)
223
to_weave = self.to_repository.get_inventory_weave()
224
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
226
# just merge, this is optimisable and its means we don't
227
# copy unreferenced data such as not-needed inventories.
228
pb.update("fetch inventory", 1, 3)
229
from_weave = self.from_repository.get_inventory_weave()
230
pb.update("fetch inventory", 2, 3)
231
# we fetch only the referenced inventories because we do not
232
# know for unselected inventories whether all their required
233
# texts are present in the other repository - it could be
235
to_weave.join(from_weave, pb=child_pb, msg='merge inventory',
237
from_weave.clear_cache()
241
def _generate_root_texts(self, revs):
242
"""This will be called by __fetch between fetching weave texts and
243
fetching the inventory weave.
245
Subclasses should override this if they need to generate root texts
246
after fetching weave texts.
222
251
class GenericRepoFetcher(RepoFetcher):
226
255
It triggers a reconciliation after fetching to ensure integrity.
229
def _fetch_revision_texts(self, revs):
258
def _fetch_revision_texts(self, revs, pb):
230
259
"""Fetch revision object texts"""
231
rev_pb = bzrlib.ui.ui_factory.nested_progress_bar()
233
to_txn = self.to_transaction = self.to_repository.get_transaction()
236
to_store = self.to_repository._revision_store
238
pb = bzrlib.ui.ui_factory.nested_progress_bar()
240
pb.update('copying revisions', count, total)
242
sig_text = self.from_repository.get_signature_text(rev)
243
to_store.add_revision_signature_text(rev, sig_text, to_txn)
244
except errors.NoSuchRevision:
247
to_store.add_revision(self.from_repository.get_revision(rev),
252
# fixup inventory if needed:
253
# this is expensive because we have no inverse index to current ghosts.
254
# but on local disk its a few seconds and sftp push is already insane.
256
# FIXME: repository should inform if this is needed.
257
self.to_repository.reconcile()
260
to_txn = self.to_transaction = self.to_repository.get_transaction()
263
to_store = self.to_repository._revision_store
265
pb.update('copying revisions', count, total)
267
sig_text = self.from_repository.get_signature_text(rev)
268
to_store.add_revision_signature_text(rev, sig_text, to_txn)
269
except errors.NoSuchRevision:
272
to_store.add_revision(self.from_repository.get_revision(rev),
275
# fixup inventory if needed:
276
# this is expensive because we have no inverse index to current ghosts.
277
# but on local disk its a few seconds and sftp push is already insane.
279
# FIXME: repository should inform if this is needed.
280
self.to_repository.reconcile()
262
283
class KnitRepoFetcher(RepoFetcher):
375
394
KnitRepoFetcher.__init__(self, to_repository, from_repository,
376
395
last_revision, pb)
378
def _fetch_weave_texts(self, revs):
379
KnitRepoFetcher._fetch_weave_texts(self, revs)
380
# Now generate a weave for the tree root
397
def _generate_root_texts(self, revs):
381
398
self.helper.generate_root_texts(revs)
383
def _fetch_inventory_weave(self, revs):
400
def _fetch_inventory_weave(self, revs, pb):
384
401
self.helper.regenerate_inventory(revs)
387
class Fetcher(object):
388
"""Backwards compatibility glue for branch.fetch()."""
390
@deprecated_method(zero_eight)
391
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
392
"""Please see branch.fetch()."""
393
to_branch.fetch(from_branch, last_revision, pb)
404
class RemoteToOtherFetcher(GenericRepoFetcher):
406
def _fetch_everything_for_revisions(self, revs, pp):
407
data_stream = self.from_repository.get_data_stream(revs)
408
self.to_repository.insert_data_stream(data_stream)