~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/changeset/serializer/v06.py

  • Committer: John Arbash Meinel
  • Date: 2005-11-20 01:37:41 UTC
  • mto: (1185.82.108 w-changeset)
  • mto: This revision was merged to the branch mainline in revision 1738.
  • Revision ID: john@arbash-meinel.com-20051120013741-5de2ea06b61bb803
Created output format, slightly simplified code

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Serializer factory for reading and writing changesets.
18
18
"""
19
19
 
 
20
import os
20
21
import bzrlib.errors as errors
21
 
from bzrlib.changeset.serializer import ChangesetSerializer
22
 
 
23
 
 
24
 
def ChangesetSerializerV06(ChangesetSerializer):
 
22
from bzrlib.testament import Testament
 
23
from bzrlib.changeset.serializer import (ChangesetSerializer, 
 
24
        CHANGESET_HEADER,
 
25
        format_highres_date, unpack_highres_date)
 
26
from sha import sha
 
27
from bzrlib.diff import internal_diff
 
28
from bzrlib.delta import compare_trees
 
29
 
 
30
 
 
31
class ChangesetSerializerV06(ChangesetSerializer):
25
32
    def read(self, f):
26
33
        """Read the rest of the changesets from the supplied file.
27
34
 
28
35
        :param f: The file to read from
29
36
        :return: A list of changesets
30
37
        """
 
38
        assert self.version == '0.6'
 
39
        # The first line of the header should have been read
31
40
        raise NotImplementedError
32
41
 
33
 
    def write(self, csets, f):
 
42
    def write(self, source, revision_ids, f):
34
43
        """Write the changesets to the supplied files.
35
44
 
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
38
48
        """
39
 
        raise NotImplementedError
 
49
        self.source = source
 
50
        self.revision_ids = revision_ids
 
51
        self.to_file = f
 
52
        source.lock_read()
 
53
        try:
 
54
            self._write_main_header()
 
55
            self._write_revisions()
 
56
        finally:
 
57
            source.unlock()
 
58
 
 
59
    def _write_main_header(self):
 
60
        """Write the header for the changes"""
 
61
        f = self.to_file
 
62
        f.write(CHANGESET_HEADER)
 
63
        f.write('0.6\n')
 
64
        f.write('#\n')
 
65
 
 
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'
 
69
        f = self.to_file
 
70
        f.write('#' + (' ' * indent))
 
71
        f.write(key.encode('utf-8'))
 
72
        if not value:
 
73
            f.write(':\n')
 
74
        elif '\n' not in value:
 
75
            f.write(': ')
 
76
            f.write(value.encode('utf-8'))
 
77
            f.write('\n')
 
78
        else:
 
79
            f.write(':\n')
 
80
            for line in value.split('\n'):
 
81
                f.write('#' + (' ' * (indent+2)))
 
82
                f.write(line)
 
83
                f.write('\n')
 
84
 
 
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.
 
90
 
 
91
        # Optimize for the case of revisions in order
 
92
        last_rev_id = None
 
93
        last_rev = None
 
94
        last_rev_tree = None
 
95
 
 
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)
 
99
 
 
100
            # Try to only grab bases which are in the
 
101
            # revision set
 
102
            base_id = None
 
103
            for p_id in rev.parent_ids:
 
104
                if p_id in self.revision_ids:
 
105
                    base_id = p_id
 
106
                    break
 
107
            if base_id is None and rev.parent_ids:
 
108
                base_id = rev.parent_ids[0]
 
109
 
 
110
            if base_id == last_rev_id:
 
111
                base_rev = last_rev
 
112
                base_tree = last_rev_tree
 
113
            else:
 
114
                base_rev = self.source.get_revision(base_id)
 
115
                base_tree = self.source.revision_tree(base_id)
 
116
 
 
117
            self._write_revision(rev, rev_tree, base_rev, base_tree)
 
118
 
 
119
            last_rev_id = rev_id
 
120
            last_rev = rev
 
121
            last_rev_tree = rev_tree
 
122
 
 
123
    def _write_revision(self, rev, rev_tree, base_rev, base_tree):
 
124
        """Write out the information for a revision."""
 
125
        def w(key, value):
 
126
            self._write(key, value, indent=1)
 
127
 
 
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')
 
133
 
 
134
        self._write_delta(rev_tree, base_tree)
 
135
 
 
136
        s = sha()
 
137
        t = Testament.from_revision(self.source, rev.revision_id)
 
138
        map(s.update, t.as_text_lines())
 
139
        w('sha1', s.hexdigest())
 
140
        if rev.parent_ids:
 
141
            w('parent ids', '\n'.join(rev.parent_ids))
 
142
        if rev.properties:
 
143
            self._write('properties', None, indent=1)
 
144
            for name, value in rev.properties.items():
 
145
                self._write(name, value, indent=3)
 
146
        
 
147
        # Add an extra blank space at the end
 
148
        self.to_file.write('\n')
 
149
 
 
150
    def _write_delta(self, new_tree, old_tree):
 
151
        """Write out the changes between the trees."""
 
152
        DEVNULL = '/dev/null'
 
153
        old_label = ''
 
154
        new_label = ''
 
155
 
 
156
        def pjoin(*args):
 
157
            # Only forward slashes in changesets
 
158
            return os.path.join(*args).replace('\\', '/')
 
159
 
 
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,
 
165
                    self.to_file)
 
166
        def do_meta(file_id):
 
167
            ie = new_tree.inventory[file_id]
 
168
            w(' // executable:')
 
169
            if ie.executable:
 
170
                w('yes')
 
171
            else:
 
172
                w('no')
 
173
 
 
174
 
 
175
        delta = compare_trees(old_tree, new_tree, want_unchanged=False)
 
176
 
 
177
        w = self.to_file.write
 
178
 
 
179
        for path, file_id, kind in delta.removed:
 
180
            w('=== removed %s %s\n' % (kind, path))
 
181
 
 
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,
 
186
                    DEVNULL, None, None,
 
187
                    self.to_file, reverse=True)
 
188
 
 
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))
 
192
            if meta_modified:
 
193
                do_meta(file_id)
 
194
            w('\n')
 
195
            if text_modified:
 
196
                do_diff(old_path, file_id, new_path, text_modified)
 
197
 
 
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))
 
203
            if meta_modified:
 
204
                do_meta(file_id)
 
205
            w('\n')
 
206
            if text_modified:
 
207
                do_diff(path, file_id, path, kind)
 
208
 
40
209