/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?
173
        assumed_base = self.revision_list[0].parents[0].revision_id
174
        if self.base_revision.revision_id != assumed_base:
175
            base = self.base_revision.revision_id
176
            write(base, key='base')
177
            write(self.branch.get_revision_sha1(base), key='base sha1')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
178
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
179
        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.
180
0.5.38 by John Arbash Meinel
Working on updating the information to be minimalistic
181
        #self._write_ids()
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
182
        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.
183
184
    def _write_revisions(self):
185
        """Not used. Used for writing multiple revisions."""
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
186
        from common import format_highres_date
187
0.5.3 by John Arbash Meinel
Added a couple more bits
188
        for rev in self.revision_list:
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
189
            rev_id = rev.revision_id
190
            self.to_file.write('# revision: %s\n' % rev_id)
191
            self.to_file.write('#    sha1: %s\n' % 
192
                self.branch.get_revision_sha1(rev_id))
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
193
            if rev.committer != self.committer:
194
                self.to_file.write('#    committer: %s\n' % rev.committer)
195
            date = format_highres_date(rev.timestamp, rev.timezone)
196
            if date != self.date:
197
                self.to_file.write('#    date: %s\n' % date)
198
            if rev.inventory_id != rev_id:
199
                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.
200
            self.to_file.write('#    inventory sha1: %s\n' % rev.inventory_sha1)
201
            self.to_file.write('#    parents:\n')
202
            for parent in rev.parents:
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
203
                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.
204
                    parent.revision_id,
205
                    parent.revision_sha1))
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
206
            if rev.message and rev.message != self.message:
207
                self.to_file.write('#    message:\n')
208
                for line in rev.message.split('\n'):
209
                    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.
210
211
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
212
    def _write_ids(self):
213
        if hasattr(self.branch, 'get_root_id'):
214
            root_id = self.branch.get_root_id()
215
        else:
216
            root_id = ROOT_ID
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
217
218
        old_ids = set()
219
        new_ids = set()
220
221
        for path, file_id, kind in self.delta.removed:
222
            old_ids.add(file_id)
223
        for path, file_id, kind in self.delta.added:
224
            new_ids.add(file_id)
225
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
226
            old_ids.add(file_id)
227
            new_ids.add(file_id)
228
        for path, file_id, kind in self.delta.modified:
229
            new_ids.add(file_id)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
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
        self._write(root_id, key='tree root id')
232
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
233
        def write_ids(tree, id_set, name):
234
            if len(id_set) > 0:
235
                self.to_file.write('# %s ids:\n' % name)
236
            seen_ids = set([root_id])
237
            while len(id_set) > 0:
238
                file_id = id_set.pop()
239
                if file_id in seen_ids:
240
                    continue
241
                seen_ids.add(file_id)
242
                ie = tree.inventory[file_id]
243
                if ie.parent_id not in seen_ids:
244
                    id_set.add(ie.parent_id)
245
                path = tree.inventory.id2path(file_id)
246
                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.
247
                        % (path, file_id,
248
                            ie.parent_id))
0.5.15 by John Arbash Meinel
Created an apply-changeset function, and modified output for better parsing.
249
        write_ids(self.new_tree, new_ids, 'file')
250
        write_ids(self.old_tree, old_ids, 'old file')
0.5.5 by John Arbash Meinel
Updated to now include the diffs
251
0.5.38 by John Arbash Meinel
Working on updating the information to be minimalistic
252
    def _write_text_ids(self):
253
        pass
254
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
255
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
256
        """Write out the specific diffs"""
257
        from bzrlib.diff import internal_diff, external_diff
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
258
        from common import encode
0.5.5 by John Arbash Meinel
Updated to now include the diffs
259
        DEVNULL = '/dev/null'
260
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
261
        diff_file = internal_diff
262
        # Get the target tree so that we can check for
263
        # Appropriate text ids.
264
        rev_id = self.revision_list[-1].revision_id
265
        tree = self.branch.revision_tree(rev_id)
266
267
268
        def get_text_id_str(file_id, modified=True):
269
            """This returns an empty string if guess_text_id == real_text_id.
270
            Otherwise it returns a string suitable for printing, indicating
271
            the file's id.
272
            """
273
            guess_id = common.guess_text_id(tree, file_id, rev_id,
274
                    modified=modified)
275
            real_id = tree.inventory[file_id].text_id
276
            if guess_id != real_id:
277
                return '\ttext-id:' + encode(real_id)
278
            else:
279
                return ''
280
0.5.5 by John Arbash Meinel
Updated to now include the diffs
281
282
        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.
283
            # We don't care about text ids for removed files
284
            print >>self.to_file, '*** removed %s %s' % (kind,
285
                    encode(path))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
286
            if kind == 'file' and self.full_remove:
287
                diff_file(self.old_label + path,
288
                          self.old_tree.get_file(file_id).readlines(),
289
                          DEVNULL, 
290
                          [],
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.added:
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
294
            print >>self.to_file, '*** added %s %s\tfile-id:%s%s' % (kind,
295
                    encode(path),
296
                    encode(file_id),
297
                    get_text_id_str(file_id))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
298
            if kind == 'file':
299
                diff_file(DEVNULL,
300
                          [],
301
                          self.new_label + path,
302
                          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.
303
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
304
    
305
        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.
306
            print >>self.to_file, '*** renamed %s %s\t=> %s%s' % (kind,
307
                    encode(old_path), encode(new_path),
308
                    get_text_id_str(file_id, text_modified))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
309
            if self.full_rename and kind == 'file':
310
                diff_file(self.old_label + old_path,
311
                          self.old_tree.get_file(file_id).readlines(),
312
                          DEVNULL, 
313
                          [],
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
                diff_file(DEVNULL,
316
                          [],
317
                          self.new_label + new_path,
318
                          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.
319
                          self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
320
            elif text_modified:
321
                    diff_file(self.old_label + old_path,
322
                              self.old_tree.get_file(file_id).readlines(),
323
                              self.new_label + new_path,
324
                              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.
325
                              self.to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
326
    
327
        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.
328
            print >>self.to_file, '*** modified %s %s%s' % (kind,
329
                    encode(path), get_text_id_str(file_id))
0.5.5 by John Arbash Meinel
Updated to now include the diffs
330
            if kind == 'file':
331
                diff_file(self.old_label + path,
332
                          self.old_tree.get_file(file_id).readlines(),
333
                          self.new_label + path,
334
                          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.
335
                          self.to_file)
0.5.1 by John Arbash Meinel
Just an initial working step.
336
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
337
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.
338
    from bzrlib.diff import compare_trees
339
340
    if to_file is None:
341
        import sys
342
        to_file = sys.stdout
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
343
    revisions = common.canonicalize_revision(branch, revisions)
0.5.1 by John Arbash Meinel
Just an initial working step.
344
345
    old_tree, new_tree = _get_trees(branch, revisions)
346
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
347
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
0.5.1 by John Arbash Meinel
Just an initial working step.
348
0.5.5 by John Arbash Meinel
Updated to now include the diffs
349
    meta = MetaInfoHeader(branch, revisions, delta,
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