~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/testament.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-03-22 12:17:00 UTC
  • mfrom: (1616.1.10 bzr.mbp.integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060322121700-79ce0be81013aba1
(mbp) pycurl fixes, other fixes, weave commands, verbose commit changes from robert

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