1
# Copyright (C) 2005 by Canonical Ltd
1
# Copyright (C) 2005 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
99
99
def __init__(self, rev, inventory):
100
100
"""Create a new testament for rev using inventory."""
101
self.revision_id = str(rev.revision_id)
101
self.revision_id = rev.revision_id
102
102
self.committer = rev.committer
103
103
self.timezone = rev.timezone or 0
104
104
self.timestamp = rev.timestamp
106
106
self.parent_ids = rev.parent_ids[:]
107
107
self.inventory = inventory
108
108
self.revprops = copy(rev.properties)
109
assert not contains_whitespace(self.revision_id)
110
assert not contains_linebreaks(self.committer)
109
if contains_whitespace(self.revision_id):
110
raise ValueError(self.revision_id)
111
if contains_linebreaks(self.committer):
112
raise ValueError(self.committer)
112
114
def as_text_lines(self):
113
115
"""Yield text form as a sequence of lines.
125
127
# inventory length contains the root, which is not shown here
127
129
for parent_id in sorted(self.parent_ids):
128
assert not contains_whitespace(parent_id)
130
if contains_whitespace(parent_id):
131
raise ValueError(parent_id)
129
132
a(' %s\n' % parent_id)
131
134
for l in self.message.splitlines():
133
136
a('inventory:\n')
134
entries = self.inventory.iter_entries()
136
for path, ie in entries:
137
for path, ie in self._get_entries():
137
138
a(self._entry_to_line(path, ie))
138
139
r.extend(self._revprops_to_lines())
141
assert isinstance(l, basestring), \
142
'%r of type %s is not a plain string' % (l, type(l))
143
140
return [line.encode('utf-8') for line in r]
142
def _get_entries(self):
143
entries = self.inventory.iter_entries()
145
147
def _escape_path(self, path):
146
assert not contains_linebreaks(path)
148
if contains_linebreaks(path):
149
raise ValueError(path)
147
150
return unicode(path.replace('\\', '/').replace(' ', '\ '))
149
152
def _entry_to_line(self, path, ie):
150
153
"""Turn an inventory entry into a testament line"""
151
assert not contains_whitespace(ie.file_id)
154
if contains_whitespace(ie.file_id):
155
raise ValueError(ie.file_id)
154
157
content_spacer=''
155
158
if ie.kind == 'file':
156
159
# TODO: avoid switching on kind
161
raise AssertionError()
158
162
content = ie.text_sha1
159
163
content_spacer = ' '
160
164
elif ie.kind == 'symlink':
161
assert ie.symlink_target
165
if not ie.symlink_target:
166
raise AssertionError()
162
167
content = self._escape_path(ie.symlink_target)
163
168
content_spacer = ' '
165
170
l = u' %s %s %s%s%s\n' % (ie.kind, self._escape_path(path),
171
ie.file_id.decode('utf8'),
167
172
content_spacer, content)
184
189
r = ['properties:\n']
185
190
for name, value in sorted(self.revprops.items()):
186
assert isinstance(name, str)
187
assert not contains_whitespace(name)
191
if contains_whitespace(name):
192
raise ValueError(name)
188
193
r.append(' %s:\n' % name)
189
194
for line in value.splitlines():
190
195
r.append(u' %s\n' % line)
199
204
class StrictTestament(Testament):
200
"""This testament format is for use as a checksum in changesets"""
205
"""This testament format is for use as a checksum in bundle format 0.8"""
202
207
long_header = 'bazaar-ng testament version 2.1\n'
203
208
short_header = 'bazaar-ng testament short form 2.1\n'
206
211
l += ' ' + ie.revision
207
212
l += {True: ' yes\n', False: ' no\n'}[ie.executable]
216
class StrictTestament3(StrictTestament):
217
"""This testament format is for use as a checksum in bundle format 0.9+
219
It differs from StrictTestament by including data about the tree root.
222
long_header = 'bazaar testament version 3 strict\n'
223
short_header = 'bazaar testament short form 3 strict\n'
224
def _get_entries(self):
225
return self.inventory.iter_entries()
227
def _escape_path(self, path):
228
if contains_linebreaks(path):
229
raise ValueError(path)
232
return unicode(path.replace('\\', '/').replace(' ', '\ '))