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