1
# Copyright (C) 2005, 2006 by Canonical Ltd
1
# Copyright (C) 2005, 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
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
35
35
import bzrlib.errors as errors
36
from bzrlib.errors import (InstallFailed, NoSuchRevision,
36
from bzrlib.errors import (InstallFailed,
38
from bzrlib.progress import ProgressPhase
39
from bzrlib.revision import NULL_REVISION
40
from bzrlib.symbol_versioning import (deprecated_function,
38
44
from bzrlib.trace import mutter
39
from bzrlib.progress import ProgressBar, ProgressPhase
40
from bzrlib.reconcile import RepoReconciler
41
from bzrlib.revision import NULL_REVISION
42
from bzrlib.symbol_versioning import *
47
from bzrlib.lazy_import import lazy_import
45
49
# TODO: Avoid repeatedly opening weaves so many times.
157
162
def _fetch_weave_texts(self, revs):
158
163
texts_pb = bzrlib.ui.ui_factory.nested_progress_bar()
160
file_ids = self.from_repository.fileid_involved_by_set(revs)
165
# fileids_altered_by_revision_ids requires reading the inventory
166
# weave, we will need to read the inventory weave again when
167
# all this is done, so enable caching for that specific weave
168
inv_w = self.from_repository.get_inventory_weave()
170
file_ids = self.from_repository.fileids_altered_by_revision_ids(revs)
162
172
num_file_ids = len(file_ids)
163
for file_id in file_ids:
173
for file_id, required_versions in file_ids.items():
164
174
texts_pb.update("fetch texts", count, num_file_ids)
167
to_weave = self.to_weaves.get_weave(file_id,
168
self.to_repository.get_transaction())
169
except errors.NoSuchFile:
170
# destination is empty, just copy it.
171
# this copies all the texts, which is useful and
172
# on per-file basis quite cheap.
173
self.to_weaves.copy_multi(
177
self.from_repository.get_transaction(),
178
self.to_repository.get_transaction())
180
# destination has contents, must merge
181
from_weave = self.from_weaves.get_weave(file_id,
182
self.from_repository.get_transaction())
183
# we fetch all the texts, because texts do
184
# not reference anything, and its cheap enough
185
to_weave.join(from_weave)
176
to_weave = self.to_weaves.get_weave_or_empty(file_id,
177
self.to_repository.get_transaction())
178
from_weave = self.from_weaves.get_weave(file_id,
179
self.from_repository.get_transaction())
180
# we fetch all the texts, because texts do
181
# not reference anything, and its cheap enough
182
to_weave.join(from_weave, version_ids=required_versions)
183
# we don't need *all* of this data anymore, but we dont know
184
# what we do. This cache clearing will result in a new read
185
# of the knit data when we do the checkout, but probably we
186
# want to emit the needed data on the fly rather than at the
188
# the from weave should know not to cache data being joined,
189
# but its ok to ask it to clear.
190
from_weave.clear_cache()
191
to_weave.clear_cache()
187
193
texts_pb.finished()
276
283
to_rf.join(from_rf, version_ids=revs)
286
class Inter1and2Helper(object):
287
"""Helper for operations that convert data from model 1 and 2
289
This is for use by fetchers and converters.
292
def __init__(self, source, target):
295
:param source: The repository data comes from
296
:param target: The repository data goes to
301
def iter_rev_trees(self, revs):
302
"""Iterate through RevisionTrees efficiently.
304
Additionally, the inventory's revision_id is set if unset.
306
Trees are retrieved in batches of 100, and then yielded in the order
309
:param revs: A list of revision ids
312
for tree in self.source.revision_trees(revs[:100]):
313
if tree.inventory.revision_id is None:
314
tree.inventory.revision_id = tree.get_revision_id()
318
def generate_root_texts(self, revs):
319
"""Generate VersionedFiles for all root ids.
321
:param revs: the revisions to include
323
inventory_weave = self.source.get_inventory_weave()
326
to_store = self.target.weave_store
327
for tree in self.iter_rev_trees(revs):
328
revision_id = tree.inventory.root.revision
329
root_id = tree.inventory.root.file_id
330
parents = inventory_weave.get_parents(revision_id)
331
if root_id not in versionedfile:
332
versionedfile[root_id] = to_store.get_weave_or_empty(root_id,
333
self.target.get_transaction())
334
parent_texts[root_id] = versionedfile[root_id].add_lines(
335
revision_id, parents, [], parent_texts)
337
def regenerate_inventory(self, revs):
338
"""Generate a new inventory versionedfile in target, convertin data.
340
The inventory is retrieved from the source, (deserializing it), and
341
stored in the target (reserializing it in a different format).
342
:param revs: The revisions to include
344
inventory_weave = self.source.get_inventory_weave()
345
for tree in self.iter_rev_trees(revs):
346
parents = inventory_weave.get_parents(tree.get_revision_id())
347
self.target.add_inventory(tree.get_revision_id(), tree.inventory,
351
class Model1toKnit2Fetcher(GenericRepoFetcher):
352
"""Fetch from a Model1 repository into a Knit2 repository
354
def __init__(self, to_repository, from_repository, last_revision=None,
356
self.helper = Inter1and2Helper(from_repository, to_repository)
357
GenericRepoFetcher.__init__(self, to_repository, from_repository,
360
def _fetch_weave_texts(self, revs):
361
GenericRepoFetcher._fetch_weave_texts(self, revs)
362
# Now generate a weave for the tree root
363
self.helper.generate_root_texts(revs)
365
def _fetch_inventory_weave(self, revs):
366
self.helper.regenerate_inventory(revs)
369
class Knit1to2Fetcher(KnitRepoFetcher):
370
"""Fetch from a Knit1 repository into a Knit2 repository"""
372
def __init__(self, to_repository, from_repository, last_revision=None,
374
self.helper = Inter1and2Helper(from_repository, to_repository)
375
KnitRepoFetcher.__init__(self, to_repository, from_repository,
378
def _fetch_weave_texts(self, revs):
379
KnitRepoFetcher._fetch_weave_texts(self, revs)
380
# Now generate a weave for the tree root
381
self.helper.generate_root_texts(revs)
383
def _fetch_inventory_weave(self, revs):
384
self.helper.regenerate_inventory(revs)
279
387
class Fetcher(object):
280
"""Backwards compatability glue for branch.fetch()."""
388
"""Backwards compatibility glue for branch.fetch()."""
282
390
@deprecated_method(zero_eight)
283
391
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):