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