17
17
"""Serializer factory for reading and writing changesets.
20
21
import bzrlib.errors as errors
21
from bzrlib.changeset.serializer import ChangesetSerializer
24
def ChangesetSerializerV06(ChangesetSerializer):
22
from bzrlib.testament import Testament
23
from bzrlib.changeset.serializer import (ChangesetSerializer,
25
format_highres_date, unpack_highres_date)
27
from bzrlib.diff import internal_diff
28
from bzrlib.delta import compare_trees
31
class ChangesetSerializerV06(ChangesetSerializer):
26
33
"""Read the rest of the changesets from the supplied file.
28
35
:param f: The file to read from
29
36
:return: A list of changesets
38
assert self.version == '0.6'
39
# The first line of the header should have been read
31
40
raise NotImplementedError
33
def write(self, csets, f):
42
def write(self, source, revision_ids, f):
34
43
"""Write the changesets to the supplied files.
36
:param csets: A list of changesets to be serialized
37
:param f: The file to write to
45
:param source: A source for revision information
46
:param revision_ids: The list of revision ids to serialize
47
:param f: The file to output to
39
raise NotImplementedError
50
self.revision_ids = revision_ids
54
self._write_main_header()
55
self._write_revisions()
59
def _write_main_header(self):
60
"""Write the header for the changes"""
62
f.write(CHANGESET_HEADER)
66
def _write(self, key, value, indent=1):
67
"""Write out meta information, with proper indenting, etc"""
68
assert indent > 0, 'indentation must be greater than 0'
70
f.write('#' + (' ' * indent))
71
f.write(key.encode('utf-8'))
74
elif '\n' not in value:
76
f.write(value.encode('utf-8'))
80
for line in value.split('\n'):
81
f.write('#' + (' ' * (indent+2)))
85
def _write_revisions(self):
86
"""Write the information for all of the revisions."""
87
# The next version of changesets will write a rollup
88
# at the top, and back-patches, or something else after that.
89
# For now, we just write the patches in order.
91
# Optimize for the case of revisions in order
96
for rev_id in self.revision_ids:
97
rev = self.source.get_revision(rev_id)
98
rev_tree = self.source.revision_tree(rev_id)
100
# Try to only grab bases which are in the
103
for p_id in rev.parent_ids:
104
if p_id in self.revision_ids:
107
if base_id is None and rev.parent_ids:
108
base_id = rev.parent_ids[0]
110
if base_id == last_rev_id:
112
base_tree = last_rev_tree
114
base_rev = self.source.get_revision(base_id)
115
base_tree = self.source.revision_tree(base_id)
117
self._write_revision(rev, rev_tree, base_rev, base_tree)
121
last_rev_tree = rev_tree
123
def _write_revision(self, rev, rev_tree, base_rev, base_tree):
124
"""Write out the information for a revision."""
126
self._write(key, value, indent=1)
128
w('revision id', rev.revision_id)
129
w('committer', rev.committer)
130
w('date', format_highres_date(rev.timestamp, rev.timezone))
131
w('message', rev.message)
132
self.to_file.write('\n')
134
self._write_delta(rev_tree, base_tree)
137
t = Testament.from_revision(self.source, rev.revision_id)
138
map(s.update, t.as_text_lines())
139
w('sha1', s.hexdigest())
141
w('parent ids', '\n'.join(rev.parent_ids))
143
self._write('properties', None, indent=1)
144
for name, value in rev.properties.items():
145
self._write(name, value, indent=3)
147
# Add an extra blank space at the end
148
self.to_file.write('\n')
150
def _write_delta(self, new_tree, old_tree):
151
"""Write out the changes between the trees."""
152
DEVNULL = '/dev/null'
157
# Only forward slashes in changesets
158
return os.path.join(*args).replace('\\', '/')
160
def do_diff(old_path, file_id, new_path, kind):
161
new_entry = new_tree.inventory[file_id]
162
old_tree.inventory[file_id].diff(internal_diff,
163
pjoin(old_label, old_path), old_tree,
164
pjoin(new_label, new_path), new_entry, new_tree,
166
def do_meta(file_id):
167
ie = new_tree.inventory[file_id]
175
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
177
w = self.to_file.write
179
for path, file_id, kind in delta.removed:
180
w('=== removed %s %s\n' % (kind, path))
182
for path, file_id, kind in delta.added:
183
w('=== added %s %s // file-id:%s\n' % (kind, path, file_id))
184
new_tree.inventory[file_id].diff(internal_diff,
185
pjoin(new_label, path), new_tree,
187
self.to_file, reverse=True)
189
for (old_path, new_path, file_id, kind,
190
text_modified, meta_modified) in delta.renamed:
191
w('=== renamed %s %s // %s' % (kind, old_path, new_path))
196
do_diff(old_path, file_id, new_path, text_modified)
198
for (path, file_id, kind,
199
text_modified, meta_modified) in delta.modified:
200
# TODO: Handle meta_modified
201
#prop_str = get_prop_change(meta_modified)
202
w('=== modified %s %s' % (kind, path))
207
do_diff(path, file_id, path, kind)