~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: Martin Pool
  • Date: 2006-03-10 06:29:53 UTC
  • mfrom: (1608 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1611.
  • Revision ID: mbp@sourcefrog.net-20060310062953-bc1c7ade75c89a7a
[merge] bzr.dev; pycurl not updated for readv yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
add a revision to the store until everything it refers to is also
27
27
stored, so that if a revision is present we can totally recreate it.
28
28
However, we can't know what files are included in a revision until we
29
 
read its inventory.  Therefore, we first pull the XML and hold it in
30
 
memory until we've updated all of the files referenced.
 
29
read its inventory.  So we query the inventory store of the source for
 
30
the ids we need, and then pull those ids and finally actually join
 
31
the inventories.
31
32
"""
32
33
 
33
34
import bzrlib
34
35
import bzrlib.errors as errors
35
 
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
 
36
from bzrlib.errors import (InstallFailed, NoSuchRevision,
36
37
                           MissingText)
37
38
from bzrlib.trace import mutter
38
39
from bzrlib.progress import ProgressBar
94
95
        # must not mutate self._last_revision as its potentially a shared instance
95
96
        self._last_revision = last_revision
96
97
        if pb is None:
97
 
            self.pb = bzrlib.ui.ui_factory.progress_bar()
 
98
            self.pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
99
            self.nested_pb = self.pb
98
100
        else:
99
101
            self.pb = pb
 
102
            self.nested_pb = None
100
103
        self.from_repository.lock_read()
101
104
        try:
102
105
            self.to_repository.lock_write()
103
106
            try:
104
107
                self.__fetch()
105
108
            finally:
 
109
                if self.nested_pb is not None:
 
110
                    self.nested_pb.finished()
106
111
                self.to_repository.unlock()
107
112
        finally:
108
113
            self.from_repository.unlock()
146
151
        except errors.NoSuchRevision:
147
152
            raise InstallFailed([self._last_revision])
148
153
 
149
 
    def _fetch_revision_texts(self, revs):
150
 
        self.to_repository.revision_store.copy_multi(
151
 
            self.from_repository.revision_store,
152
 
            revs,
153
 
            pb=self.pb)
154
 
        # fixup inventory if needed:
155
 
        # this is expensive because we have no inverse index to current ghosts.
156
 
        # but on local disk its a few seconds and sftp push is already insane.
157
 
        # so we just-do-it.
158
 
        # FIXME: the generic code path should not need this, if it truely is
159
 
        # generic.
160
 
        reconciler = RepoReconciler(self.to_repository)
161
 
        reconciler.reconcile()
162
 
 
163
154
    def _fetch_weave_texts(self, revs):
164
155
        file_ids = self.from_repository.fileid_involved_by_set(revs)
165
156
        count = 0
169
160
            count +=1
170
161
            to_weave = self.to_weaves.get_weave_or_empty(file_id,
171
162
                self.to_repository.get_transaction())
172
 
            from_weave = self.from_weaves.get_weave(file_id,
173
 
                self.from_repository.get_transaction())
174
163
 
175
 
            if to_weave.numversions() > 0:
 
164
            if to_weave.num_versions() > 0:
176
165
                # destination has contents, must merge
177
 
                try:
178
 
                    to_weave.join(from_weave)
179
 
                except errors.WeaveParentMismatch:
180
 
                    to_weave.reweave(from_weave)
 
166
                from_weave = self.from_weaves.get_weave(file_id,
 
167
                    self.from_repository.get_transaction())
 
168
                # we fetch all the texts, because texts do
 
169
                # not reference anything, and its cheap enough
 
170
                to_weave.join(from_weave)
181
171
            else:
182
 
                # destination is empty, just replace it
183
 
                to_weave = from_weave.copy()
184
 
 
185
 
            self.to_weaves.put_weave(file_id, to_weave,
186
 
                self.to_repository.get_transaction())
 
172
                # destination is empty, just copy it.
 
173
                # this copies all the texts, which is useful and 
 
174
                # on per-file basis quite cheap.
 
175
                self.to_weaves.copy_multi(self.from_weaves, [file_id], self.pb,
 
176
                                          self.from_repository.get_transaction(),
 
177
                                          self.to_repository.get_transaction())
187
178
        self.pb.clear()
188
179
 
189
180
    def _fetch_inventory_weave(self, revs):
190
181
        self.pb.update("inventory fetch", 0, 2)
 
182
        to_weave = self.to_control.get_weave('inventory',
 
183
                self.to_repository.get_transaction())
 
184
 
 
185
        # just merge, this is optimisable and its means we dont
 
186
        # copy unreferenced data such as not-needed inventories.
 
187
        self.pb.update("inventory fetch", 1, 2)
191
188
        from_weave = self.from_repository.get_inventory_weave()
192
 
        self.to_inventory_weave = self.to_repository.get_inventory_weave()
193
 
        self.pb.update("inventory fetch", 1, 2)
194
 
        self.to_inventory_weave = self.to_control.get_weave('inventory',
195
 
                self.to_repository.get_transaction())
196
189
        self.pb.update("inventory fetch", 2, 2)
197
 
 
198
 
        if self.to_inventory_weave.numversions() > 0:
199
 
            # destination has contents, must merge
 
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
 
193
        # corrupt.
 
194
        to_weave.join(from_weave, pb=self.pb, msg='merge inventory',
 
195
                      version_ids=revs)
 
196
        self.pb.clear()
 
197
 
 
198
 
 
199
class GenericRepoFetcher(RepoFetcher):
 
200
    """This is a generic repo to repo fetcher.
 
201
 
 
202
    This makes minimal assumptions about repo layout and contents.
 
203
    It triggers a reconciliation after fetching to ensure integrity.
 
204
    """
 
205
 
 
206
    def _fetch_revision_texts(self, revs):
 
207
        self.to_transaction = self.to_repository.get_transaction()
 
208
        count = 0
 
209
        total = len(revs)
 
210
        for rev in revs:
 
211
            self.pb.update('copying revisions', count, total)
200
212
            try:
201
 
                self.to_inventory_weave.join(from_weave, pb=self.pb, msg='merge inventory')
202
 
            except errors.WeaveParentMismatch:
203
 
                self.to_inventory_weave.reweave(from_weave, pb=self.pb, msg='reweave inventory')
204
 
        else:
205
 
            # destination is empty, just replace it
206
 
            self.to_inventory_weave = from_weave.copy()
207
 
 
208
 
        # must be written before pulling any revisions
209
 
        self.to_control.put_weave('inventory', self.to_inventory_weave,
210
 
            self.to_repository.get_transaction())
211
 
 
212
 
        self.pb.clear()
 
213
                sig_text = self.from_repository.get_signature_text(rev)
 
214
                self.to_repository._revision_store.add_revision_signature_text(
 
215
                    rev, sig_text, self.to_transaction)
 
216
            except errors.NoSuchRevision:
 
217
                # not signed.
 
218
                pass
 
219
            self.to_repository._revision_store.add_revision(
 
220
                self.from_repository.get_revision(rev),
 
221
                self.to_transaction)
 
222
            count += 1
 
223
        self.pb.update('copying revisions', count, total)
 
224
        # fixup inventory if needed: 
 
225
        # this is expensive because we have no inverse index to current ghosts.
 
226
        # but on local disk its a few seconds and sftp push is already insane.
 
227
        # so we just-do-it.
 
228
        # FIXME: repository should inform if this is needed.
 
229
        self.to_repository.reconcile()
 
230
    
 
231
 
 
232
class KnitRepoFetcher(RepoFetcher):
 
233
    """This is a knit format repository specific fetcher.
 
234
 
 
235
    This differs from the GenericRepoFetcher by not doing a 
 
236
    reconciliation after copying, and using knit joining to
 
237
    copy revision texts.
 
238
    """
 
239
 
 
240
    def _fetch_revision_texts(self, revs):
 
241
        # may need to be a InterRevisionStore call here.
 
242
        from_transaction = self.from_repository.get_transaction()
 
243
        to_transaction = self.to_repository.get_transaction()
 
244
        to_sf = self.to_repository._revision_store.get_signature_file(
 
245
            to_transaction)
 
246
        from_sf = self.from_repository._revision_store.get_signature_file(
 
247
            from_transaction)
 
248
        to_sf.join(from_sf, version_ids=revs, pb=self.pb, ignore_missing=True)
 
249
        to_rf = self.to_repository._revision_store.get_revision_file(
 
250
            to_transaction)
 
251
        from_rf = self.from_repository._revision_store.get_revision_file(
 
252
            from_transaction)
 
253
        to_rf.join(from_rf, version_ids=revs, pb=self.pb)
213
254
 
214
255
 
215
256
class Fetcher(object):