1
# Copyright (C) 2005, 2008 Canonical Ltd
3
# Copyright (C) 2005 Canonical Ltd
3
5
# This program is free software; you can redistribute it and/or modify
4
6
# it under the terms of the GNU General Public License as published by
5
7
# the Free Software Foundation; either version 2 of the License, or
6
8
# (at your option) any later version.
8
10
# This program is distributed in the hope that it will be useful,
9
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
13
# GNU General Public License for more details.
13
15
# You should have received a copy of the GNU General Public License
14
16
# along with this program; if not, write to the Free Software
15
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""bzr upgrade logic."""
19
# change upgrade from .bzr to create a '.bzr-new', then do a bait and switch.
22
from bzrlib.bzrdir import ConvertBzrDir4To5, ConvertBzrDir5To6, BzrDir, BzrDirFormat4, BzrDirFormat5, BzrDirFormat
23
import bzrlib.errors as errors
24
from bzrlib.remote import RemoteBzrDir
25
from bzrlib.transport import get_transport
26
import bzrlib.ui as ui
29
class Convert(object):
31
def __init__(self, url, format):
33
self.bzrdir = BzrDir.open_unsupported(url)
34
if isinstance(self.bzrdir, RemoteBzrDir):
35
self.bzrdir._ensure_real()
36
self.bzrdir = self.bzrdir._real_bzrdir
37
if self.bzrdir.root_transport.is_readonly():
38
raise errors.UpgradeReadonly
39
self.transport = self.bzrdir.root_transport
40
self.pb = ui.ui_factory.nested_progress_bar()
48
branch = self.bzrdir.open_branch()
49
if branch.bzrdir.root_transport.base != \
50
self.bzrdir.root_transport.base:
51
self.pb.note("This is a checkout. The branch (%s) needs to be "
52
"upgraded separately.",
53
branch.bzrdir.root_transport.base)
55
except (errors.NotBranchError, errors.IncompatibleRepositories):
56
# might not be a format we can open without upgrading; see e.g.
57
# https://bugs.launchpad.net/bzr/+bug/253891
59
if not self.bzrdir.needs_format_conversion(self.format):
60
raise errors.UpToDateFormat(self.bzrdir._format)
61
if not self.bzrdir.can_convert_format():
62
raise errors.BzrError("cannot upgrade from bzrdir format %s" %
64
if self.format is None:
65
target_format = BzrDirFormat.get_default_format()
67
target_format = self.format
68
self.bzrdir.check_conversion_target(target_format)
69
self.pb.note('starting upgrade of %s', self.transport.base)
70
self._backup_control_dir()
71
while self.bzrdir.needs_format_conversion(self.format):
72
converter = self.bzrdir._format.get_converter(self.format)
73
self.bzrdir = converter.convert(self.bzrdir, self.pb)
74
self.pb.note("finished")
76
def _backup_control_dir(self):
77
self.pb.note('making backup of tree history')
78
self.transport.copy_tree('.bzr', 'backup.bzr')
79
self.pb.note('%s.bzr has been backed up to %sbackup.bzr',
82
self.pb.note('if conversion fails, you can move this directory back to .bzr')
83
self.pb.note('if it succeeds, you can remove this directory if you wish')
85
def upgrade(url, format=None):
86
"""Upgrade to format, or the default bzrdir format if not supplied."""
19
"""Experiment in converting existing bzr branches to weaves."""
29
from bzrlib.revfile import Revfile
30
from bzrlib.weave import Weave
31
from bzrlib.weavefile import read_weave, write_weave
32
from bzrlib.progress import ProgressBar
33
from bzrlib.atomicfile import AtomicFile
35
import hotshot, hotshot.stats
45
# holds in-memory weaves for all files
48
b = bzrlib.branch.find_branch('.')
51
rev_history = b.revision_history()
56
for rev_id in rev_history:
57
pb.update('converting revision', revno, len(rev_history))
59
inv_xml = b.get_inventory_xml(rev_id).readlines()
61
new_idx = inv_weave.add(rev_id, inv_parents, inv_xml)
62
inv_parents = [new_idx]
64
tree = b.revision_tree(rev_id)
67
# for each file in the inventory, put it into its own revfile
72
if last_text_sha.get(file_id) == ie.text_sha1:
75
last_text_sha[file_id] = ie.text_sha1
77
# new text (though possibly already stored); need to store it
78
text_lines = tree.get_file(file_id).readlines()
80
# if the file's created for the first time in this
81
# revision then make a new weave; else find the old one
82
if file_id not in text_weaves:
83
text_weaves[file_id] = Weave()
85
w = text_weaves[file_id]
87
# base the new text version off whatever was last
88
# (actually it'd be better to track this, to allow for
89
# files that are deleted and then reappear)
96
w.add(rev_id, parents, text_lines)
102
print '%6d revisions and inventories' % revno
103
print '%6d texts' % text_count
106
# TODO: commit them all atomically at the end, not one by one
107
write_atomic_weave(inv_weave, 'weaves/inventory.weave')
108
for file_id, file_weave in text_weaves.items():
109
pb.update('writing weave', i, len(text_weaves))
110
write_atomic_weave(file_weave, 'weaves/%s.weave' % file_id)
116
def write_atomic_weave(weave, filename):
117
inv_wf = AtomicFile(filename)
119
write_weave(weave, inv_wf)
127
def profile_convert():
128
prof_f = tempfile.NamedTemporaryFile()
130
prof = hotshot.Profile(prof_f.name)
132
prof.runcall(convert)
135
stats = hotshot.stats.load(prof_f.name)
137
stats.sort_stats('time')
138
## XXX: Might like to write to stderr or the trace file instead but
139
## print_stats seems hardcoded to stdout
140
stats.print_stats(20)
143
if '-p' in sys.argv[1:]: