~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: Martin Pool
  • Date: 2006-03-22 18:03:25 UTC
  • mto: This revision was merged to the branch mainline in revision 1626.
  • Revision ID: mbp@sourcefrog.net-20060322180325-eff9250dcb85c390
Add missing selftest modules to setup.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33
33
 
34
34
import bzrlib
35
35
import bzrlib.errors as errors
36
 
from bzrlib.errors import (InstallFailed,
37
 
                           )
38
 
from bzrlib.progress import ProgressPhase
 
36
from bzrlib.errors import (InstallFailed, NoSuchRevision,
 
37
                           MissingText)
 
38
from bzrlib.trace import mutter
 
39
from bzrlib.progress import ProgressBar, ProgressPhase
 
40
from bzrlib.reconcile import RepoReconciler
39
41
from bzrlib.revision import NULL_REVISION
40
 
from bzrlib.symbol_versioning import (deprecated_function,
41
 
        deprecated_method,
42
 
        zero_eight,
43
 
        )
44
 
from bzrlib.trace import mutter
45
 
import bzrlib.ui
 
42
from bzrlib.symbol_versioning import *
46
43
 
47
 
from bzrlib.lazy_import import lazy_import
48
44
 
49
45
# TODO: Avoid repeatedly opening weaves so many times.
50
46
 
128
124
        self.from_control = self.from_repository.control_weaves
129
125
        self.count_total = 0
130
126
        self.file_ids_names = {}
131
 
        pp = ProgressPhase('Fetch phase', 4, self.pb)
 
127
        pp = ProgressPhase('fetch phase', 4, self.pb)
132
128
        try:
133
 
            pp.next_phase()
134
129
            revs = self._revids_to_fetch()
135
130
            # something to do ?
136
131
            if revs:
149
144
        if self._last_revision is NULL_REVISION:
150
145
            # explicit limit of no revisions needed
151
146
            return None
152
 
        if (self._last_revision is not None and
 
147
        if (self._last_revision != None and
153
148
            self.to_repository.has_revision(self._last_revision)):
154
149
            return None
155
150
            
162
157
    def _fetch_weave_texts(self, revs):
163
158
        texts_pb = bzrlib.ui.ui_factory.nested_progress_bar()
164
159
        try:
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()
169
 
            inv_w.enable_cache()
170
 
            file_ids = self.from_repository.fileids_altered_by_revision_ids(revs)
 
160
            file_ids = self.from_repository.fileid_involved_by_set(revs)
171
161
            count = 0
172
162
            num_file_ids = len(file_ids)
173
 
            for file_id, required_versions in file_ids.items():
 
163
            for file_id in file_ids:
174
164
                texts_pb.update("fetch texts", count, num_file_ids)
175
165
                count +=1
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
187
 
                # end anyhow.
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()
 
166
                try:
 
167
                    to_weave = self.to_weaves.get_weave(file_id,
 
168
                        self.to_repository.get_transaction())
 
169
                except errors.NoSuchFile:
 
170
                    # destination is empty, just copy it.
 
171
                    # this copies all the texts, which is useful and 
 
172
                    # on per-file basis quite cheap.
 
173
                    self.to_weaves.copy_multi(
 
174
                        self.from_weaves,
 
175
                        [file_id],
 
176
                        None,
 
177
                        self.from_repository.get_transaction(),
 
178
                        self.to_repository.get_transaction())
 
179
                else:
 
180
                    # destination has contents, must merge
 
181
                    from_weave = self.from_weaves.get_weave(file_id,
 
182
                        self.from_repository.get_transaction())
 
183
                    # we fetch all the texts, because texts do
 
184
                    # not reference anything, and its cheap enough
 
185
                    to_weave.join(from_weave)
192
186
        finally:
193
187
            texts_pb.finished()
194
188
 
201
195
    
202
196
            child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
203
197
            try:
204
 
                # just merge, this is optimisable and its means we don't
 
198
                # just merge, this is optimisable and its means we dont
205
199
                # copy unreferenced data such as not-needed inventories.
206
200
                pb.update("fetch inventory", 1, 3)
207
201
                from_weave = self.from_repository.get_inventory_weave()
212
206
                # corrupt.
213
207
                to_weave.join(from_weave, pb=child_pb, msg='merge inventory',
214
208
                              version_ids=revs)
215
 
                from_weave.clear_cache()
216
209
            finally:
217
210
                child_pb.finished()
218
211
        finally:
283
276
        to_rf.join(from_rf, version_ids=revs)
284
277
 
285
278
 
286
 
class Inter1and2Helper(object):
287
 
    """Helper for operations that convert data from model 1 and 2
288
 
    
289
 
    This is for use by fetchers and converters.
290
 
    """
291
 
 
292
 
    def __init__(self, source, target):
293
 
        """Constructor.
294
 
 
295
 
        :param source: The repository data comes from
296
 
        :param target: The repository data goes to
297
 
        """
298
 
        self.source = source
299
 
        self.target = target
300
 
 
301
 
    def iter_rev_trees(self, revs):
302
 
        """Iterate through RevisionTrees efficiently.
303
 
 
304
 
        Additionally, the inventory's revision_id is set if unset.
305
 
 
306
 
        Trees are retrieved in batches of 100, and then yielded in the order
307
 
        they were requested.
308
 
 
309
 
        :param revs: A list of revision ids
310
 
        """
311
 
        while revs:
312
 
            for tree in self.source.revision_trees(revs[:100]):
313
 
                if tree.inventory.revision_id is None:
314
 
                    tree.inventory.revision_id = tree.get_revision_id()
315
 
                yield tree
316
 
            revs = revs[100:]
317
 
 
318
 
    def generate_root_texts(self, revs):
319
 
        """Generate VersionedFiles for all root ids.
320
 
        
321
 
        :param revs: the revisions to include
322
 
        """
323
 
        inventory_weave = self.source.get_inventory_weave()
324
 
        parent_texts = {}
325
 
        versionedfile = {}
326
 
        to_store = self.target.weave_store
327
 
        for tree in self.iter_rev_trees(revs):
328
 
            revision_id = tree.inventory.root.revision
329
 
            root_id = tree.inventory.root.file_id
330
 
            parents = inventory_weave.get_parents(revision_id)
331
 
            if root_id not in versionedfile:
332
 
                versionedfile[root_id] = to_store.get_weave_or_empty(root_id, 
333
 
                    self.target.get_transaction())
334
 
            parent_texts[root_id] = versionedfile[root_id].add_lines(
335
 
                revision_id, parents, [], parent_texts)
336
 
 
337
 
    def regenerate_inventory(self, revs):
338
 
        """Generate a new inventory versionedfile in target, convertin data.
339
 
        
340
 
        The inventory is retrieved from the source, (deserializing it), and
341
 
        stored in the target (reserializing it in a different format).
342
 
        :param revs: The revisions to include
343
 
        """
344
 
        inventory_weave = self.source.get_inventory_weave()
345
 
        for tree in self.iter_rev_trees(revs):
346
 
            parents = inventory_weave.get_parents(tree.get_revision_id())
347
 
            self.target.add_inventory(tree.get_revision_id(), tree.inventory,
348
 
                                      parents)
349
 
 
350
 
 
351
 
class Model1toKnit2Fetcher(GenericRepoFetcher):
352
 
    """Fetch from a Model1 repository into a Knit2 repository
353
 
    """
354
 
    def __init__(self, to_repository, from_repository, last_revision=None, 
355
 
                 pb=None):
356
 
        self.helper = Inter1and2Helper(from_repository, to_repository)
357
 
        GenericRepoFetcher.__init__(self, to_repository, from_repository,
358
 
                                    last_revision, pb)
359
 
 
360
 
    def _fetch_weave_texts(self, revs):
361
 
        GenericRepoFetcher._fetch_weave_texts(self, revs)
362
 
        # Now generate a weave for the tree root
363
 
        self.helper.generate_root_texts(revs)
364
 
 
365
 
    def _fetch_inventory_weave(self, revs):
366
 
        self.helper.regenerate_inventory(revs)
367
 
 
368
 
 
369
 
class Knit1to2Fetcher(KnitRepoFetcher):
370
 
    """Fetch from a Knit1 repository into a Knit2 repository"""
371
 
 
372
 
    def __init__(self, to_repository, from_repository, last_revision=None, 
373
 
                 pb=None):
374
 
        self.helper = Inter1and2Helper(from_repository, to_repository)
375
 
        KnitRepoFetcher.__init__(self, to_repository, from_repository,
376
 
                                 last_revision, pb)
377
 
 
378
 
    def _fetch_weave_texts(self, revs):
379
 
        KnitRepoFetcher._fetch_weave_texts(self, revs)
380
 
        # Now generate a weave for the tree root
381
 
        self.helper.generate_root_texts(revs)
382
 
 
383
 
    def _fetch_inventory_weave(self, revs):
384
 
        self.helper.regenerate_inventory(revs)
385
 
        
386
 
 
387
279
class Fetcher(object):
388
 
    """Backwards compatibility glue for branch.fetch()."""
 
280
    """Backwards compatability glue for branch.fetch()."""
389
281
 
390
282
    @deprecated_method(zero_eight)
391
283
    def __init__(self, to_branch, from_branch, last_revision=None, pb=None):