/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.5.1 by John Arbash Meinel
Just an initial working step.
1
#!/usr/bin/env python
2
"""\
3
Just some work for generating a changeset.
4
"""
5
6
import bzrlib, bzrlib.errors
7
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
8
import common
9
10
from bzrlib.inventory import ROOT_ID
11
0.5.5 by John Arbash Meinel
Updated to now include the diffs
12
try:
13
    set
14
except NameError:
15
    from sets import Set as set
16
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
17
def _canonicalize_revision(branch, revno):
0.5.1 by John Arbash Meinel
Just an initial working step.
18
    """Turn some sort of revision information into a single
19
    set of from-to revision ids.
20
0.5.3 by John Arbash Meinel
Added a couple more bits
21
    A revision id can be None if there is no associated revison.
22
23
    :return: (old, new)
0.5.1 by John Arbash Meinel
Just an initial working step.
24
    """
25
    # This is a little clumsy because revision parsing may return
26
    # a single entry, or a list
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
27
    if revno is None:
28
        new = branch.last_patch()
29
    else:
30
        new = branch.lookup_revision(revno)
31
32
    if new is None:
33
        raise BzrCommandError('Cannot generate a changset with no commits in tree.')
34
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
35
    old = branch.get_revision(new).parents[0].revision_id
0.5.1 by John Arbash Meinel
Just an initial working step.
36
37
    return old, new
38
39
def _get_trees(branch, revisions):
40
    """Get the old and new trees based on revision.
41
    """
0.5.18 by John Arbash Meinel
Some minor fixups
42
    from bzrlib.tree import EmptyTree
0.5.1 by John Arbash Meinel
Just an initial working step.
43
    if revisions[0] is None:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
44
        if hasattr(branch, 'get_root_id'): # Watch out for trees with labeled ROOT ids
45
            old_tree = EmptyTree(branch.get_root_id) 
46
        else:
47
            old_tree = EmptyTree()
0.5.1 by John Arbash Meinel
Just an initial working step.
48
    else:
49
        old_tree = branch.revision_tree(revisions[0])
50
51
    if revisions[1] is None:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
52
        # This is for the future, once we support rollup revisions
53
        # Or working tree revisions
0.5.1 by John Arbash Meinel
Just an initial working step.
54
        new_tree = branch.working_tree()
55
    else:
56
        new_tree = branch.revision_tree(revisions[1])
57
    return old_tree, new_tree
58
59
def _fake_working_revision(branch):
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
60
    """Fake a Revision object for the working tree.
61
    
62
    This is for the future, to support changesets against the working tree.
63
    """
0.5.1 by John Arbash Meinel
Just an initial working step.
64
    from bzrlib.revision import Revision
65
    import time
66
    from bzrlib.osutils import local_time_offset, \
67
            username
68
69
    precursor = branch.last_patch()
70
    precursor_sha1 = branch.get_revision_sha1(precursor)
71
72
    return Revision(timestamp=time.time(),
73
            timezone=local_time_offset(),
74
            committer=username(),
75
            precursor=precursor,
76
            precursor_sha1=precursor_sha1)
77
78
79
class MetaInfoHeader(object):
80
    """Maintain all of the header information about this
81
    changeset.
82
    """
83
0.5.5 by John Arbash Meinel
Updated to now include the diffs
84
    def __init__(self, branch, revisions, delta,
0.5.11 by John Arbash Meinel
Working on properly representing renames.
85
            full_remove=True, full_rename=False,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
86
            external_diff_options = None,
87
            new_tree=None, old_tree=None,
88
            old_label = '', new_label = ''):
89
        """
90
        :param full_remove: Include the full-text for a delete
91
        :param full_rename: Include an add+delete patch for a rename
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
92
0.5.5 by John Arbash Meinel
Updated to now include the diffs
93
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
94
        self.branch = branch
95
        self.delta = delta
0.5.5 by John Arbash Meinel
Updated to now include the diffs
96
        self.full_remove=full_remove
97
        self.full_rename=full_rename
98
        self.external_diff_options = external_diff_options
99
        self.old_label = old_label
100
        self.new_label = new_label
101
        self.old_tree = old_tree
102
        self.new_tree = new_tree
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
103
        self.to_file = None
104
        self.revno = None
105
        self.precursor_revno = None
106
107
        self._get_revision_list(revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
108
109
    def _get_revision_list(self, revisions):
110
        """This generates the list of all revisions from->to.
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
111
112
        This is for the future, when we support having a rollup changeset.
113
        For now, the list should only be one long.
0.5.1 by John Arbash Meinel
Just an initial working step.
114
        """
115
        old_revno = None
116
        new_revno = None
117
        rh = self.branch.revision_history()
118
        for revno, rev in enumerate(rh):
119
            if rev == revisions[0]:
120
                old_revno = revno
121
            if rev == revisions[1]:
122
                new_revno = revno
123
0.5.3 by John Arbash Meinel
Added a couple more bits
124
        self.revision_list = []
0.5.1 by John Arbash Meinel
Just an initial working step.
125
        if old_revno is None:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
126
            self.base_revision = None # Effectively the EmptyTree()
0.5.18 by John Arbash Meinel
Some minor fixups
127
            old_revno = -1
0.5.3 by John Arbash Meinel
Added a couple more bits
128
        else:
129
            self.base_revision = self.branch.get_revision(rh[old_revno])
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
130
        if new_revno is None:
131
            # For the future, when we support working tree changesets.
0.5.3 by John Arbash Meinel
Added a couple more bits
132
            for rev_id in rh[old_revno+1:]:
0.5.1 by John Arbash Meinel
Just an initial working step.
133
                self.revision_list.append(self.branch.get_revision(rev_id))
134
            self.revision_list.append(_fake_working_revision(self.branch))
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
135
        else:
136
            for rev_id in rh[old_revno+1:new_revno+1]:
137
                self.revision_list.append(self.branch.get_revision(rev_id))
138
        self.precursor_revno = old_revno
139
        self.revno = new_revno
140
141
    def _write(self, txt, key=None):
142
        if key:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
143
            self.to_file.write('# %s: %s\n' % (key, txt))
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
144
        else:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
145
            self.to_file.write('# %s\n' % (txt,))
0.5.1 by John Arbash Meinel
Just an initial working step.
146
147
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
148
        """Write out the meta-info portion to the supplied file.
149
150
        :param to_file: Write out the meta information to the supplied
151
                        file
152
        """
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
153
        self.to_file = to_file
154
155
        self._write_header()
156
        self._write_diffs()
157
        self._write_footer()
158
159
    def _write_header(self):
160
        """Write the stuff that comes before the patches."""
161
        from bzrlib.osutils import username, format_date
162
        write = self._write
163
164
        for line in common.get_header():
165
            write(line)
166
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
167
        # For now, we only support 1 revision, but we can support more in the future
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
168
        assert len(self.revision_list) == 1
169
        rev = self.revision_list[0]
170
        write(rev.committer, key='committer')
171
        write(format_date(rev.timestamp, offset=rev.timezone), key='date')
172
        write(str(self.revno), key='revno')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
173
        if rev.message:
174
            self.to_file.write('# message:\n')
175
            for line in rev.message.split('\n'):
176
                self.to_file.write('#    %s\n' % line)
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
177
        write(rev.revision_id, key='revision')
178
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
179
        # Base revision is the revision this changeset is against
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
180
        if self.base_revision:
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
181
            write(self.base_revision.revision_id, key='base')
182
            write(str(self.precursor_revno), key='base revno')
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
183
184
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
185
        write('')
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
186
        self.to_file.write('\n')
187
188
    def _write_footer(self):
189
        """Write the stuff that comes after the patches.
190
191
        This is meant to be more meta-information, which people probably don't want
192
        to read, but which is required for proper bzr operation.
193
        """
194
        write = self._write
195
196
        write('BEGIN BZR FOOTER')
197
0.5.3 by John Arbash Meinel
Added a couple more bits
198
        if self.base_revision:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
199
            rev_id = self.base_revision.revision_id
200
            write(self.branch.get_revision_sha1(rev_id),
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
201
                    key='base sha1')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
202
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
203
        self._write_revisions()
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
204
205
        self._write_ids()
206
207
        write('END BZR FOOTER')
208
209
    def _write_revisions(self):
210
        """Not used. Used for writing multiple revisions."""
0.5.3 by John Arbash Meinel
Added a couple more bits
211
        for rev in self.revision_list:
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
212
            rev_id = rev.revision_id
213
            self.to_file.write('# revision: %s\n' % rev_id)
214
            self.to_file.write('#    sha1: %s\n' % 
215
                self.branch.get_revision_sha1(rev_id))
216
            self.to_file.write('#    committer: %s\n' % rev.committer)
217
            self.to_file.write('#    timestamp: %.9f\n' % rev.timestamp)
218
            self.to_file.write('#    timezone: %.9f\n' % rev.timezone)
219
            self.to_file.write('#    inventory id: %s\n' % rev.inventory_id)
220
            self.to_file.write('#    inventory sha1: %s\n' % rev.inventory_sha1)
221
            self.to_file.write('#    parents:\n')
222
            for parent in rev.parents:
223
                self.to_file.write('#        %s\t%s\n' % (
224
                    parent.revision_id,
225
                    parent.revision_sha1))
226
227
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
228
229
230
    def _write_ids(self):
231
        if hasattr(self.branch, 'get_root_id'):
232
            root_id = self.branch.get_root_id()
233
        else:
234
            root_id = ROOT_ID
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
235
236
        old_ids = set()
237
        new_ids = set()
238
239
        for path, file_id, kind in self.delta.removed:
240
            old_ids.add(file_id)
241
        for path, file_id, kind in self.delta.added:
242
            new_ids.add(file_id)
243
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
244
            old_ids.add(file_id)
245
            new_ids.add(file_id)
246
        for path, file_id, kind in self.delta.modified:
247
            new_ids.add(file_id)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
248
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
249
        self._write(root_id, key='tree root id')
250
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
251
        def write_ids(tree, id_set, name):
252
            if len(id_set) > 0:
253
                self.to_file.write('# %s ids:\n' % name)
254
            seen_ids = set([root_id])
255
            while len(id_set) > 0:
256
                file_id = id_set.pop()
257
                if file_id in seen_ids:
258
                    continue
259
                seen_ids.add(file_id)
260
                ie = tree.inventory[file_id]
261
                if ie.parent_id not in seen_ids:
262
                    id_set.add(ie.parent_id)
263
                path = tree.inventory.id2path(file_id)
264
                self.to_file.write('#    %s\t%s\t%s\n'
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
265
                        % (path, file_id,
266
                            ie.parent_id))
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
267
        write_ids(self.new_tree, new_ids, 'file')
268
        write_ids(self.old_tree, old_ids, 'old file')
0.5.5 by John Arbash Meinel
Updated to now include the diffs
269
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
270
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
271
        """Write out the specific diffs"""
272
        from bzrlib.diff import internal_diff, external_diff
273
        DEVNULL = '/dev/null'
274
275
        if self.external_diff_options:
276
            assert isinstance(self.external_diff_options, basestring)
277
            opts = self.external_diff_options.split()
278
            def diff_file(olab, olines, nlab, nlines, to_file):
279
                external_diff(olab, olines, nlab, nlines, to_file, opts)
280
        else:
281
            diff_file = internal_diff
282
283
        for path, file_id, kind in self.delta.removed:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
284
            print >>self.to_file, '*** removed %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
285
            if kind == 'file' and self.full_remove:
286
                diff_file(self.old_label + path,
287
                          self.old_tree.get_file(file_id).readlines(),
288
                          DEVNULL, 
289
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
290
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
291
    
292
        for path, file_id, kind in self.delta.added:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
293
            print >>self.to_file, '*** added %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
294
            if kind == 'file':
295
                diff_file(DEVNULL,
296
                          [],
297
                          self.new_label + path,
298
                          self.new_tree.get_file(file_id).readlines(),
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
299
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
300
    
301
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
302
            print >>self.to_file, '*** renamed %s %r => %r' % (kind, old_path, new_path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
303
            if self.full_rename and kind == 'file':
304
                diff_file(self.old_label + old_path,
305
                          self.old_tree.get_file(file_id).readlines(),
306
                          DEVNULL, 
307
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
308
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
309
                diff_file(DEVNULL,
310
                          [],
311
                          self.new_label + new_path,
312
                          self.new_tree.get_file(file_id).readlines(),
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
313
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
314
            elif text_modified:
315
                    diff_file(self.old_label + old_path,
316
                              self.old_tree.get_file(file_id).readlines(),
317
                              self.new_label + new_path,
318
                              self.new_tree.get_file(file_id).readlines(),
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
319
                              self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
320
    
321
        for path, file_id, kind in self.delta.modified:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
322
            print >>self.to_file, '*** modified %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
323
            if kind == 'file':
324
                diff_file(self.old_label + path,
325
                          self.old_tree.get_file(file_id).readlines(),
326
                          self.new_label + path,
327
                          self.new_tree.get_file(file_id).readlines(),
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
328
                          self.to_file)
0.5.1 by John Arbash Meinel
Just an initial working step.
329
330
def show_changeset(branch, revision=None, specific_files=None,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
331
        external_diff_options=None, to_file=None,
332
        include_full_diff=False):
0.5.1 by John Arbash Meinel
Just an initial working step.
333
    from bzrlib.diff import compare_trees
334
335
    if to_file is None:
336
        import sys
337
        to_file = sys.stdout
338
    revisions = _canonicalize_revision(branch, revision)
339
340
    old_tree, new_tree = _get_trees(branch, revisions)
341
342
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
343
                          specific_files=specific_files)
344
0.5.5 by John Arbash Meinel
Updated to now include the diffs
345
    meta = MetaInfoHeader(branch, revisions, delta,
346
            external_diff_options=external_diff_options,
347
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
348
    meta.write_meta_info(to_file)
349
350