/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
            new_tree=None, old_tree=None,
63
            old_label = '', new_label = ''):
64
        """
65
        :param full_remove: Include the full-text for a delete
66
        :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.
67
0.5.5 by John Arbash Meinel
Updated to now include the diffs
68
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
69
        self.branch = branch
70
        self.delta = delta
0.5.5 by John Arbash Meinel
Updated to now include the diffs
71
        self.full_remove=full_remove
72
        self.full_rename=full_rename
73
        self.old_label = old_label
74
        self.new_label = new_label
75
        self.old_tree = old_tree
76
        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.
77
        self.to_file = None
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
78
        #self.revno = None
79
        #self.parent_revno = None
80
81
        # These are entries in the header.
82
        # They will be repeated in the footer,
83
        # only if they have changed
84
        self.date = None
85
        self.committer = None
86
        self.message = 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.
87
88
        self._get_revision_list(revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
89
90
    def _get_revision_list(self, revisions):
91
        """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.
92
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
93
        This is for having a rollup changeset.
0.5.1 by John Arbash Meinel
Just an initial working step.
94
        """
95
        old_revno = None
96
        new_revno = None
97
        rh = self.branch.revision_history()
98
        for revno, rev in enumerate(rh):
99
            if rev == revisions[0]:
100
                old_revno = revno
101
            if rev == revisions[1]:
102
                new_revno = revno
103
0.5.3 by John Arbash Meinel
Added a couple more bits
104
        self.revision_list = []
0.5.1 by John Arbash Meinel
Just an initial working step.
105
        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.
106
            self.base_revision = None # Effectively the EmptyTree()
0.5.18 by John Arbash Meinel
Some minor fixups
107
            old_revno = -1
0.5.3 by John Arbash Meinel
Added a couple more bits
108
        else:
109
            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.
110
        if new_revno is None:
111
            # For the future, when we support working tree changesets.
0.5.3 by John Arbash Meinel
Added a couple more bits
112
            for rev_id in rh[old_revno+1:]:
0.5.1 by John Arbash Meinel
Just an initial working step.
113
                self.revision_list.append(self.branch.get_revision(rev_id))
114
            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.
115
        else:
116
            for rev_id in rh[old_revno+1:new_revno+1]:
117
                self.revision_list.append(self.branch.get_revision(rev_id))
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
118
        #self.parent_revno = old_revno+1
119
        #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.
120
121
    def _write(self, txt, key=None):
122
        if key:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
123
            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.
124
        else:
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
125
            self.to_file.write('# %s\n' % (txt,))
0.5.1 by John Arbash Meinel
Just an initial working step.
126
127
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
128
        """Write out the meta-info portion to the supplied file.
129
130
        :param to_file: Write out the meta information to the supplied
131
                        file
132
        """
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
133
        self.to_file = to_file
134
135
        self._write_header()
136
        self._write_diffs()
137
        self._write_footer()
138
139
    def _write_header(self):
140
        """Write the stuff that comes before the patches."""
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
141
        from bzrlib.osutils import username
142
        from common import format_highres_date
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
        write = self._write
144
145
        for line in common.get_header():
146
            write(line)
147
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
148
        # Print out the basic information about the 'target' revision
149
        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.
150
        write(rev.committer, key='committer')
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
151
        self.committer = rev.committer
152
        self.date = format_highres_date(rev.timestamp, offset=rev.timezone)
153
        write(self.date, key='date')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
154
        if rev.message:
155
            self.to_file.write('# message:\n')
156
            for line in rev.message.split('\n'):
157
                self.to_file.write('#    %s\n' % line)
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
158
            self.message = rev.message
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
159
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
160
        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.
161
        self.to_file.write('\n')
162
163
    def _write_footer(self):
164
        """Write the stuff that comes after the patches.
165
166
        This is meant to be more meta-information, which people probably don't want
167
        to read, but which is required for proper bzr operation.
168
        """
169
        write = self._write
170
0.5.57 by John Arbash Meinel
Simplified the header, only output base if it is not the expected one.
171
        # What should we print out for an Empty base revision?
172
        assumed_base = self.revision_list[0].parents[0].revision_id
173
        if self.base_revision.revision_id != assumed_base:
174
            base = self.base_revision.revision_id
175
            write(base, key='base')
176
            write(self.branch.get_revision_sha1(base), key='base sha1')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
177
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
178
        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.
179
0.5.38 by John Arbash Meinel
Working on updating the information to be minimalistic
180
        #self._write_ids()
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
181
        self._write_text_ids()
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
182
183
    def _write_revisions(self):
184
        """Not used. Used for writing multiple revisions."""
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
185
        from common import format_highres_date
186
0.5.3 by John Arbash Meinel
Added a couple more bits
187
        for rev in self.revision_list:
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
188
            rev_id = rev.revision_id
189
            self.to_file.write('# revision: %s\n' % rev_id)
190
            self.to_file.write('#    sha1: %s\n' % 
191
                self.branch.get_revision_sha1(rev_id))
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
192
            if rev.committer != self.committer:
193
                self.to_file.write('#    committer: %s\n' % rev.committer)
194
            date = format_highres_date(rev.timestamp, rev.timezone)
195
            if date != self.date:
196
                self.to_file.write('#    date: %s\n' % date)
197
            if rev.inventory_id != rev_id:
198
                self.to_file.write('#    inventory id: %s\n' % rev.inventory_id)
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
199
            self.to_file.write('#    inventory sha1: %s\n' % rev.inventory_sha1)
200
            self.to_file.write('#    parents:\n')
201
            for parent in rev.parents:
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
202
                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.
203
                    parent.revision_id,
204
                    parent.revision_sha1))
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
205
            if rev.message and rev.message != self.message:
206
                self.to_file.write('#    message:\n')
207
                for line in rev.message.split('\n'):
208
                    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.
209
210
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
211
    def _write_ids(self):
212
        if hasattr(self.branch, 'get_root_id'):
213
            root_id = self.branch.get_root_id()
214
        else:
215
            root_id = ROOT_ID
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
216
217
        old_ids = set()
218
        new_ids = set()
219
220
        for path, file_id, kind in self.delta.removed:
221
            old_ids.add(file_id)
222
        for path, file_id, kind in self.delta.added:
223
            new_ids.add(file_id)
224
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
225
            old_ids.add(file_id)
226
            new_ids.add(file_id)
227
        for path, file_id, kind in self.delta.modified:
228
            new_ids.add(file_id)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
229
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
230
        self._write(root_id, key='tree root id')
231
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
232
        def write_ids(tree, id_set, name):
233
            if len(id_set) > 0:
234
                self.to_file.write('# %s ids:\n' % name)
235
            seen_ids = set([root_id])
236
            while len(id_set) > 0:
237
                file_id = id_set.pop()
238
                if file_id in seen_ids:
239
                    continue
240
                seen_ids.add(file_id)
241
                ie = tree.inventory[file_id]
242
                if ie.parent_id not in seen_ids:
243
                    id_set.add(ie.parent_id)
244
                path = tree.inventory.id2path(file_id)
245
                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.
246
                        % (path, file_id,
247
                            ie.parent_id))
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
248
        write_ids(self.new_tree, new_ids, 'file')
249
        write_ids(self.old_tree, old_ids, 'old file')
0.5.5 by John Arbash Meinel
Updated to now include the diffs
250
0.5.38 by John Arbash Meinel
Working on updating the information to be minimalistic
251
    def _write_text_ids(self):
252
        pass
253
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
254
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
255
        """Write out the specific diffs"""
256
        from bzrlib.diff import internal_diff, external_diff
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
257
        from common import encode
0.5.5 by John Arbash Meinel
Updated to now include the diffs
258
        DEVNULL = '/dev/null'
259
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
260
        diff_file = internal_diff
261
        # Get the target tree so that we can check for
262
        # Appropriate text ids.
263
        rev_id = self.revision_list[-1].revision_id
264
        tree = self.branch.revision_tree(rev_id)
265
266
267
        def get_text_id_str(file_id, modified=True):
268
            """This returns an empty string if guess_text_id == real_text_id.
269
            Otherwise it returns a string suitable for printing, indicating
270
            the file's id.
271
            """
272
            guess_id = common.guess_text_id(tree, file_id, rev_id,
273
                    modified=modified)
274
            real_id = tree.inventory[file_id].text_id
275
            if guess_id != real_id:
276
                return '\ttext-id:' + encode(real_id)
277
            else:
278
                return ''
279
0.5.5 by John Arbash Meinel
Updated to now include the diffs
280
281
        for path, file_id, kind in self.delta.removed:
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
282
            # We don't care about text ids for removed files
283
            print >>self.to_file, '*** removed %s %s' % (kind,
284
                    encode(path))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
285
            if kind == 'file' and self.full_remove:
286
                diff_file(self.old_label + path,
287
                          self.old_tree.get_file(file_id).readlines(),
288
                          DEVNULL, 
289
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
290
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
291
    
292
        for path, file_id, kind in self.delta.added:
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
293
            print >>self.to_file, '*** added %s %s\tfile-id:%s%s' % (kind,
294
                    encode(path),
295
                    encode(file_id),
296
                    get_text_id_str(file_id))
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.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
305
            print >>self.to_file, '*** renamed %s %s\t=> %s%s' % (kind,
306
                    encode(old_path), encode(new_path),
307
                    get_text_id_str(file_id, text_modified))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
308
            if self.full_rename and kind == 'file':
309
                diff_file(self.old_label + old_path,
310
                          self.old_tree.get_file(file_id).readlines(),
311
                          DEVNULL, 
312
                          [],
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
313
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
314
                diff_file(DEVNULL,
315
                          [],
316
                          self.new_label + new_path,
317
                          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.
318
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
319
            elif text_modified:
320
                    diff_file(self.old_label + old_path,
321
                              self.old_tree.get_file(file_id).readlines(),
322
                              self.new_label + new_path,
323
                              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.
324
                              self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
325
    
326
        for path, file_id, kind in self.delta.modified:
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
327
            print >>self.to_file, '*** modified %s %s%s' % (kind,
328
                    encode(path), get_text_id_str(file_id))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
329
            if kind == 'file':
330
                diff_file(self.old_label + path,
331
                          self.old_tree.get_file(file_id).readlines(),
332
                          self.new_label + path,
333
                          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.
334
                          self.to_file)
0.5.1 by John Arbash Meinel
Just an initial working step.
335
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
336
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.
337
    from bzrlib.diff import compare_trees
338
339
    if to_file is None:
340
        import sys
341
        to_file = sys.stdout
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
342
    revisions = common.canonicalize_revision(branch, revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
343
344
    old_tree, new_tree = _get_trees(branch, revisions)
345
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
346
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
0.5.1 by John Arbash Meinel
Just an initial working step.
347
0.5.5 by John Arbash Meinel
Updated to now include the diffs
348
    meta = MetaInfoHeader(branch, revisions, delta,
349
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
350
    meta.write_meta_info(to_file)
351