~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/testament.py

  • Committer: John Arbash Meinel
  • Date: 2005-11-30 15:43:57 UTC
  • mto: (1185.50.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1518.
  • Revision ID: john@arbash-meinel.com-20051130154357-614206b3a7b83cd0
Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005 by Canonical Ltd
2
2
#
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
70
70
# revisions can be serialized.
71
71
 
72
72
from copy import copy
73
 
 
74
 
from bzrlib.osutils import (
75
 
    contains_whitespace,
76
 
    contains_linebreaks,
77
 
    sha,
78
 
    )
79
 
 
 
73
from cStringIO import StringIO
 
74
import string
 
75
from sha import sha
 
76
 
 
77
from bzrlib.osutils import contains_whitespace, contains_linebreaks
80
78
 
81
79
class Testament(object):
82
80
    """Reduced summary of a revision.
89
87
      - compared to a revision
90
88
    """
91
89
 
92
 
    long_header = 'bazaar-ng testament version 1\n'
93
 
    short_header = 'bazaar-ng testament short form 1\n'
94
 
 
95
90
    @classmethod
96
 
    def from_revision(cls, repository, revision_id):
 
91
    def from_revision(cls, branch, revision_id):
97
92
        """Produce a new testament from a historical revision"""
98
 
        rev = repository.get_revision(revision_id)
99
 
        inventory = repository.get_inventory(revision_id)
 
93
        rev = branch.get_revision(revision_id)
 
94
        inventory = branch.get_inventory(revision_id)
100
95
        return cls(rev, inventory)
101
96
 
102
97
    def __init__(self, rev, inventory):
103
98
        """Create a new testament for rev using inventory."""
104
 
        self.revision_id = rev.revision_id
 
99
        self.revision_id = str(rev.revision_id)
105
100
        self.committer = rev.committer
106
101
        self.timezone = rev.timezone or 0
107
102
        self.timestamp = rev.timestamp
109
104
        self.parent_ids = rev.parent_ids[:]
110
105
        self.inventory = inventory
111
106
        self.revprops = copy(rev.properties)
112
 
        if contains_whitespace(self.revision_id):
113
 
            raise ValueError(self.revision_id)
114
 
        if contains_linebreaks(self.committer):
115
 
            raise ValueError(self.committer)
 
107
        assert not contains_whitespace(self.revision_id)
 
108
        assert not contains_linebreaks(self.committer)
116
109
 
117
110
    def as_text_lines(self):
118
111
        """Yield text form as a sequence of lines.
121
114
        hashed in that encoding.
122
115
        """
123
116
        r = []
124
 
        a = r.append
125
 
        a(self.long_header)
 
117
        def a(s):
 
118
            r.append(s)
 
119
        a('bazaar-ng testament version 1\n')
126
120
        a('revision-id: %s\n' % self.revision_id)
127
121
        a('committer: %s\n' % self.committer)
128
122
        a('timestamp: %d\n' % self.timestamp)
130
124
        # inventory length contains the root, which is not shown here
131
125
        a('parents:\n')
132
126
        for parent_id in sorted(self.parent_ids):
133
 
            if contains_whitespace(parent_id):
134
 
                raise ValueError(parent_id)
 
127
            assert not contains_whitespace(parent_id)
135
128
            a('  %s\n' % parent_id)
136
129
        a('message:\n')
137
130
        for l in self.message.splitlines():
138
131
            a('  %s\n' % l)
139
132
        a('inventory:\n')
140
 
        for path, ie in self._get_entries():
 
133
        for path, ie in self.inventory.iter_entries():
141
134
            a(self._entry_to_line(path, ie))
142
135
        r.extend(self._revprops_to_lines())
143
 
        return [line.encode('utf-8') for line in r]
144
 
 
145
 
    def _get_entries(self):
146
 
        entries = self.inventory.iter_entries()
147
 
        entries.next()
148
 
        return entries
 
136
        if __debug__:
 
137
            for l in r:
 
138
                assert isinstance(l, basestring), \
 
139
                    '%r of type %s is not a plain string' % (l, type(l))
 
140
        return r
149
141
 
150
142
    def _escape_path(self, path):
151
 
        if contains_linebreaks(path):
152
 
            raise ValueError(path)
153
 
        return unicode(path.replace('\\', '/').replace(' ', '\ '))
 
143
        assert not contains_linebreaks(path)
 
144
        return unicode(path.replace('\\', '/').replace(' ', '\ ')).encode('utf-8')
154
145
 
155
146
    def _entry_to_line(self, path, ie):
156
147
        """Turn an inventory entry into a testament line"""
157
 
        if contains_whitespace(ie.file_id):
158
 
            raise ValueError(ie.file_id)
159
 
        content = ''
160
 
        content_spacer=''
 
148
        l = '  ' + str(ie.kind)
 
149
        l += ' ' + self._escape_path(path)
 
150
        assert not contains_whitespace(ie.file_id)
 
151
        l += ' ' + unicode(ie.file_id).encode('utf-8')
161
152
        if ie.kind == 'file':
162
153
            # TODO: avoid switching on kind
163
 
            if not ie.text_sha1:
164
 
                raise AssertionError()
165
 
            content = ie.text_sha1
166
 
            content_spacer = ' '
 
154
            assert ie.text_sha1
 
155
            l += ' ' + ie.text_sha1
167
156
        elif ie.kind == 'symlink':
168
 
            if not ie.symlink_target:
169
 
                raise AssertionError()
170
 
            content = self._escape_path(ie.symlink_target)
171
 
            content_spacer = ' '
172
 
 
173
 
        l = u'  %s %s %s%s%s\n' % (ie.kind, self._escape_path(path),
174
 
                                   ie.file_id.decode('utf8'),
175
 
                                   content_spacer, content)
 
157
            assert ie.symlink_target
 
158
            l += ' ' + self._escape_path(ie.symlink_target)
 
159
        l += '\n'
176
160
        return l
177
161
 
178
162
    def as_text(self):
180
164
 
181
165
    def as_short_text(self):
182
166
        """Return short digest-based testament."""
183
 
        return (self.short_header + 
 
167
        s = sha()
 
168
        map(s.update, self.as_text_lines())
 
169
        return ('bazaar-ng testament short form 1\n'
184
170
                'revision-id: %s\n'
185
171
                'sha1: %s\n'
186
 
                % (self.revision_id, self.as_sha1()))
 
172
                % (self.revision_id, s.hexdigest()))
187
173
 
188
174
    def _revprops_to_lines(self):
189
175
        """Pack up revision properties."""
191
177
            return []
192
178
        r = ['properties:\n']
193
179
        for name, value in sorted(self.revprops.items()):
194
 
            if contains_whitespace(name):
195
 
                raise ValueError(name)
 
180
            assert isinstance(name, str)
 
181
            assert not contains_whitespace(name)
196
182
            r.append('  %s:\n' % name)
197
183
            for line in value.splitlines():
198
 
                r.append(u'    %s\n' % line)
 
184
                if not isinstance(line, str):
 
185
                    line = line.encode('utf-8')
 
186
                r.append('    %s\n' % line)
199
187
        return r
200
 
 
201
 
    def as_sha1(self):
202
 
        s = sha()
203
 
        map(s.update, self.as_text_lines())
204
 
        return s.hexdigest()
205
 
 
206
 
 
207
 
class StrictTestament(Testament):
208
 
    """This testament format is for use as a checksum in bundle format 0.8"""
209
 
 
210
 
    long_header = 'bazaar-ng testament version 2.1\n'
211
 
    short_header = 'bazaar-ng testament short form 2.1\n'
212
 
    def _entry_to_line(self, path, ie):
213
 
        l = Testament._entry_to_line(self, path, ie)[:-1]
214
 
        l += ' ' + ie.revision
215
 
        l += {True: ' yes\n', False: ' no\n'}[ie.executable]
216
 
        return l
217
 
 
218
 
 
219
 
class StrictTestament3(StrictTestament):
220
 
    """This testament format is for use as a checksum in bundle format 0.9+
221
 
    
222
 
    It differs from StrictTestament by including data about the tree root.
223
 
    """
224
 
 
225
 
    long_header = 'bazaar testament version 3 strict\n'
226
 
    short_header = 'bazaar testament short form 3 strict\n'
227
 
    def _get_entries(self):
228
 
        return self.inventory.iter_entries()
229
 
 
230
 
    def _escape_path(self, path):
231
 
        if contains_linebreaks(path):
232
 
            raise ValueError(path)
233
 
        if path == '':
234
 
            path = '.'
235
 
        return unicode(path.replace('\\', '/').replace(' ', '\ '))