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