~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

Exclude more files from dumb-rsync upload

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
17
18
import os
18
19
from cStringIO import StringIO
19
20
 
20
 
import bzrlib.errors
 
21
import bzrlib
 
22
import bzrlib.errors as errors
 
23
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
 
24
                           MissingText)
21
25
from bzrlib.trace import mutter, note, warning
22
26
from bzrlib.branch import Branch
23
27
from bzrlib.progress import ProgressBar
24
28
from bzrlib.xml5 import serializer_v5
25
29
from bzrlib.osutils import sha_string, split_lines
26
 
from bzrlib.errors import InstallFailed, NoSuchRevision, WeaveError
27
30
 
28
31
"""Copying of history from one branch to another.
29
32
 
82
85
 
83
86
    count_copied -- number of revisions copied
84
87
 
85
 
    count_texts -- number of file texts copied
 
88
    count_weaves -- number of file weaves copied
86
89
    """
87
90
    def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
88
91
        if to_branch == from_branch:
96
99
        self.failed_revisions = []
97
100
        self.count_copied = 0
98
101
        self.count_total = 0
99
 
        self.count_texts = 0
 
102
        self.count_weaves = 0
 
103
        self.copied_file_ids = set()
100
104
        if pb is None:
101
105
            self.pb = bzrlib.ui.ui_factory.progress_bar()
102
106
        else:
103
107
            self.pb = pb
 
108
        self.from_branch.lock_read()
104
109
        try:
105
 
            self.last_revision = self._find_last_revision(last_revision)
106
 
        except NoSuchRevision, e:
107
 
            mutter('failed getting last revision: %s', e)
108
 
            raise InstallFailed([last_revision])
 
110
            self._fetch_revisions(last_revision)
 
111
        finally:
 
112
            self.from_branch.unlock()
 
113
            self.pb.clear()
 
114
 
 
115
    def _fetch_revisions(self, last_revision):
 
116
        self.last_revision = self._find_last_revision(last_revision)
109
117
        mutter('fetch up to rev {%s}', self.last_revision)
 
118
        if (self.last_revision is not None and 
 
119
            self.to_branch.has_revision(self.last_revision)):
 
120
            return
110
121
        try:
111
122
            revs_to_fetch = self._compare_ancestries()
112
123
        except WeaveError:
114
125
        self._copy_revisions(revs_to_fetch)
115
126
        self.new_ancestry = revs_to_fetch
116
127
 
117
 
 
118
128
    def _find_last_revision(self, last_revision):
119
129
        """Find the limiting source revision.
120
130
 
122
132
 
123
133
        Returns the revision_id, or returns None if there's no history
124
134
        in the source branch."""
 
135
        if last_revision:
 
136
            return last_revision
125
137
        self.pb.update('get source history')
126
138
        from_history = self.from_branch.revision_history()
127
139
        self.pb.update('get destination history')
128
 
        if last_revision:
129
 
            self.from_branch.get_revision(last_revision)
130
 
            return last_revision
131
 
        elif from_history:
 
140
        if from_history:
132
141
            return from_history[-1]
133
142
        else:
134
143
            return None                 # no history in the source branch
185
194
               len(rev.parent_ids))
186
195
        self._copy_new_texts(rev_id, inv)
187
196
        parents = rev.parent_ids
 
197
        new_parents = copy(parents)
188
198
        for parent in parents:
189
199
            if not self.to_branch.has_revision(parent):
190
 
                parents.pop(parents.index(parent))
191
 
        self._copy_inventory(rev_id, inv_xml, parents)
192
 
        self._copy_ancestry(rev_id, parents)
 
200
                new_parents.pop(new_parents.index(parent))
 
201
        self._copy_inventory(rev_id, inv_xml, new_parents)
193
202
        self.to_branch.revision_store.add(StringIO(rev_xml), rev_id)
194
 
 
 
203
        mutter('copied revision %s', rev_id)
195
204
 
196
205
    def _copy_inventory(self, rev_id, inv_xml, parent_ids):
197
206
        self.to_control.add_text('inventory', rev_id,
198
 
                                split_lines(inv_xml), parent_ids)
199
 
 
200
 
 
201
 
    def _copy_ancestry(self, rev_id, parent_ids):
202
 
        ancestry_lines = self.from_control.get_lines('ancestry', rev_id)
203
 
        self.to_control.add_text('ancestry', rev_id, ancestry_lines,
204
 
                                 parent_ids)
205
 
 
206
 
        
 
207
                                split_lines(inv_xml), parent_ids,
 
208
                                self.to_branch.get_transaction())
 
209
 
207
210
    def _copy_new_texts(self, rev_id, inv):
208
211
        """Copy any new texts occuring in this revision."""
209
212
        # TODO: Rather than writing out weaves every time, hold them
210
213
        # in memory until everything's done?  But this way is nicer
211
214
        # if it's interrupted.
212
215
        for path, ie in inv.iter_entries():
213
 
            if not ie.has_text():
214
 
                continue
215
 
            if ie.revision != rev_id:
216
 
                continue
217
 
            mutter('%s {%s} is changed in this revision',
218
 
                   path, ie.file_id)
219
 
            self._copy_one_text(rev_id, ie.file_id)
220
 
 
221
 
 
222
 
    def _copy_one_text(self, rev_id, file_id):
223
 
        """Copy one file text."""
224
 
        mutter('copy text version {%s} of file {%s}',
225
 
               rev_id, file_id)
226
 
        from_weave = self.from_weaves.get_weave(file_id)
227
 
        from_idx = from_weave.lookup(rev_id)
228
 
        from_parents = map(from_weave.idx_to_name, from_weave.parents(from_idx))
229
 
        text_lines = from_weave.get(from_idx)
230
 
        to_weave = self.to_weaves.get_weave_or_empty(file_id)
231
 
        to_parents = map(to_weave.lookup, from_parents)
232
 
        # it's ok to add even if the text is already there
233
 
        to_weave.add(rev_id, to_parents, text_lines)
234
 
        self.to_weaves.put_weave(file_id, to_weave)
235
 
        self.count_texts += 1
 
216
            self._copy_one_weave(rev_id, ie.file_id, ie.revision)
 
217
 
 
218
    def _copy_one_weave(self, rev_id, file_id, text_revision):
 
219
        """Copy one file weave, esuring the result contains text_revision."""
 
220
        to_weave = self.to_weaves.get_weave_or_empty(file_id,
 
221
            self.to_branch.get_transaction())
 
222
        if text_revision in to_weave:
 
223
            return
 
224
        from_weave = self.from_weaves.get_weave(file_id,
 
225
            self.from_branch.get_transaction())
 
226
        if text_revision not in from_weave:
 
227
            raise MissingText(self.from_branch, text_revision, file_id)
 
228
        mutter('copy file {%s} modified in {%s}', file_id, rev_id)
 
229
        try:
 
230
            to_weave.join(from_weave)
 
231
        except errors.WeaveParentMismatch:
 
232
            to_weave.reweave(from_weave)
 
233
        self.to_weaves.put_weave(file_id, to_weave,
 
234
            self.to_branch.get_transaction())
 
235
        self.count_weaves += 1
 
236
        self.copied_file_ids.add(file_id)
 
237
        mutter('copied file {%s}', file_id)
236
238
 
237
239
 
238
240
fetch = Fetcher