~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: Robert Collins
  • Date: 2005-10-23 11:46:19 UTC
  • Revision ID: robertc@robertcollins.net-20051023114619-cec8ca25207b1344
More quoting at the transport layer bugfixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import os
18
18
from cStringIO import StringIO
19
19
 
20
 
import bzrlib.errors
 
20
import bzrlib
 
21
import bzrlib.errors as errors
 
22
from bzrlib.errors import InstallFailed, NoSuchRevision, WeaveError
21
23
from bzrlib.trace import mutter, note, warning
22
 
from bzrlib.branch import Branch, INVENTORY_FILEID, ANCESTRY_FILEID
 
24
from bzrlib.branch import Branch
23
25
from bzrlib.progress import ProgressBar
24
26
from bzrlib.xml5 import serializer_v5
25
27
from bzrlib.osutils import sha_string, split_lines
26
 
from bzrlib.errors import NoSuchRevision
27
28
 
28
29
"""Copying of history from one branch to another.
29
30
 
82
83
 
83
84
    count_copied -- number of revisions copied
84
85
 
85
 
    count_texts -- number of file texts copied
 
86
    count_weaves -- number of file weaves copied
86
87
    """
87
88
    def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
 
89
        if to_branch == from_branch:
 
90
            raise Exception("can't fetch from a branch to itself")
88
91
        self.to_branch = to_branch
89
92
        self.to_weaves = to_branch.weave_store
 
93
        self.to_control = to_branch.control_weaves
90
94
        self.from_branch = from_branch
91
95
        self.from_weaves = from_branch.weave_store
 
96
        self.from_control = from_branch.control_weaves
92
97
        self.failed_revisions = []
93
98
        self.count_copied = 0
94
99
        self.count_total = 0
95
 
        self.count_texts = 0
 
100
        self.count_weaves = 0
 
101
        self.copied_file_ids = set()
96
102
        if pb is None:
97
103
            self.pb = bzrlib.ui.ui_factory.progress_bar()
98
104
        else:
99
105
            self.pb = pb
 
106
        self.from_branch.lock_read()
 
107
        try:
 
108
            self._fetch_revisions(last_revision)
 
109
        finally:
 
110
            self.from_branch.unlock()
 
111
            self.pb.clear()
 
112
 
 
113
    def _fetch_revisions(self, last_revision):
100
114
        self.last_revision = self._find_last_revision(last_revision)
101
115
        mutter('fetch up to rev {%s}', self.last_revision)
102
 
        revs_to_fetch = self._compare_ancestries()
 
116
        if (self.last_revision is not None and 
 
117
            self.to_branch.has_revision(self.last_revision)):
 
118
            return
 
119
        try:
 
120
            revs_to_fetch = self._compare_ancestries()
 
121
        except WeaveError:
 
122
            raise InstallFailed([self.last_revision])
103
123
        self._copy_revisions(revs_to_fetch)
104
124
        self.new_ancestry = revs_to_fetch
105
125
 
106
 
        
107
 
 
108
126
    def _find_last_revision(self, last_revision):
109
127
        """Find the limiting source revision.
110
128
 
112
130
 
113
131
        Returns the revision_id, or returns None if there's no history
114
132
        in the source branch."""
 
133
        if last_revision:
 
134
            return last_revision
115
135
        self.pb.update('get source history')
116
136
        from_history = self.from_branch.revision_history()
117
137
        self.pb.update('get destination history')
118
 
        if last_revision:
119
 
            if last_revision not in from_history:
120
 
                raise NoSuchRevision(self.from_branch, last_revision)
121
 
            else:
122
 
                return last_revision
123
 
        elif from_history:
 
138
        if from_history:
124
139
            return from_history[-1]
125
140
        else:
126
141
            return None                 # no history in the source branch
149
164
        mutter('need to get %d revisions in total', len(to_fetch))
150
165
        self.count_total = len(to_fetch)
151
166
        return to_fetch
152
 
                
153
 
 
154
167
 
155
168
    def _copy_revisions(self, revs_to_fetch):
156
169
        i = 0
157
170
        for rev_id in revs_to_fetch:
158
171
            i += 1
 
172
            if rev_id is None:
 
173
                continue
159
174
            if self.to_branch.has_revision(rev_id):
160
175
                continue
161
176
            self.pb.update('fetch revision', i, self.count_total)
174
189
        assert rev.inventory_sha1 == sha_string(inv_xml)
175
190
        mutter('  commiter %s, %d parents',
176
191
               rev.committer,
177
 
               len(rev.parents))
 
192
               len(rev.parent_ids))
178
193
        self._copy_new_texts(rev_id, inv)
179
 
        parent_ids = [x.revision_id for x in rev.parents]
180
 
        self._copy_inventory(rev_id, inv_xml, parent_ids)
181
 
        self._copy_ancestry(rev_id, parent_ids)
 
194
        parents = rev.parent_ids
 
195
        for parent in parents:
 
196
            if not self.to_branch.has_revision(parent):
 
197
                parents.pop(parents.index(parent))
 
198
        self._copy_inventory(rev_id, inv_xml, parents)
182
199
        self.to_branch.revision_store.add(StringIO(rev_xml), rev_id)
 
200
        mutter('copied revision %s', rev_id)
183
201
 
184
202
 
185
203
    def _copy_inventory(self, rev_id, inv_xml, parent_ids):
186
 
        self.to_weaves.add_text(INVENTORY_FILEID, rev_id,
187
 
                                split_lines(inv_xml), parent_ids)
188
 
 
189
 
 
190
 
    def _copy_ancestry(self, rev_id, parent_ids):
191
 
        ancestry_lines = self.from_weaves.get_lines(ANCESTRY_FILEID, rev_id)
192
 
        self.to_weaves.add_text(ANCESTRY_FILEID, rev_id, ancestry_lines,
193
 
                                parent_ids)
194
 
 
195
 
        
 
204
        self.to_control.add_text('inventory', rev_id,
 
205
                                split_lines(inv_xml), parent_ids,
 
206
                                self.to_branch.get_transaction())
 
207
 
196
208
    def _copy_new_texts(self, rev_id, inv):
197
209
        """Copy any new texts occuring in this revision."""
198
210
        # TODO: Rather than writing out weaves every time, hold them
199
211
        # in memory until everything's done?  But this way is nicer
200
212
        # if it's interrupted.
201
213
        for path, ie in inv.iter_entries():
202
 
            if ie.kind != 'file':
203
 
                continue
204
 
            if ie.text_version != rev_id:
 
214
            if ie.revision != rev_id:
205
215
                continue
206
216
            mutter('%s {%s} is changed in this revision',
207
217
                   path, ie.file_id)
208
 
            self._copy_one_text(rev_id, ie.file_id)
209
 
 
210
 
 
211
 
    def _copy_one_text(self, rev_id, file_id):
212
 
        """Copy one file text."""
213
 
        mutter('copy text version {%s} of file {%s}',
214
 
               rev_id, file_id)
215
 
        from_weave = self.from_weaves.get_weave(file_id)
216
 
        from_idx = from_weave.lookup(rev_id)
217
 
        from_parents = map(from_weave.idx_to_name, from_weave.parents(from_idx))
218
 
        text_lines = from_weave.get(from_idx)
219
 
        to_weave = self.to_weaves.get_weave_or_empty(file_id)
220
 
        to_parents = map(to_weave.lookup, from_parents)
221
 
        # it's ok to add even if the text is already there
222
 
        to_weave.add(rev_id, to_parents, text_lines)
223
 
        self.to_weaves.put_weave(file_id, to_weave)
224
 
        self.count_texts += 1
 
218
            self._copy_one_weave(rev_id, ie.file_id)
 
219
 
 
220
 
 
221
    def _copy_one_weave(self, rev_id, file_id):
 
222
        """Copy one file weave."""
 
223
        mutter('copy file {%s} modified in {%s}', file_id, rev_id)
 
224
        if file_id in self.copied_file_ids:
 
225
            mutter('file {%s} already copied', file_id)
 
226
            return
 
227
        from_weave = self.from_weaves.get_weave(file_id,
 
228
            self.from_branch.get_transaction())
 
229
        to_weave = self.to_weaves.get_weave_or_empty(file_id,
 
230
            self.to_branch.get_transaction())
 
231
        try:
 
232
            to_weave.join(from_weave)
 
233
        except errors.WeaveParentMismatch:
 
234
            to_weave.reweave(from_weave)
 
235
        self.to_weaves.put_weave(file_id, to_weave,
 
236
            self.to_branch.get_transaction())
 
237
        self.count_weaves += 1
 
238
        self.copied_file_ids.add(file_id)
 
239
        mutter('copied file {%s}', file_id)
225
240
 
226
241
 
227
242
fetch = Fetcher