~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/fetch.py

  • Committer: Martin Pool
  • Date: 2006-01-23 02:09:39 UTC
  • mfrom: (1534.1.11 integration)
  • Revision ID: mbp@sourcefrog.net-20060123020939-567fb193328ed7a6
[merge] robert's integration

Show diffs side-by-side

added added

removed removed

Lines of Context:
101
101
        self.count_total = 0
102
102
        self.count_weaves = 0
103
103
        self.copied_file_ids = set()
 
104
        self.file_ids_names = {}
104
105
        if pb is None:
105
106
            self.pb = bzrlib.ui.ui_factory.progress_bar()
106
107
        else:
107
108
            self.pb = pb
108
109
        self.from_branch.lock_read()
109
110
        try:
110
 
            self._fetch_revisions(last_revision)
 
111
            revs = self._revids_to_fetch(last_revision)
 
112
            # nothing to do
 
113
            if revs: 
 
114
                self._fetch_weave_texts(revs)
 
115
                self._fetch_inventory_weave(revs)
 
116
                self._fetch_revision_texts(revs)
 
117
                self.count_copied += len(revs)
111
118
        finally:
112
119
            self.from_branch.unlock()
113
120
            self.pb.clear()
114
121
 
115
 
    def _fetch_revisions(self, last_revision):
 
122
    def _revids_to_fetch(self, last_revision):
116
123
        self.last_revision = self._find_last_revision(last_revision)
117
124
        mutter('fetch up to rev {%s}', self.last_revision)
118
125
        if (self.last_revision is not None and 
119
126
            self.to_branch.has_revision(self.last_revision)):
120
127
            return
121
128
        try:
122
 
            revs_to_fetch = self._compare_ancestries()
 
129
            branch_from_revs = set(self.from_branch.get_ancestry(self.last_revision))
123
130
        except WeaveError:
124
131
            raise InstallFailed([self.last_revision])
125
 
        self._copy_revisions(revs_to_fetch)
126
 
        self.new_ancestry = revs_to_fetch
 
132
 
 
133
        self.dest_last_rev = self.to_branch.last_revision()
 
134
        branch_to_revs = set(self.to_branch.get_ancestry(self.dest_last_rev))
 
135
 
 
136
        return branch_from_revs.difference(branch_to_revs)
 
137
 
 
138
    def _fetch_revision_texts(self, revs):
 
139
        self.to_branch.revision_store.copy_multi(
 
140
            self.from_branch.revision_store, revs)
 
141
 
 
142
    def _fetch_weave_texts(self, revs):
 
143
        file_ids = self.from_branch.fileid_involved_by_set(revs)
 
144
        count = 0
 
145
        num_file_ids = len(file_ids)
 
146
        for file_id in file_ids:
 
147
            self.pb.update("merge weave merge", count, num_file_ids)
 
148
            count +=1
 
149
            to_weave = self.to_weaves.get_weave_or_empty(file_id,
 
150
                self.to_branch.get_transaction())
 
151
            from_weave = self.from_weaves.get_weave(file_id,
 
152
                self.from_branch.get_transaction())
 
153
 
 
154
            if to_weave.numversions() > 0:
 
155
                # destination has contents, must merge
 
156
                try:
 
157
                    to_weave.join(from_weave)
 
158
                except errors.WeaveParentMismatch:
 
159
                    to_weave.reweave(from_weave)
 
160
            else:
 
161
                # destination is empty, just replace it
 
162
                to_weave = from_weave.copy()
 
163
 
 
164
            self.to_weaves.put_weave(file_id, to_weave,
 
165
                self.to_branch.get_transaction())
 
166
 
 
167
        self.pb.clear()
 
168
 
 
169
    def _fetch_inventory_weave(self, revs):
 
170
        self.pb.update("inventory merge", 0, 1)
 
171
 
 
172
        from_weave = self.from_control.get_weave('inventory',
 
173
                self.from_branch.get_transaction())
 
174
        to_weave = self.to_control.get_weave('inventory',
 
175
                self.to_branch.get_transaction())
 
176
 
 
177
        if to_weave.numversions() > 0:
 
178
            # destination has contents, must merge
 
179
            try:
 
180
                to_weave.join(from_weave)
 
181
            except errors.WeaveParentMismatch:
 
182
                to_weave.reweave(from_weave)
 
183
        else:
 
184
            # destination is empty, just replace it
 
185
            to_weave = from_weave.copy()
 
186
 
 
187
        self.to_control.put_weave('inventory', to_weave,
 
188
            self.to_branch.get_transaction())
 
189
 
 
190
        self.pb.clear()
127
191
 
128
192
    def _find_last_revision(self, last_revision):
129
193
        """Find the limiting source revision.
141
205
            return from_history[-1]
142
206
        else:
143
207
            return None                 # no history in the source branch
144
 
            
145
 
 
146
 
    def _compare_ancestries(self):
147
 
        """Get a list of revisions that must be copied.
148
 
 
149
 
        That is, every revision that's in the ancestry of the source
150
 
        branch and not in the destination branch."""
151
 
        self.pb.update('get source ancestry')
152
 
        self.from_ancestry = self.from_branch.get_ancestry(self.last_revision)
153
 
 
154
 
        dest_last_rev = self.to_branch.last_revision()
155
 
        self.pb.update('get destination ancestry')
156
 
        if dest_last_rev:
157
 
            dest_ancestry = self.to_branch.get_ancestry(dest_last_rev)
158
 
        else:
159
 
            dest_ancestry = []
160
 
        ss = set(dest_ancestry)
161
 
        to_fetch = []
162
 
        for rev_id in self.from_ancestry:
163
 
            if rev_id not in ss:
164
 
                to_fetch.append(rev_id)
165
 
                mutter('need to get revision {%s}', rev_id)
166
 
        mutter('need to get %d revisions in total', len(to_fetch))
167
 
        self.count_total = len(to_fetch)
168
 
        return to_fetch
169
 
 
170
 
    def _copy_revisions(self, revs_to_fetch):
171
 
        i = 0
172
 
        for rev_id in revs_to_fetch:
173
 
            i += 1
174
 
            if rev_id is None:
175
 
                continue
176
 
            if self.to_branch.has_revision(rev_id):
177
 
                continue
178
 
            self.pb.update('fetch revision', i, self.count_total)
179
 
            self._copy_one_revision(rev_id)
180
 
            self.count_copied += 1
181
 
 
182
 
 
183
 
    def _copy_one_revision(self, rev_id):
184
 
        """Copy revision and everything referenced by it."""
185
 
        mutter('copying revision {%s}', rev_id)
186
 
        rev_xml = self.from_branch.get_revision_xml(rev_id)
187
 
        inv_xml = self.from_branch.get_inventory_xml(rev_id)
188
 
        rev = serializer_v5.read_revision_from_string(rev_xml)
189
 
        inv = serializer_v5.read_inventory_from_string(inv_xml)
190
 
        assert rev.revision_id == rev_id
191
 
        assert rev.inventory_sha1 == sha_string(inv_xml)
192
 
        mutter('  commiter %s, %d parents',
193
 
               rev.committer,
194
 
               len(rev.parent_ids))
195
 
        self._copy_new_texts(rev_id, inv)
196
 
        parents = rev.parent_ids
197
 
        new_parents = copy(parents)
198
 
        for parent in parents:
199
 
            if not self.to_branch.has_revision(parent):
200
 
                new_parents.pop(new_parents.index(parent))
201
 
        self._copy_inventory(rev_id, inv_xml, new_parents)
202
 
        self.to_branch.revision_store.add(StringIO(rev_xml), rev_id)
203
 
        mutter('copied revision %s', rev_id)
204
 
 
205
 
    def _copy_inventory(self, rev_id, inv_xml, parent_ids):
206
 
        self.to_control.add_text('inventory', rev_id,
207
 
                                split_lines(inv_xml), parent_ids,
208
 
                                self.to_branch.get_transaction())
209
 
 
210
 
    def _copy_new_texts(self, rev_id, inv):
211
 
        """Copy any new texts occuring in this revision."""
212
 
        # TODO: Rather than writing out weaves every time, hold them
213
 
        # in memory until everything's done?  But this way is nicer
214
 
        # if it's interrupted.
215
 
        for path, ie in inv.iter_entries():
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)
238
 
 
239
208
 
240
209
fetch = Fetcher