127
128
self.copied_file_ids = set()
128
129
self.file_ids_names = {}
130
self._fetch_revisions()
131
revs = self._revids_to_fetch()
134
self._fetch_weave_texts(revs)
135
self._fetch_inventory_weave(revs)
136
self._fetch_revision_texts(revs)
137
self.count_copied += len(revs)
134
def _fetch_revisions(self):
141
def _revids_to_fetch(self):
135
142
self._find_last_revision()
136
143
mutter('fetch up to rev {%s}', self._last_revision)
137
144
if (self._last_revision is not None and
138
145
self.to_repository.has_revision(self._last_revision)):
141
revs_to_fetch = self._compare_ancestries()
148
branch_from_revs = set(self.from_repository.get_ancestry(self._last_revision))
142
149
except WeaveError:
143
150
raise InstallFailed([self._last_revision])
144
self._copy_revisions(revs_to_fetch)
145
self.new_ancestry = revs_to_fetch
152
self.dest_last_rev = self.to_branch.last_revision()
153
branch_to_revs = set(self.to_repository.get_ancestry(self.dest_last_rev))
155
return branch_from_revs.difference(branch_to_revs)
157
def _fetch_revision_texts(self, revs):
158
self.to_repository.revision_store.copy_multi(
159
self.from_repository.revision_store, revs)
161
def _fetch_weave_texts(self, revs):
162
file_ids = self.from_branch.fileid_involved_by_set(revs)
164
num_file_ids = len(file_ids)
165
for file_id in file_ids:
166
self.pb.update("merge weave merge", count, num_file_ids)
168
to_weave = self.to_weaves.get_weave_or_empty(file_id,
169
self.to_branch.get_transaction())
170
from_weave = self.from_weaves.get_weave(file_id,
171
self.from_branch.get_transaction())
173
if to_weave.numversions() > 0:
174
# destination has contents, must merge
176
to_weave.join(from_weave)
177
except errors.WeaveParentMismatch:
178
to_weave.reweave(from_weave)
180
# destination is empty, just replace it
181
to_weave = from_weave.copy()
183
self.to_weaves.put_weave(file_id, to_weave,
184
self.to_branch.get_transaction())
188
def _fetch_inventory_weave(self, revs):
189
self.pb.update("inventory merge", 0, 1)
190
from_weave = self.from_repository.get_inventory_weave()
191
to_weave = self.to_repository.get_inventory_weave()
193
if to_weave.numversions() > 0:
194
# destination has contents, must merge
196
to_weave.join(from_weave)
197
except errors.WeaveParentMismatch:
198
to_weave.reweave(from_weave)
200
# destination is empty, just replace it
201
to_weave = from_weave.copy()
203
self.to_control.put_weave('inventory', to_weave,
204
self.to_branch.get_transaction())
147
208
def _find_last_revision(self):
148
209
"""Find the limiting source revision.
162
223
# no history in the source branch
163
224
self._last_revision = None
165
def _compare_ancestries(self):
166
"""Get a list of revisions that must be copied.
168
That is, every revision that's in the ancestry of the source
169
branch and not in the destination branch."""
170
self.pb.update('get source ancestry')
171
from_repository = self.from_branch.repository
172
self.from_ancestry = from_repository.get_ancestry(self._last_revision)
174
dest_last_rev = self.to_branch.last_revision()
175
self.pb.update('get destination ancestry')
177
to_repository = self.to_branch.repository
178
dest_ancestry = to_repository.get_ancestry(dest_last_rev)
181
ss = set(dest_ancestry)
183
for rev_id in self.from_ancestry:
185
to_fetch.append(rev_id)
186
mutter('need to get revision {%s}', rev_id)
187
mutter('need to get %d revisions in total', len(to_fetch))
188
self.count_total = len(to_fetch)
191
def _copy_revisions(self, revs_to_fetch):
193
for rev_id in revs_to_fetch:
197
if self.to_repository.has_revision(rev_id):
199
self.pb.update('copy revision', i, self.count_total)
200
self._copy_one_revision(rev_id)
201
self.count_copied += 1
204
def _copy_one_revision(self, rev_id):
205
"""Copy revision and everything referenced by it."""
206
mutter('copying revision {%s}', rev_id)
207
rev_xml = self.from_repository.get_revision_xml(rev_id)
208
inv_xml = self.from_repository.get_inventory_xml(rev_id)
209
rev = serializer_v5.read_revision_from_string(rev_xml)
210
inv = serializer_v5.read_inventory_from_string(inv_xml)
211
assert rev.revision_id == rev_id
212
assert rev.inventory_sha1 == sha_string(inv_xml)
213
mutter(' commiter %s, %d parents',
216
self._copy_new_texts(rev_id, inv)
217
parents = rev.parent_ids
218
new_parents = copy(parents)
219
for parent in parents:
220
if not self.to_repository.has_revision(parent):
221
new_parents.pop(new_parents.index(parent))
222
self._copy_inventory(rev_id, inv_xml, new_parents)
223
self.to_repository.revision_store.add(StringIO(rev_xml), rev_id)
224
mutter('copied revision %s', rev_id)
226
def _copy_inventory(self, rev_id, inv_xml, parent_ids):
227
self.to_control.add_text('inventory', rev_id,
228
split_lines(inv_xml), parent_ids,
229
self.to_repository.get_transaction())
231
def _copy_new_texts(self, rev_id, inv):
232
"""Copy any new texts occuring in this revision."""
233
# TODO: Rather than writing out weaves every time, hold them
234
# in memory until everything's done? But this way is nicer
235
# if it's interrupted.
236
for path, ie in inv.iter_entries():
237
self._copy_one_weave(rev_id, ie.file_id, ie.revision)
239
def _copy_one_weave(self, rev_id, file_id, text_revision):
240
"""Copy one file weave, esuring the result contains text_revision."""
241
# check if the revision is already there
242
if file_id in self.file_ids_names.keys( ) and \
243
text_revision in self.file_ids_names[file_id]:
245
to_weave = self.to_weaves.get_weave_or_empty(file_id,
246
self.to_repository.get_transaction())
247
if not file_id in self.file_ids_names.keys( ):
248
self.file_ids_names[file_id] = to_weave.names( )
249
if text_revision in to_weave:
251
from_weave = self.from_weaves.get_weave(file_id,
252
self.from_branch.repository.get_transaction())
253
if text_revision not in from_weave:
254
raise MissingText(self.from_branch, text_revision, file_id)
255
mutter('copy file {%s} modified in {%s}', file_id, rev_id)
257
if to_weave.numversions() > 0:
258
# destination has contents, must merge
260
to_weave.join(from_weave)
261
except errors.WeaveParentMismatch:
262
to_weave.reweave(from_weave)
264
# destination is empty, just replace it
265
to_weave = from_weave.copy( )
266
self.to_weaves.put_weave(file_id, to_weave,
267
self.to_repository.get_transaction())
268
self.count_weaves += 1
269
self.copied_file_ids.add(file_id)
270
self.file_ids_names[file_id] = to_weave.names()
271
mutter('copied file {%s}', file_id)