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