/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
35
    old = branch.get_revision(new).precursor
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
92
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
93
        self.branch = branch
94
        self.delta = delta
0.5.5 by John Arbash Meinel
Updated to now include the diffs
95
        self.full_remove=full_remove
96
        self.full_rename=full_rename
97
        self.external_diff_options = external_diff_options
98
        self.old_label = old_label
99
        self.new_label = new_label
100
        self.old_tree = old_tree
101
        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.
102
        self.to_file = None
103
        self.revno = None
104
        self.precursor_revno = None
105
106
        self._get_revision_list(revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
107
108
    def _get_revision_list(self, revisions):
109
        """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.
110
111
        This is for the future, when we support having a rollup changeset.
112
        For now, the list should only be one long.
0.5.1 by John Arbash Meinel
Just an initial working step.
113
        """
114
        old_revno = None
115
        new_revno = None
116
        rh = self.branch.revision_history()
117
        for revno, rev in enumerate(rh):
118
            if rev == revisions[0]:
119
                old_revno = revno
120
            if rev == revisions[1]:
121
                new_revno = revno
122
0.5.3 by John Arbash Meinel
Added a couple more bits
123
        self.revision_list = []
0.5.1 by John Arbash Meinel
Just an initial working step.
124
        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.
125
            self.base_revision = None # Effectively the EmptyTree()
0.5.18 by John Arbash Meinel
Some minor fixups
126
            old_revno = -1
0.5.3 by John Arbash Meinel
Added a couple more bits
127
        else:
128
            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.
129
        if new_revno is None:
130
            # For the future, when we support working tree changesets.
0.5.3 by John Arbash Meinel
Added a couple more bits
131
            for rev_id in rh[old_revno+1:]:
0.5.1 by John Arbash Meinel
Just an initial working step.
132
                self.revision_list.append(self.branch.get_revision(rev_id))
133
            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.
134
        else:
135
            for rev_id in rh[old_revno+1:new_revno+1]:
136
                self.revision_list.append(self.branch.get_revision(rev_id))
137
        self.precursor_revno = old_revno
138
        self.revno = new_revno
139
140
    def _write(self, txt, key=None):
141
        if key:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
142
            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.
143
        else:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
144
            self.to_file.write('# %s\n' % (txt,))
0.5.1 by John Arbash Meinel
Just an initial working step.
145
146
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
147
        """Write out the meta-info portion to the supplied file.
148
149
        :param to_file: Write out the meta information to the supplied
150
                        file
151
        """
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
152
        self.to_file = to_file
153
154
        self._write_header()
155
        self._write_diffs()
156
        self._write_footer()
157
158
    def _write_header(self):
159
        """Write the stuff that comes before the patches."""
160
        from bzrlib.osutils import username, format_date
161
        write = self._write
162
163
        for line in common.get_header():
164
            write(line)
165
166
        # This grabs the current username, what we really want is the
167
        # username from the actual patches.
168
        #write(username(), key='committer')
169
        assert len(self.revision_list) == 1
170
        rev = self.revision_list[0]
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
180
        if self.base_revision:
181
            write(self.base_revision.revision_id, key='precursor')
182
            write(str(self.precursor_revno), key='precursor revno')
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
198
        assert len(self.revision_list) == 1 # We only handle single revision entries
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
199
        rev = self.revision_list[0]
200
        write(self.branch.get_revision_sha1(rev.revision_id),
201
                key='revision sha1')
0.5.3 by John Arbash Meinel
Added a couple more bits
202
        if self.base_revision:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
203
            rev_id = self.base_revision.revision_id
204
            write(self.branch.get_revision_sha1(rev_id),
205
                    key='precursor sha1')
206
207
        write('%.9f' % rev.timestamp, key='timestamp')
208
        write(str(rev.timezone), key='timezone')
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
209
210
        self._write_ids()
211
212
        write('END BZR FOOTER')
213
214
    def _write_revisions(self):
215
        """Not used. Used for writing multiple revisions."""
0.5.3 by John Arbash Meinel
Added a couple more bits
216
        first = True
217
        for rev in self.revision_list:
218
            if rev.revision_id is not None:
219
                if first:
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
220
                    self._write('revisions:')
0.5.3 by John Arbash Meinel
Added a couple more bits
221
                    first = False
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
222
                self._write(' '*4 + rev.revision_id + '\t' + self.branch.get_revision_sha1(rev.revision_id))
223
224
225
    def _write_ids(self):
226
        if hasattr(self.branch, 'get_root_id'):
227
            root_id = self.branch.get_root_id()
228
        else:
229
            root_id = ROOT_ID
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
230
231
        old_ids = set()
232
        new_ids = set()
233
234
        for path, file_id, kind in self.delta.removed:
235
            old_ids.add(file_id)
236
        for path, file_id, kind in self.delta.added:
237
            new_ids.add(file_id)
238
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
239
            old_ids.add(file_id)
240
            new_ids.add(file_id)
241
        for path, file_id, kind in self.delta.modified:
242
            new_ids.add(file_id)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
243
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
244
        self._write(root_id, key='tree root id')
245
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
246
        def write_ids(tree, id_set, name):
247
            if len(id_set) > 0:
248
                self.to_file.write('# %s ids:\n' % name)
249
            seen_ids = set([root_id])
250
            while len(id_set) > 0:
251
                file_id = id_set.pop()
252
                if file_id in seen_ids:
253
                    continue
254
                seen_ids.add(file_id)
255
                ie = tree.inventory[file_id]
256
                if ie.parent_id not in seen_ids:
257
                    id_set.add(ie.parent_id)
258
                path = tree.inventory.id2path(file_id)
259
                self.to_file.write('#    %s\t%s\t%s\n'
260
                        % (path.encode('utf8'), file_id.encode('utf8'),
261
                            ie.parent_id.encode('utf8')))
262
        write_ids(self.new_tree, new_ids, 'file')
263
        write_ids(self.old_tree, old_ids, 'old file')
0.5.5 by John Arbash Meinel
Updated to now include the diffs
264
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
265
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
266
        """Write out the specific diffs"""
267
        from bzrlib.diff import internal_diff, external_diff
268
        DEVNULL = '/dev/null'
269
270
        if self.external_diff_options:
271
            assert isinstance(self.external_diff_options, basestring)
272
            opts = self.external_diff_options.split()
273
            def diff_file(olab, olines, nlab, nlines, to_file):
274
                external_diff(olab, olines, nlab, nlines, to_file, opts)
275
        else:
276
            diff_file = internal_diff
277
278
        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.
279
            print >>self.to_file, '*** removed %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
280
            if kind == 'file' and self.full_remove:
281
                diff_file(self.old_label + path,
282
                          self.old_tree.get_file(file_id).readlines(),
283
                          DEVNULL, 
284
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
285
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
286
    
287
        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.
288
            print >>self.to_file, '*** added %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
289
            if kind == 'file':
290
                diff_file(DEVNULL,
291
                          [],
292
                          self.new_label + path,
293
                          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.
294
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
295
    
296
        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.
297
            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
298
            if self.full_rename and kind == 'file':
299
                diff_file(self.old_label + old_path,
300
                          self.old_tree.get_file(file_id).readlines(),
301
                          DEVNULL, 
302
                          [],
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
                diff_file(DEVNULL,
305
                          [],
306
                          self.new_label + new_path,
307
                          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.
308
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
309
            elif text_modified:
310
                    diff_file(self.old_label + old_path,
311
                              self.old_tree.get_file(file_id).readlines(),
312
                              self.new_label + new_path,
313
                              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.
314
                              self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
315
    
316
        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.
317
            print >>self.to_file, '*** modified %s %r' % (kind, path)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
318
            if kind == 'file':
319
                diff_file(self.old_label + path,
320
                          self.old_tree.get_file(file_id).readlines(),
321
                          self.new_label + 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.1 by John Arbash Meinel
Just an initial working step.
324
325
def show_changeset(branch, revision=None, specific_files=None,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
326
        external_diff_options=None, to_file=None,
327
        include_full_diff=False):
0.5.1 by John Arbash Meinel
Just an initial working step.
328
    from bzrlib.diff import compare_trees
329
330
    if to_file is None:
331
        import sys
332
        to_file = sys.stdout
333
    revisions = _canonicalize_revision(branch, revision)
334
335
    old_tree, new_tree = _get_trees(branch, revisions)
336
337
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
338
                          specific_files=specific_files)
339
0.5.5 by John Arbash Meinel
Updated to now include the diffs
340
    meta = MetaInfoHeader(branch, revisions, delta,
341
            external_diff_options=external_diff_options,
342
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
343
    meta.write_meta_info(to_file)
344
345