/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: John Arbash Meinel
  • Date: 2011-03-15 10:28:20 UTC
  • mto: This revision was merged to the branch mainline in revision 5725.
  • Revision ID: john@arbash-meinel.com-20110315102820-51wy8wjre5ol34mu
'bzr export' needs to use 'exact' encoding.

If we are going to be writing binary bites out of stdout, then it needs to
be in binary mode, or it will corrupt the data stream.
Oddly enough, it only seemed to fail if we set '--verbose'. I didn't
bother to track into that bug.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
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
28
28
from bzrlib.lazy_import import lazy_import
29
29
lazy_import(globals(), """
30
30
from bzrlib import (
 
31
    graph,
31
32
    tsort,
32
33
    versionedfile,
33
34
    )
54
55
 
55
56
        :param last_revision: If set, try to limit to the data this revision
56
57
            references.
 
58
        :param fetch_spec: A SearchResult specifying which revisions to fetch.
 
59
            If set, this overrides last_revision.
57
60
        :param find_ghosts: If True search the entire history for ghosts.
58
61
        """
59
62
        # repository.fetch has the responsibility for short-circuiting
92
95
        pb.show_pct = pb.show_count = False
93
96
        try:
94
97
            pb.update("Finding revisions", 0, 2)
95
 
            search = self._revids_to_fetch()
96
 
            if search is None:
 
98
            search_result = self._revids_to_fetch()
 
99
            mutter('fetching: %s', search_result)
 
100
            if search_result.is_empty():
97
101
                return
98
102
            pb.update("Fetching revisions", 1, 2)
99
 
            self._fetch_everything_for_search(search)
 
103
            self._fetch_everything_for_search(search_result)
100
104
        finally:
101
105
            pb.finished()
102
106
 
125
129
            pb.update("Inserting stream")
126
130
            resume_tokens, missing_keys = self.sink.insert_stream(
127
131
                stream, from_format, [])
128
 
            if self.to_repository._fallback_repositories:
129
 
                missing_keys.update(
130
 
                    self._parent_inventories(search.get_keys()))
131
132
            if missing_keys:
132
133
                pb.update("Missing keys")
133
134
                stream = source.get_stream_for_missing_keys(missing_keys)
151
152
        """Determines the exact revisions needed from self.from_repository to
152
153
        install self._last_revision in self.to_repository.
153
154
 
154
 
        If no revisions need to be fetched, then this just returns None.
 
155
        :returns: A SearchResult of some sort.  (Possibly a
 
156
            PendingAncestryResult, EmptySearchResult, etc.)
155
157
        """
156
158
        if self._fetch_spec is not None:
 
159
            # The fetch spec is already a concrete search result.
157
160
            return self._fetch_spec
158
 
        mutter('fetch up to rev {%s}', self._last_revision)
159
 
        if self._last_revision is NULL_REVISION:
 
161
        elif self._last_revision == NULL_REVISION:
 
162
            # fetch_spec is None + last_revision is null => empty fetch.
160
163
            # explicit limit of no revisions needed
161
 
            return None
162
 
        return self.to_repository.search_missing_revision_ids(
163
 
            self.from_repository, self._last_revision,
164
 
            find_ghosts=self.find_ghosts)
165
 
 
166
 
    def _parent_inventories(self, revision_ids):
167
 
        # Find all the parent revisions referenced by the stream, but
168
 
        # not present in the stream, and make sure we send their
169
 
        # inventories.
170
 
        parent_maps = self.to_repository.get_parent_map(revision_ids)
171
 
        parents = set()
172
 
        map(parents.update, parent_maps.itervalues())
173
 
        parents.discard(NULL_REVISION)
174
 
        parents.difference_update(revision_ids)
175
 
        missing_keys = set(('inventories', rev_id) for rev_id in parents)
176
 
        return missing_keys
 
164
            return graph.EmptySearchResult()
 
165
        elif self._last_revision is not None:
 
166
            return graph.NotInOtherForRevs(self.to_repository,
 
167
                self.from_repository, [self._last_revision],
 
168
                find_ghosts=self.find_ghosts).execute()
 
169
        else: # self._last_revision is None:
 
170
            return graph.EverythingNotInOther(self.to_repository,
 
171
                self.from_repository,
 
172
                find_ghosts=self.find_ghosts).execute()
177
173
 
178
174
 
179
175
class Inter1and2Helper(object):
182
178
    This is for use by fetchers and converters.
183
179
    """
184
180
 
 
181
    # This is a class variable so that the test suite can override it.
 
182
    known_graph_threshold = 100
 
183
 
185
184
    def __init__(self, source):
186
185
        """Constructor.
187
186
 
243
242
        # yet, and are unlikely to in non-rich-root environments anyway.
244
243
        root_id_order.sort(key=operator.itemgetter(0))
245
244
        # Create a record stream containing the roots to create.
246
 
        if len(revs) > 100:
247
 
            # XXX: not covered by tests, should have a flag to always run
248
 
            # this. -- mbp 20100129
249
 
            graph = self.source_repo.get_known_graph_ancestry(revs)
 
245
        if len(revs) > self.known_graph_threshold:
 
246
            graph = self.source.get_known_graph_ancestry(revs)
250
247
        new_roots_stream = _new_root_data_stream(
251
248
            root_id_order, rev_id_to_root_id, parent_map, self.source, graph)
252
249
        return [('texts', new_roots_stream)]
253
250
 
254
251
 
255
 
def _get_rich_root_heads_graph(source_repo, revision_ids):
256
 
    """Get a Graph object suitable for asking heads() for new rich roots."""
257
 
    return 
258
 
 
259
 
 
260
252
def _new_root_data_stream(
261
253
    root_keys_to_create, rev_id_to_root_id_map, parent_map, repo, graph=None):
262
254
    """Generate a texts substream of synthesised root entries.
340
332
            selected_ids.append(parent_id)
341
333
    parent_keys = [(root_id, parent_id) for parent_id in selected_ids]
342
334
    return parent_keys
 
335
 
 
336
 
 
337
class TargetRepoKinds(object):
 
338
    """An enum-like set of constants.
 
339
    
 
340
    They are the possible values of FetchSpecFactory.target_repo_kinds.
 
341
    """
 
342
    
 
343
    PREEXISTING = 'preexisting'
 
344
    STACKED = 'stacked'
 
345
    EMPTY = 'empty'
 
346
 
 
347
 
 
348
class FetchSpecFactory(object):
 
349
    """A helper for building the best fetch spec for a sprout call.
 
350
 
 
351
    Factors that go into determining the sort of fetch to perform:
 
352
     * did the caller specify any revision IDs?
 
353
     * did the caller specify a source branch (need to fetch its
 
354
       heads_to_fetch(), usually the tip + tags)
 
355
     * is there an existing target repo (don't need to refetch revs it
 
356
       already has)
 
357
     * target is stacked?  (similar to pre-existing target repo: even if
 
358
       the target itself is new don't want to refetch existing revs)
 
359
 
 
360
    :ivar source_branch: the source branch if one specified, else None.
 
361
    :ivar source_branch_stop_revision_id: fetch up to this revision of
 
362
        source_branch, rather than its tip.
 
363
    :ivar source_repo: the source repository if one found, else None.
 
364
    :ivar target_repo: the target repository acquired by sprout.
 
365
    :ivar target_repo_kind: one of the TargetRepoKinds constants.
 
366
    """
 
367
 
 
368
    def __init__(self):
 
369
        self._explicit_rev_ids = set()
 
370
        self.source_branch = None
 
371
        self.source_branch_stop_revision_id = None
 
372
        self.source_repo = None
 
373
        self.target_repo = None
 
374
        self.target_repo_kind = None
 
375
 
 
376
    def add_revision_ids(self, revision_ids):
 
377
        """Add revision_ids to the set of revision_ids to be fetched."""
 
378
        self._explicit_rev_ids.update(revision_ids)
 
379
        
 
380
    def make_fetch_spec(self):
 
381
        """Build a SearchResult or PendingAncestryResult or etc."""
 
382
        if self.target_repo_kind is None or self.source_repo is None:
 
383
            raise AssertionError(
 
384
                'Incomplete FetchSpecFactory: %r' % (self.__dict__,))
 
385
        if len(self._explicit_rev_ids) == 0 and self.source_branch is None:
 
386
            # Caller hasn't specified any revisions or source branch
 
387
            if self.target_repo_kind == TargetRepoKinds.EMPTY:
 
388
                return graph.EverythingResult(self.source_repo)
 
389
            else:
 
390
                # We want everything not already in the target (or target's
 
391
                # fallbacks).
 
392
                return graph.EverythingNotInOther(
 
393
                    self.target_repo, self.source_repo).execute()
 
394
        heads_to_fetch = set(self._explicit_rev_ids)
 
395
        if self.source_branch is not None:
 
396
            must_fetch, if_present_fetch = self.source_branch.heads_to_fetch()
 
397
            if self.source_branch_stop_revision_id is not None:
 
398
                # Replace the tip rev from must_fetch with the stop revision
 
399
                # XXX: this might be wrong if the tip rev is also in the
 
400
                # must_fetch set for other reasons (e.g. it's the tip of
 
401
                # multiple loom threads?), but then it's pretty unclear what it
 
402
                # should mean to specify a stop_revision in that case anyway.
 
403
                must_fetch.discard(self.source_branch.last_revision())
 
404
                must_fetch.add(self.source_branch_stop_revision_id)
 
405
            heads_to_fetch.update(must_fetch)
 
406
        else:
 
407
            if_present_fetch = set()
 
408
        if self.target_repo_kind == TargetRepoKinds.EMPTY:
 
409
            # PendingAncestryResult does not raise errors if a requested head
 
410
            # is absent.  Ideally it would support the
 
411
            # required_ids/if_present_ids distinction, but in practice
 
412
            # heads_to_fetch will almost certainly be present so this doesn't
 
413
            # matter much.
 
414
            all_heads = heads_to_fetch.union(if_present_fetch)
 
415
            return graph.PendingAncestryResult(all_heads, self.source_repo)
 
416
        return graph.NotInOtherForRevs(self.target_repo, self.source_repo,
 
417
            required_ids=heads_to_fetch, if_present_ids=if_present_fetch
 
418
            ).execute()
 
419
 
 
420