~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/history2weaves.py

  • Committer: Martin Pool
  • Date: 2005-09-16 08:23:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050916082310-ecb5a25c40253839
- wrap wide strings when showing exceptions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
#
1
3
# Copyright (C) 2005 Canonical Ltd
2
4
#
3
5
# This program is free software; you can redistribute it and/or modify
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
16
18
 
17
 
"""bzr upgrade logic."""
18
 
 
19
 
# change upgrade from .bzr to create a '.bzr-new', then do a bait and switch.
20
 
 
21
 
 
22
 
from bzrlib.bzrdir import ConvertBzrDir4To5, ConvertBzrDir5To6, BzrDir, BzrDirFormat4, BzrDirFormat5
23
 
import bzrlib.errors as errors
24
 
from bzrlib.transport import get_transport
25
 
import bzrlib.ui as ui
26
 
 
27
 
 
28
 
class Convert(object):
29
 
 
30
 
    def __init__(self, url, format):
31
 
        self.format = format
32
 
        self.bzrdir = BzrDir.open_unsupported(url)
33
 
        if self.bzrdir.root_transport.is_readonly():
34
 
            raise errors.UpgradeReadonly
35
 
        self.transport = self.bzrdir.root_transport
36
 
        self.pb = ui.ui_factory.nested_progress_bar()
37
 
        try:
38
 
            self.convert()
39
 
        finally:
40
 
            self.pb.finished()
41
 
 
42
 
    def convert(self):
43
 
        try:
44
 
            branch = self.bzrdir.open_branch()
45
 
            if branch.bzrdir.root_transport.base != \
46
 
                self.bzrdir.root_transport.base:
47
 
                self.pb.note("This is a checkout. The branch (%s) needs to be "
48
 
                             "upgraded separately.",
49
 
                             branch.bzrdir.root_transport.base)
50
 
        except errors.NotBranchError:
51
 
            pass
52
 
        if not self.bzrdir.needs_format_conversion(self.format):
53
 
            raise errors.UpToDateFormat(self.bzrdir._format)
54
 
        if not self.bzrdir.can_convert_format():
55
 
            raise errors.BzrError("cannot upgrade from branch format %s" %
56
 
                           self.bzrdir._format)
57
 
        self.pb.note('starting upgrade of %s', self.transport.base)
58
 
        self._backup_control_dir()
59
 
        while self.bzrdir.needs_format_conversion(self.format):
60
 
            converter = self.bzrdir._format.get_converter(self.format)
61
 
            self.bzrdir = converter.convert(self.bzrdir, self.pb)
62
 
        self.pb.note("finished")
63
 
 
64
 
    def _backup_control_dir(self):
65
 
        self.pb.note('making backup of tree history')
66
 
        self.transport.copy_tree('.bzr', '.bzr.backup')
67
 
        self.pb.note('%s.bzr has been backed up to %s.bzr.backup',
68
 
             self.transport.base,
69
 
             self.transport.base)
70
 
        self.pb.note('if conversion fails, you can move this directory back to .bzr')
71
 
        self.pb.note('if it succeeds, you can remove this directory if you wish')
72
 
 
73
 
def upgrade(url, format=None):
74
 
    """Upgrade to format, or the default bzrdir format if not supplied."""
75
 
    Convert(url, format)
 
19
"""Experiment in converting existing bzr branches to weaves."""
 
20
 
 
21
# To make this properly useful
 
22
#
 
23
# 1. assign text version ids, and put those text versions into
 
24
#    the inventory as they're converted.
 
25
#
 
26
# 2. keep track of the previous version of each file, rather than
 
27
#    just using the last one imported
 
28
#
 
29
# 3. assign entry versions when files are added, renamed or moved.
 
30
#
 
31
# 4. when merged-in versions are observed, walk down through them
 
32
#    to discover everything, then commit bottom-up
 
33
#
 
34
# 5. track ancestry as things are merged in, and commit that in each
 
35
#    revision
 
36
#
 
37
# Perhaps it's best to first walk the whole graph and make a plan for
 
38
# what should be imported in what order?  Need a kind of topological
 
39
# sort of all revisions.  (Or do we, can we just before doing a revision
 
40
# see that all its parents have either been converted or abandoned?)
 
41
 
 
42
try:
 
43
    import psyco
 
44
    psyco.full()
 
45
except ImportError:
 
46
    pass
 
47
 
 
48
 
 
49
import tempfile
 
50
import hotshot, hotshot.stats
 
51
import sys
 
52
import logging
 
53
 
 
54
import bzrlib.branch
 
55
from bzrlib.revfile import Revfile
 
56
from bzrlib.weave import Weave
 
57
from bzrlib.weavefile import read_weave, write_weave
 
58
from bzrlib.progress import ProgressBar
 
59
from bzrlib.atomicfile import AtomicFile
 
60
import bzrlib.trace
 
61
 
 
62
 
 
63
 
 
64
def convert():
 
65
    bzrlib.trace.enable_default_logging()
 
66
 
 
67
    pb = ProgressBar()
 
68
 
 
69
    inv_weave = Weave()
 
70
 
 
71
    last_text_sha = {}
 
72
 
 
73
    # holds in-memory weaves for all files
 
74
    text_weaves = {}
 
75
 
 
76
    b = bzrlib.branch.find_branch('.')
 
77
 
 
78
    revno = 1
 
79
    rev_history = b.revision_history()
 
80
    last_idx = None
 
81
    inv_parents = []
 
82
    text_count = 0
 
83
    
 
84
    for rev_id in rev_history:
 
85
        pb.update('converting revision', revno, len(rev_history))
 
86
        
 
87
        inv_xml = b.get_inventory_xml(rev_id).readlines()
 
88
 
 
89
        new_idx = inv_weave.add(rev_id, inv_parents, inv_xml)
 
90
        inv_parents = [new_idx]
 
91
 
 
92
        tree = b.revision_tree(rev_id)
 
93
        inv = tree.inventory
 
94
 
 
95
        # for each file in the inventory, put it into its own revfile
 
96
        for file_id in inv:
 
97
            ie = inv[file_id]
 
98
            if ie.kind != 'file':
 
99
                continue
 
100
            if last_text_sha.get(file_id) == ie.text_sha1:
 
101
                # same as last time
 
102
                continue
 
103
            last_text_sha[file_id] = ie.text_sha1
 
104
 
 
105
            # new text (though possibly already stored); need to store it
 
106
            text_lines = tree.get_file(file_id).readlines()
 
107
 
 
108
            # if the file's created for the first time in this
 
109
            # revision then make a new weave; else find the old one
 
110
            if file_id not in text_weaves:
 
111
                text_weaves[file_id] = Weave()
 
112
                
 
113
            w = text_weaves[file_id]
 
114
 
 
115
            # base the new text version off whatever was last
 
116
            # (actually it'd be better to track this, to allow for
 
117
            # files that are deleted and then reappear)
 
118
            last = len(w)
 
119
            if last == 0:
 
120
                parents = []
 
121
            else:
 
122
                parents = [last-1]
 
123
 
 
124
            w.add(rev_id, parents, text_lines)
 
125
            text_count += 1
 
126
 
 
127
        revno += 1
 
128
 
 
129
    pb.clear()
 
130
    print '%6d revisions and inventories' % revno
 
131
    print '%6d texts' % text_count
 
132
 
 
133
    i = 0
 
134
    # TODO: commit them all atomically at the end, not one by one
 
135
    write_atomic_weave(inv_weave, 'weaves/inventory.weave')
 
136
    for file_id, file_weave in text_weaves.items():
 
137
        pb.update('writing weave', i, len(text_weaves))
 
138
        write_atomic_weave(file_weave, 'weaves/%s.weave' % file_id)
 
139
        i += 1
 
140
 
 
141
    pb.clear()
 
142
 
 
143
 
 
144
def write_atomic_weave(weave, filename):
 
145
    inv_wf = AtomicFile(filename)
 
146
    try:
 
147
        write_weave(weave, inv_wf)
 
148
        inv_wf.commit()
 
149
    finally:
 
150
        inv_wf.close()
 
151
 
 
152
    
 
153
 
 
154
 
 
155
def profile_convert(): 
 
156
    prof_f = tempfile.NamedTemporaryFile()
 
157
 
 
158
    prof = hotshot.Profile(prof_f.name)
 
159
 
 
160
    prof.runcall(convert) 
 
161
    prof.close()
 
162
 
 
163
    stats = hotshot.stats.load(prof_f.name)
 
164
    ##stats.strip_dirs()
 
165
    stats.sort_stats('time')
 
166
    # XXX: Might like to write to stderr or the trace file instead but
 
167
    # print_stats seems hardcoded to stdout
 
168
    stats.print_stats(20)
 
169
            
 
170
 
 
171
if '-p' in sys.argv[1:]:
 
172
    profile_convert()
 
173
else:
 
174
    convert()
 
175