~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: Martin Pool
  • Date: 2006-02-22 04:29:54 UTC
  • mfrom: (1566 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1569.
  • Revision ID: mbp@sourcefrog.net-20060222042954-60333f08dd56a646
[merge] from bzr.dev before integration
Fix undefined ordering in sign_my_revisions breaking tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
16
16
 
17
 
from copy import copy
18
 
import os
19
 
from cStringIO import StringIO
20
 
 
21
 
import bzrlib
22
 
import bzrlib.errors as errors
23
 
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
24
 
                           MissingText)
25
 
from bzrlib.trace import mutter, note, warning
26
 
from bzrlib.branch import Branch
27
 
from bzrlib.progress import ProgressBar
28
 
from bzrlib.xml5 import serializer_v5
29
 
from bzrlib.osutils import sha_string, split_lines
30
17
 
31
18
"""Copying of history from one branch to another.
32
19
 
43
30
memory until we've updated all of the files referenced.
44
31
"""
45
32
 
 
33
import bzrlib
 
34
import bzrlib.errors as errors
 
35
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
 
36
                           MissingText)
 
37
from bzrlib.trace import mutter
 
38
from bzrlib.progress import ProgressBar
 
39
from bzrlib.revision import NULL_REVISION
 
40
from bzrlib.symbol_versioning import *
 
41
 
 
42
 
46
43
# TODO: Avoid repeatedly opening weaves so many times.
47
44
 
48
45
# XXX: This doesn't handle ghost (not present in branch) revisions at
61
58
#   and add in all file versions
62
59
 
63
60
 
64
 
 
 
61
@deprecated_function(zero_eight)
65
62
def greedy_fetch(to_branch, from_branch, revision=None, pb=None):
 
63
    """Legacy API, please see branch.fetch(from_branch, last_revision, pb)."""
66
64
    f = Fetcher(to_branch, from_branch, revision, pb)
67
65
    return f.count_copied, f.failed_revisions
68
66
 
69
 
 
70
 
 
71
 
class Fetcher(object):
72
 
    """Pull revisions and texts from one branch to another.
73
 
 
74
 
    This doesn't update the destination's history; that can be done
75
 
    separately if desired.  
76
 
 
77
 
    revision_limit
78
 
        If set, pull only up to this revision_id.
79
 
 
80
 
    After running:
81
 
 
82
 
    last_revision -- if last_revision
83
 
        is given it will be that, otherwise the last revision of
84
 
        from_branch
85
 
 
 
67
fetch = greedy_fetch
 
68
 
 
69
 
 
70
class RepoFetcher(object):
 
71
    """Pull revisions and texts from one repository to another.
 
72
 
 
73
    last_revision
 
74
        if set, try to limit to the data this revision references.
 
75
 
 
76
    after running:
86
77
    count_copied -- number of revisions copied
87
78
 
88
 
    count_weaves -- number of file weaves copied
 
79
    This should not be used directory, its essential a object to encapsulate
 
80
    the logic in InterRepository.fetch().
89
81
    """
90
 
    def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
91
 
        if to_branch.base == from_branch.base:
92
 
            raise Exception("can't fetch from a branch to itself %s, %s" % 
93
 
                            (from_branch.base, to_branch.base))
94
 
        
95
 
        self.to_branch = to_branch
96
 
        self.from_branch = from_branch
 
82
    def __init__(self, to_repository, from_repository, last_revision=None, pb=None):
 
83
        # result variables.
 
84
        self.failed_revisions = []
 
85
        self.count_copied = 0
 
86
        if to_repository.bzrdir.transport.base == from_repository.bzrdir.transport.base:
 
87
            # check that last_revision is in 'from' and then return a no-operation.
 
88
            if last_revision not in (None, NULL_REVISION):
 
89
                from_repository.get_revision(last_revision)
 
90
            return
 
91
        self.to_repository = to_repository
 
92
        self.from_repository = from_repository
 
93
        # must not mutate self._last_revision as its potentially a shared instance
97
94
        self._last_revision = last_revision
98
95
        if pb is None:
99
96
            self.pb = bzrlib.ui.ui_factory.progress_bar()
100
97
        else:
101
98
            self.pb = pb
102
 
        self.from_branch.lock_read()
 
99
        self.from_repository.lock_read()
103
100
        try:
104
 
            self.to_branch.lock_write()
 
101
            self.to_repository.lock_write()
105
102
            try:
106
103
                self.__fetch()
107
104
            finally:
108
 
                self.to_branch.unlock()
 
105
                self.to_repository.unlock()
109
106
        finally:
110
 
            self.from_branch.unlock()
 
107
            self.from_repository.unlock()
111
108
 
112
109
    def __fetch(self):
113
110
        """Primary worker function.
115
112
        This initialises all the needed variables, and then fetches the 
116
113
        requested revisions, finally clearing the progress bar.
117
114
        """
118
 
        self.to_repository = self.to_branch.repository
119
115
        self.to_weaves = self.to_repository.weave_store
120
116
        self.to_control = self.to_repository.control_weaves
121
 
        self.from_repository = self.from_branch.repository
122
117
        self.from_weaves = self.from_repository.weave_store
123
118
        self.from_control = self.from_repository.control_weaves
124
 
        self.failed_revisions = []
125
 
        self.count_copied = 0
126
119
        self.count_total = 0
127
 
        self.count_weaves = 0
128
 
        self.copied_file_ids = set()
129
120
        self.file_ids_names = {}
130
121
        try:
131
122
            revs = self._revids_to_fetch()
139
130
            self.pb.clear()
140
131
 
141
132
    def _revids_to_fetch(self):
142
 
        self._find_last_revision()
 
133
        self.pb.update('get destination history')
143
134
        mutter('fetch up to rev {%s}', self._last_revision)
144
 
        if (self._last_revision is not None and 
 
135
        if self._last_revision is NULL_REVISION:
 
136
            # explicit limit of no revisions needed
 
137
            return None
 
138
        if (self._last_revision != None and
145
139
            self.to_repository.has_revision(self._last_revision)):
146
 
            return
 
140
            return None
 
141
            
147
142
        try:
148
 
            branch_from_revs = set(self.from_repository.get_ancestry(self._last_revision))
149
 
        except WeaveError:
 
143
            return self.to_repository.missing_revision_ids(self.from_repository,
 
144
                                                           self._last_revision)
 
145
        except errors.NoSuchRevision:
150
146
            raise InstallFailed([self._last_revision])
151
147
 
152
 
        self.dest_last_rev = self.to_branch.last_revision()
153
 
        branch_to_revs = set(self.to_repository.get_ancestry(self.dest_last_rev))
154
 
 
155
 
        return branch_from_revs.difference(branch_to_revs)
156
 
 
157
148
    def _fetch_revision_texts(self, revs):
158
149
        self.to_repository.revision_store.copy_multi(
159
 
            self.from_repository.revision_store, revs)
 
150
            self.from_repository.revision_store,
 
151
            revs,
 
152
            pb=self.pb)
160
153
 
161
154
    def _fetch_weave_texts(self, revs):
162
 
        file_ids = self.from_branch.fileid_involved_by_set(revs)
 
155
        file_ids = self.from_repository.fileid_involved_by_set(revs)
163
156
        count = 0
164
157
        num_file_ids = len(file_ids)
165
158
        for file_id in file_ids:
166
 
            self.pb.update("merge weave merge", count, num_file_ids)
 
159
            self.pb.update("merge weaves", count, num_file_ids)
167
160
            count +=1
168
161
            to_weave = self.to_weaves.get_weave_or_empty(file_id,
169
 
                self.to_branch.get_transaction())
 
162
                self.to_repository.get_transaction())
170
163
            from_weave = self.from_weaves.get_weave(file_id,
171
 
                self.from_branch.get_transaction())
 
164
                self.from_repository.get_transaction())
172
165
 
173
166
            if to_weave.numversions() > 0:
174
167
                # destination has contents, must merge
181
174
                to_weave = from_weave.copy()
182
175
 
183
176
            self.to_weaves.put_weave(file_id, to_weave,
184
 
                self.to_branch.get_transaction())
185
 
 
 
177
                self.to_repository.get_transaction())
186
178
        self.pb.clear()
187
179
 
188
180
    def _fetch_inventory_weave(self, revs):
191
183
        to_weave = self.to_repository.get_inventory_weave()
192
184
        self.pb.update("inventory fetch", 1, 2)
193
185
        to_weave = self.to_control.get_weave('inventory',
194
 
                self.to_branch.get_transaction())
 
186
                self.to_repository.get_transaction())
195
187
        self.pb.update("inventory fetch", 2, 2)
196
188
 
197
189
        if to_weave.numversions() > 0:
205
197
            to_weave = from_weave.copy()
206
198
 
207
199
        self.to_control.put_weave('inventory', to_weave,
208
 
            self.to_branch.get_transaction())
 
200
            self.to_repository.get_transaction())
209
201
 
210
202
        self.pb.clear()
211
203
 
212
 
    def _find_last_revision(self):
213
 
        """Find the limiting source revision.
214
 
 
215
 
        Every ancestor of that revision will be merged across.
216
 
 
217
 
        Returns the revision_id, or returns None if there's no history
218
 
        in the source branch."""
219
 
        if self._last_revision:
220
 
            return
221
 
        self.pb.update('get source history')
222
 
        from_history = self.from_branch.revision_history()
223
 
        self.pb.update('get destination history')
224
 
        if from_history:
225
 
            self._last_revision = from_history[-1]
226
 
        else:
227
 
            # no history in the source branch
228
 
            self._last_revision = None
229
 
 
230
 
fetch = Fetcher
 
204
 
 
205
class Fetcher(object):
 
206
    """Backwards compatability glue for branch.fetch()."""
 
207
 
 
208
    @deprecated_method(zero_eight)
 
209
    def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
 
210
        """Please see branch.fetch()."""
 
211
        to_branch.fetch(from_branch, last_revision, pb)