/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.27 by John Arbash Meinel
Now capable of generating rollup changesets.
17
def _canonicalize_revision(branch, revnos):
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
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
23
    :param revnos:  A list of revisions to lookup, should be at most 2 long
0.5.3 by John Arbash Meinel
Added a couple more bits
24
    :return: (old, new)
0.5.1 by John Arbash Meinel
Just an initial working step.
25
    """
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
26
    # If only 1 entry is given, then we assume we want just the
27
    # changeset between that entry and it's base (we assume parents[0])
28
    if len(revnos) <= 1:
29
        if not revnos or revnos[0] is None:
30
            new = branch.last_patch()
31
        else:
32
            new = branch.lookup_revision(revnos[0])
33
        old = branch.get_revision(new).parents[0].revision_id
34
        return old, new
35
    elif len(revnos) == 2:
36
        old = branch.lookup_revision(revnos[0])
37
        new = branch.lookup_revision(revnos[1])
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
38
    else:
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
39
        raise BzrCommandError('bzr changeset takes at most 2 revisions a base & a target')
0.5.1 by John Arbash Meinel
Just an initial working step.
40
41
    return old, new
42
43
def _get_trees(branch, revisions):
44
    """Get the old and new trees based on revision.
45
    """
0.5.18 by John Arbash Meinel
Some minor fixups
46
    from bzrlib.tree import EmptyTree
0.5.1 by John Arbash Meinel
Just an initial working step.
47
    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.
48
        if hasattr(branch, 'get_root_id'): # Watch out for trees with labeled ROOT ids
49
            old_tree = EmptyTree(branch.get_root_id) 
50
        else:
51
            old_tree = EmptyTree()
0.5.1 by John Arbash Meinel
Just an initial working step.
52
    else:
53
        old_tree = branch.revision_tree(revisions[0])
54
55
    if revisions[1] is None:
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
56
        raise BzrCommandError('Cannot form a bzr changeset with no committed revisions')
0.5.1 by John Arbash Meinel
Just an initial working step.
57
    else:
58
        new_tree = branch.revision_tree(revisions[1])
59
    return old_tree, new_tree
60
61
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.
62
    """Fake a Revision object for the working tree.
63
    
64
    This is for the future, to support changesets against the working tree.
65
    """
0.5.1 by John Arbash Meinel
Just an initial working step.
66
    from bzrlib.revision import Revision
67
    import time
68
    from bzrlib.osutils import local_time_offset, \
69
            username
70
71
    precursor = branch.last_patch()
72
    precursor_sha1 = branch.get_revision_sha1(precursor)
73
74
    return Revision(timestamp=time.time(),
75
            timezone=local_time_offset(),
76
            committer=username(),
77
            precursor=precursor,
78
            precursor_sha1=precursor_sha1)
79
80
81
class MetaInfoHeader(object):
82
    """Maintain all of the header information about this
83
    changeset.
84
    """
85
0.5.5 by John Arbash Meinel
Updated to now include the diffs
86
    def __init__(self, branch, revisions, delta,
0.5.11 by John Arbash Meinel
Working on properly representing renames.
87
            full_remove=True, full_rename=False,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
88
            external_diff_options = None,
89
            new_tree=None, old_tree=None,
90
            old_label = '', new_label = ''):
91
        """
92
        :param full_remove: Include the full-text for a delete
93
        :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.
94
0.5.5 by John Arbash Meinel
Updated to now include the diffs
95
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
96
        self.branch = branch
97
        self.delta = delta
0.5.5 by John Arbash Meinel
Updated to now include the diffs
98
        self.full_remove=full_remove
99
        self.full_rename=full_rename
100
        self.external_diff_options = external_diff_options
101
        self.old_label = old_label
102
        self.new_label = new_label
103
        self.old_tree = old_tree
104
        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.
105
        self.to_file = None
106
        self.revno = None
107
        self.precursor_revno = None
108
109
        self._get_revision_list(revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
110
111
    def _get_revision_list(self, revisions):
112
        """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.
113
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
114
        This is for having a rollup changeset.
0.5.1 by John Arbash Meinel
Just an initial working step.
115
        """
116
        old_revno = None
117
        new_revno = None
118
        rh = self.branch.revision_history()
119
        for revno, rev in enumerate(rh):
120
            if rev == revisions[0]:
121
                old_revno = revno
122
            if rev == revisions[1]:
123
                new_revno = revno
124
0.5.3 by John Arbash Meinel
Added a couple more bits
125
        self.revision_list = []
0.5.1 by John Arbash Meinel
Just an initial working step.
126
        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.
127
            self.base_revision = None # Effectively the EmptyTree()
0.5.18 by John Arbash Meinel
Some minor fixups
128
            old_revno = -1
0.5.3 by John Arbash Meinel
Added a couple more bits
129
        else:
130
            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.
131
        if new_revno is None:
132
            # For the future, when we support working tree changesets.
0.5.3 by John Arbash Meinel
Added a couple more bits
133
            for rev_id in rh[old_revno+1:]:
0.5.1 by John Arbash Meinel
Just an initial working step.
134
                self.revision_list.append(self.branch.get_revision(rev_id))
135
            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.
136
        else:
137
            for rev_id in rh[old_revno+1:new_revno+1]:
138
                self.revision_list.append(self.branch.get_revision(rev_id))
139
        self.precursor_revno = old_revno
140
        self.revno = new_revno
141
142
    def _write(self, txt, key=None):
143
        if key:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
144
            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.
145
        else:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
146
            self.to_file.write('# %s\n' % (txt,))
0.5.1 by John Arbash Meinel
Just an initial working step.
147
148
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
149
        """Write out the meta-info portion to the supplied file.
150
151
        :param to_file: Write out the meta information to the supplied
152
                        file
153
        """
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
154
        self.to_file = to_file
155
156
        self._write_header()
157
        self._write_diffs()
158
        self._write_footer()
159
160
    def _write_header(self):
161
        """Write the stuff that comes before the patches."""
162
        from bzrlib.osutils import username, format_date
163
        write = self._write
164
165
        for line in common.get_header():
166
            write(line)
167
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
168
        # Print out the basic information about the 'target' revision
169
        rev = self.revision_list[-1]
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
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))
0.5.26 by John Arbash Meinel
Adding the commit message for each revision.
226
            self.to_file.write('#    message:\n')
227
            for line in rev.message.split('\n'):
228
                self.to_file.write('#        %s\n' % line)
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
229
230
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
231
232
233
    def _write_ids(self):
234
        if hasattr(self.branch, 'get_root_id'):
235
            root_id = self.branch.get_root_id()
236
        else:
237
            root_id = ROOT_ID
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
238
239
        old_ids = set()
240
        new_ids = set()
241
242
        for path, file_id, kind in self.delta.removed:
243
            old_ids.add(file_id)
244
        for path, file_id, kind in self.delta.added:
245
            new_ids.add(file_id)
246
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
247
            old_ids.add(file_id)
248
            new_ids.add(file_id)
249
        for path, file_id, kind in self.delta.modified:
250
            new_ids.add(file_id)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
251
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
252
        self._write(root_id, key='tree root id')
253
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
254
        def write_ids(tree, id_set, name):
255
            if len(id_set) > 0:
256
                self.to_file.write('# %s ids:\n' % name)
257
            seen_ids = set([root_id])
258
            while len(id_set) > 0:
259
                file_id = id_set.pop()
260
                if file_id in seen_ids:
261
                    continue
262
                seen_ids.add(file_id)
263
                ie = tree.inventory[file_id]
264
                if ie.parent_id not in seen_ids:
265
                    id_set.add(ie.parent_id)
266
                path = tree.inventory.id2path(file_id)
267
                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.
268
                        % (path, file_id,
269
                            ie.parent_id))
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
270
        write_ids(self.new_tree, new_ids, 'file')
271
        write_ids(self.old_tree, old_ids, 'old file')
0.5.5 by John Arbash Meinel
Updated to now include the diffs
272
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
273
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
274
        """Write out the specific diffs"""
275
        from bzrlib.diff import internal_diff, external_diff
276
        DEVNULL = '/dev/null'
277
278
        if self.external_diff_options:
279
            assert isinstance(self.external_diff_options, basestring)
280
            opts = self.external_diff_options.split()
281
            def diff_file(olab, olines, nlab, nlines, to_file):
282
                external_diff(olab, olines, nlab, nlines, to_file, opts)
283
        else:
284
            diff_file = internal_diff
285
286
        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.
287
            print >>self.to_file, '*** removed %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
288
            if kind == 'file' and self.full_remove:
289
                diff_file(self.old_label + path,
290
                          self.old_tree.get_file(file_id).readlines(),
291
                          DEVNULL, 
292
                          [],
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
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
294
    
295
        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.
296
            print >>self.to_file, '*** added %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
297
            if kind == 'file':
298
                diff_file(DEVNULL,
299
                          [],
300
                          self.new_label + path,
301
                          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.
302
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
303
    
304
        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.
305
            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
306
            if self.full_rename and kind == 'file':
307
                diff_file(self.old_label + old_path,
308
                          self.old_tree.get_file(file_id).readlines(),
309
                          DEVNULL, 
310
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
311
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
312
                diff_file(DEVNULL,
313
                          [],
314
                          self.new_label + new_path,
315
                          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.
316
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
317
            elif text_modified:
318
                    diff_file(self.old_label + old_path,
319
                              self.old_tree.get_file(file_id).readlines(),
320
                              self.new_label + new_path,
321
                              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.
322
                              self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
323
    
324
        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.
325
            print >>self.to_file, '*** modified %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
326
            if kind == 'file':
327
                diff_file(self.old_label + path,
328
                          self.old_tree.get_file(file_id).readlines(),
329
                          self.new_label + path,
330
                          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.
331
                          self.to_file)
0.5.1 by John Arbash Meinel
Just an initial working step.
332
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
333
def show_changeset(branch, revisions=None, to_file=None, include_full_diff=False):
0.5.1 by John Arbash Meinel
Just an initial working step.
334
    from bzrlib.diff import compare_trees
335
336
    if to_file is None:
337
        import sys
338
        to_file = sys.stdout
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
339
    revisions = _canonicalize_revision(branch, revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
340
341
    old_tree, new_tree = _get_trees(branch, revisions)
342
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
343
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
0.5.1 by John Arbash Meinel
Just an initial working step.
344
0.5.5 by John Arbash Meinel
Updated to now include the diffs
345
    meta = MetaInfoHeader(branch, revisions, delta,
346
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
347
    meta.write_meta_info(to_file)
348