~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

(spiv) Fetch tagged revisions (not just tags) during branch,
 merge and pull. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
 
56
56
        :param last_revision: If set, try to limit to the data this revision
57
57
            references.
 
58
        :param fetch_spec: A SearchResult specifying which revisions to fetch.
 
59
            If set, this overrides last_revision.
58
60
        :param find_ghosts: If True search the entire history for ghosts.
59
61
        """
60
62
        # repository.fetch has the responsibility for short-circuiting
93
95
        pb.show_pct = pb.show_count = False
94
96
        try:
95
97
            pb.update("Finding revisions", 0, 2)
96
 
            search = self._revids_to_fetch()
97
 
            mutter('fetching: %s', search)
98
 
            if search.is_empty():
 
98
            search_result = self._revids_to_fetch()
 
99
            mutter('fetching: %s', search_result)
 
100
            if search_result.is_empty():
99
101
                return
100
102
            pb.update("Fetching revisions", 1, 2)
101
 
            self._fetch_everything_for_search(search)
 
103
            self._fetch_everything_for_search(search_result)
102
104
        finally:
103
105
            pb.finished()
104
106
 
151
153
        install self._last_revision in self.to_repository.
152
154
 
153
155
        :returns: A SearchResult of some sort.  (Possibly a
154
 
        PendingAncestryResult, EmptySearchResult, etc.)
 
156
            PendingAncestryResult, EmptySearchResult, etc.)
155
157
        """
156
 
        mutter("self._fetch_spec, self._last_revision: %r, %r",
157
 
                self._fetch_spec, self._last_revision)
158
 
        get_search_result = getattr(self._fetch_spec, 'get_search_result', None)
159
 
        if get_search_result is not None:
160
 
            mutter(
161
 
                'resolving fetch_spec into search result: %s', self._fetch_spec)
162
 
            # This is EverythingNotInOther or a similar kind of fetch_spec.
163
 
            # Turn it into a search result.
164
 
            return get_search_result()
165
 
        elif self._fetch_spec is not None:
 
158
        if self._fetch_spec is not None:
166
159
            # The fetch spec is already a concrete search result.
167
160
            return self._fetch_spec
168
161
        elif self._last_revision == NULL_REVISION:
172
165
        elif self._last_revision is not None:
173
166
            return graph.NotInOtherForRevs(self.to_repository,
174
167
                self.from_repository, [self._last_revision],
175
 
                find_ghosts=self.find_ghosts).get_search_result()
 
168
                find_ghosts=self.find_ghosts).execute()
176
169
        else: # self._last_revision is None:
177
170
            return graph.EverythingNotInOther(self.to_repository,
178
171
                self.from_repository,
179
 
                find_ghosts=self.find_ghosts).get_search_result()
 
172
                find_ghosts=self.find_ghosts).execute()
180
173
 
181
174
 
182
175
class Inter1and2Helper(object):
339
332
            selected_ids.append(parent_id)
340
333
    parent_keys = [(root_id, parent_id) for parent_id in selected_ids]
341
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 the tip + tags)
 
354
     * is there an existing target repo (don't need to refetch revs it
 
355
       already has)
 
356
     * target is stacked?  (similar to pre-existing target repo: even if
 
357
       the target itself is new don't want to refetch existing revs)
 
358
 
 
359
    :ivar source_branch: the source branch if one specified, else None.
 
360
    :ivar source_branch_stop_revision_id: fetch up to this revision of
 
361
        source_branch, rather than its tip.
 
362
    :ivar source_repo: the source repository if one found, else None.
 
363
    :ivar target_repo: the target repository acquired by sprout.
 
364
    :ivar target_repo_kind: one of the TargetRepoKinds constants.
 
365
    """
 
366
 
 
367
    def __init__(self):
 
368
        self._explicit_rev_ids = set()
 
369
        self.source_branch = None
 
370
        self.source_branch_stop_revision_id = None
 
371
        self.source_repo = None
 
372
        self.target_repo = None
 
373
        self.target_repo_kind = None
 
374
 
 
375
    def add_revision_ids(self, revision_ids):
 
376
        """Add revision_ids to the set of revision_ids to be fetched."""
 
377
        self._explicit_rev_ids.update(revision_ids)
 
378
        
 
379
    def make_fetch_spec(self):
 
380
        """Build a SearchResult or PendingAncestryResult or etc."""
 
381
        if self.target_repo_kind is None or self.source_repo is None:
 
382
            raise AssertionError(
 
383
                'Incomplete FetchSpecFactory: %r' % (self.__dict__,))
 
384
        if len(self._explicit_rev_ids) == 0 and self.source_branch is None:
 
385
            # Caller hasn't specified any revisions or source branch
 
386
            if self.target_repo_kind == TargetRepoKinds.EMPTY:
 
387
                return graph.EverythingResult(self.source_repo)
 
388
            else:
 
389
                # We want everything not already in the target (or target's
 
390
                # fallbacks).
 
391
                return graph.EverythingNotInOther(
 
392
                    self.target_repo, self.source_repo).execute()
 
393
        heads_to_fetch = set(self._explicit_rev_ids)
 
394
        tags_to_fetch = set()
 
395
        if self.source_branch is not None:
 
396
            try:
 
397
                tags_to_fetch.update(
 
398
                    self.source_branch.tags.get_reverse_tag_dict())
 
399
            except errors.TagsNotSupported:
 
400
                pass
 
401
            if self.source_branch_stop_revision_id is not None:
 
402
                heads_to_fetch.add(self.source_branch_stop_revision_id)
 
403
            else:
 
404
                heads_to_fetch.add(self.source_branch.last_revision())
 
405
        if self.target_repo_kind == TargetRepoKinds.EMPTY:
 
406
            # PendingAncestryResult does not raise errors if a requested head
 
407
            # is absent.  Ideally it would support the
 
408
            # required_ids/if_present_ids distinction, but in practice
 
409
            # heads_to_fetch will almost certainly be present so this doesn't
 
410
            # matter much.
 
411
            all_heads = heads_to_fetch.union(tags_to_fetch)
 
412
            return graph.PendingAncestryResult(all_heads, self.source_repo)
 
413
        return graph.NotInOtherForRevs(self.target_repo, self.source_repo,
 
414
            required_ids=heads_to_fetch, if_present_ids=tags_to_fetch
 
415
            ).execute()
 
416
 
 
417