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
19
18
from cStringIO import StringIO
22
import bzrlib.errors as errors
23
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
25
21
from bzrlib.trace import mutter, note, warning
26
22
from bzrlib.branch import Branch
27
23
from bzrlib.progress import ProgressBar
28
24
from bzrlib.xml5 import serializer_v5
29
25
from bzrlib.osutils import sha_string, split_lines
26
from bzrlib.errors import InstallFailed, NoSuchRevision, WeaveError
31
28
"""Copying of history from one branch to another.
99
96
self.failed_revisions = []
100
97
self.count_copied = 0
101
98
self.count_total = 0
102
self.count_weaves = 0
103
self.copied_file_ids = set()
104
self.file_ids_names = {}
106
101
self.pb = bzrlib.ui.ui_factory.progress_bar()
109
self.from_branch.lock_read()
111
self._fetch_revisions(last_revision)
113
self.from_branch.unlock()
116
def _fetch_revisions(self, last_revision):
117
self.last_revision = self._find_last_revision(last_revision)
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])
118
109
mutter('fetch up to rev {%s}', self.last_revision)
119
if (self.last_revision is not None and
120
self.to_branch.has_revision(self.last_revision)):
123
111
revs_to_fetch = self._compare_ancestries()
124
112
except WeaveError:
195
185
len(rev.parent_ids))
196
186
self._copy_new_texts(rev_id, inv)
197
parents = rev.parent_ids
198
new_parents = copy(parents)
199
for parent in parents:
200
if not self.to_branch.has_revision(parent):
201
new_parents.pop(new_parents.index(parent))
202
self._copy_inventory(rev_id, inv_xml, new_parents)
187
self._copy_inventory(rev_id, inv_xml, rev.parent_ids)
188
self._copy_ancestry(rev_id, rev.parent_ids)
203
189
self.to_branch.revision_store.add(StringIO(rev_xml), rev_id)
204
mutter('copied revision %s', rev_id)
206
192
def _copy_inventory(self, rev_id, inv_xml, parent_ids):
207
193
self.to_control.add_text('inventory', rev_id,
208
split_lines(inv_xml), parent_ids,
209
self.to_branch.get_transaction())
194
split_lines(inv_xml), parent_ids)
197
def _copy_ancestry(self, rev_id, parent_ids):
198
ancestry_lines = self.from_control.get_lines('ancestry', rev_id)
199
self.to_control.add_text('ancestry', rev_id, ancestry_lines,
211
203
def _copy_new_texts(self, rev_id, inv):
212
204
"""Copy any new texts occuring in this revision."""
213
205
# TODO: Rather than writing out weaves every time, hold them
214
206
# in memory until everything's done? But this way is nicer
215
207
# if it's interrupted.
216
208
for path, ie in inv.iter_entries():
217
self._copy_one_weave(rev_id, ie.file_id, ie.revision)
219
def _copy_one_weave(self, rev_id, file_id, text_revision):
220
"""Copy one file weave, esuring the result contains text_revision."""
221
# check if the revision is already there
222
if file_id in self.file_ids_names.keys( ) and \
223
text_revision in self.file_ids_names[file_id]:
225
to_weave = self.to_weaves.get_weave_or_empty(file_id,
226
self.to_branch.get_transaction())
227
if not file_id in self.file_ids_names.keys( ):
228
self.file_ids_names[file_id] = to_weave.names( )
229
if text_revision in to_weave:
231
from_weave = self.from_weaves.get_weave(file_id,
232
self.from_branch.get_transaction())
233
if text_revision not in from_weave:
234
raise MissingText(self.from_branch, text_revision, file_id)
235
mutter('copy file {%s} modified in {%s}', file_id, rev_id)
237
if to_weave.numversions() > 0:
238
# destination has contents, must merge
240
to_weave.join(from_weave)
241
except errors.WeaveParentMismatch:
242
to_weave.reweave(from_weave)
244
# destination is empty, just replace it
245
to_weave = from_weave.copy( )
246
self.to_weaves.put_weave(file_id, to_weave,
247
self.to_branch.get_transaction())
248
self.count_weaves += 1
249
self.copied_file_ids.add(file_id)
250
self.file_ids_names[file_id] = to_weave.names()
251
mutter('copied file {%s}', file_id)
209
if ie.kind != 'file':
211
if ie.text_version != rev_id:
213
mutter('%s {%s} is changed in this revision',
215
self._copy_one_text(rev_id, ie.file_id)
218
def _copy_one_text(self, rev_id, file_id):
219
"""Copy one file text."""
220
mutter('copy text version {%s} of file {%s}',
222
from_weave = self.from_weaves.get_weave(file_id)
223
from_idx = from_weave.lookup(rev_id)
224
from_parents = map(from_weave.idx_to_name, from_weave.parents(from_idx))
225
text_lines = from_weave.get(from_idx)
226
to_weave = self.to_weaves.get_weave_or_empty(file_id)
227
to_parents = map(to_weave.lookup, from_parents)
228
# it's ok to add even if the text is already there
229
to_weave.add(rev_id, to_parents, text_lines)
230
self.to_weaves.put_weave(file_id, to_weave)
231
self.count_texts += 1