/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))
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
333
def show_changeset(branch, revision=None, specific_files=None,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
334
        external_diff_options=None, to_file=None,
335
        include_full_diff=False):
0.5.1 by John Arbash Meinel
Just an initial working step.
336
    from bzrlib.diff import compare_trees
337
338
    if to_file is None:
339
        import sys
340
        to_file = sys.stdout
341
    revisions = _canonicalize_revision(branch, revision)
342
343
    old_tree, new_tree = _get_trees(branch, revisions)
344
345
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
346
                          specific_files=specific_files)
347
0.5.5 by John Arbash Meinel
Updated to now include the diffs
348
    meta = MetaInfoHeader(branch, revisions, delta,
349
            external_diff_options=external_diff_options,
350
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
351
    meta.write_meta_info(to_file)
352
353