/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
0.5.81 by John Arbash Meinel
Cleaning up from pychecker.
6
import bzrlib
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
7
import os
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
9
from bzrlib.inventory import ROOT_ID
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
10
from bzrlib.errors import BzrCommandError, NotAncestor
0.5.74 by John Arbash Meinel
Fixed handling when base does not exist in local tree, and workaround for older revisions without precursor sha hashes.
11
from bzrlib.trace import warning, mutter
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
12
from collections import deque
13
from bzrlib.revision import (common_ancestor, MultipleRevisionSources,
0.5.115 by John Arbash Meinel
Getting closer to being able to read back the changesets, still broken, though.
14
                             get_intervening_revisions, NULL_REVISION)
15
from bzrlib.diff import internal_diff, compare_trees
0.5.1 by John Arbash Meinel
Just an initial working step.
16
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
17
def _create_ancestry_to_rev(branch, ancestor_rev_id, this_rev_id):
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
18
    """Return a listing of revisions, tracing from this_rev_id to ancestor_rev_id.
19
20
    This attempts to use branch.revision_history() as much as possible. 
21
    Because for changesets, that is generally what you want to show.
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
22
    """
23
    # This is an optimization, when both target and base
24
    # exist in the revision history, we should already have
25
    # a valid listing of revision ancestry.
26
    rh = branch.revision_history()
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
27
    rh_set = set(rh)
28
29
    ancestry = set(branch.get_ancestry(this_rev_id))
30
    if ancestor_rev_id not in ancestry:
31
        raise NotAncestor(this_rev_id, ancestor_rev_id)
32
    # First, if ancestor_rev_id is None, then
33
    # we just need to trace back to the revision history
34
    # and then return the rest
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
35
    if ancestor_rev_id is None:
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
36
        if this_rev_id in rh_set:
37
            rh = rh[:rh.index(this_rev_id)+1]
38
            rh.reverse()
39
            rh.append(None)
40
            return rh
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
41
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
42
    if ancestor_rev_id in rh_set and this_rev_id in rh_set:
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
43
        ancestor_idx = rh.index(ancestor_rev_id)
44
        this_rev_idx = rh.index(this_rev_id)
45
        if ancestor_idx > this_rev_idx:
46
            raise BzrCommandError('Revision {%s} is a child not an ancestor'
47
                    ' of {%s}' % (ancestor_rev_id, this_rev_id))
48
        rh_list = rh[ancestor_idx:this_rev_idx+1]
49
        rh_list.reverse()
50
        # return rh_list
51
52
    # I considered using depth-first search, as it is a little
53
    # bit less resource intensive, and it should favor generating
54
    # paths that are the same as revision_history
55
    # but since breadth-first-search is generally used
56
    # we will use that
57
    # 
58
    # WARNING: In the presence of merges, there are cases where
59
    # breadth first search will return a very different path
60
    # than revision_history or depth first search. Imaging the following:
61
    #
62
    # rh: A -> B -> C -> D -> E -> F
63
    #     |                        ^
64
    #     |                        |
65
    #     +--> Z ------------------+
66
    #
67
    # In this case, Starting with F, looking for A will return
68
    # A-F for a revision_history search, but breadth-first will
69
    # return A,Z,F since it is a much shorter path, and with
70
    # F merging Z, it looks like a shortcut.
71
    #
72
    # But since A-F seems to be the more "correct" history
73
    # for F, we might consider that revision_history should always
74
    # be consulted first, and if not found there, to use breadth
75
    # first search.
76
    checked_rev_ids = set()
77
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
78
    cur_trails = deque([[this_rev_id]])
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
79
    
80
    while len(cur_trails) > 0:
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
81
        cur_trail = cur_trails.popleft()
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
82
        cur_rev_id = cur_trail[-1]
83
        if cur_rev_id in checked_rev_ids:
84
            continue
85
        checked_rev_ids.add(cur_rev_id)
86
87
        if cur_rev_id == ancestor_rev_id:
88
            return cur_trail
89
0.5.71 by John Arbash Meinel
Cleaning up code for latest bzr.
90
        if cur_rev_id in branch.revision_store:
91
            rev = branch.get_revision(cur_rev_id)
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
92
        else:
93
            # Should we just continue here?
94
            warning('Could not find revision for rev: {%s}, unable to'
0.5.71 by John Arbash Meinel
Cleaning up code for latest bzr.
95
                    ' trace ancestry.' % cur_rev_id)
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
96
            continue
97
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
98
        for p_id in rev.parent_ids:
99
            if p_id not in checked_rev_ids:
100
                cur_trails.append(cur_trail + [p_id])
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
101
102
    raise BzrCommandError('Revision id {%s} not an ancestor of {%s}'
103
            % (ancestor_rev_id, this_rev_id))
0.5.1 by John Arbash Meinel
Just an initial working step.
104
105
class MetaInfoHeader(object):
106
    """Maintain all of the header information about this
107
    changeset.
108
    """
109
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
110
    def __init__(self,
111
            base_branch, base_rev_id, base_tree,
112
            target_branch, target_rev_id, target_tree,
113
            delta,
114
            starting_rev_id=None,
115
            full_remove=False, full_rename=False,
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
116
            message=None,
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
117
            base_label = 'orig', target_label = 'mod'):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
118
        """
119
        :param full_remove: Include the full-text for a delete
120
        :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.
121
0.5.5 by John Arbash Meinel
Updated to now include the diffs
122
        """
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
123
        self.base_branch = base_branch
124
        self.base_rev_id = base_rev_id
125
        self.base_tree = base_tree
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
126
        if self.base_rev_id is not None:
127
            self.base_revision = self.base_branch.get_revision(self.base_rev_id)
128
        else:
129
            self.base_revision = None
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
130
131
        self.target_branch = target_branch
132
        self.target_rev_id = target_rev_id
133
        self.target_tree = target_tree
134
0.5.1 by John Arbash Meinel
Just an initial working step.
135
        self.delta = delta
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
136
137
        self.starting_rev_id = starting_rev_id
138
0.5.5 by John Arbash Meinel
Updated to now include the diffs
139
        self.full_remove=full_remove
140
        self.full_rename=full_rename
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
141
142
        self.base_label = base_label
0.5.71 by John Arbash Meinel
Cleaning up code for latest bzr.
143
        self.target_label = target_label
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
144
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
145
        self.to_file = None
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
146
        #self.revno = None
147
        #self.parent_revno = None
148
149
        # These are entries in the header.
150
        # They will be repeated in the footer,
151
        # only if they have changed
152
        self.date = None
153
        self.committer = None
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
154
        self.message = 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.
155
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
156
        self._get_revision_list()
0.5.1 by John Arbash Meinel
Just an initial working step.
157
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
158
    def _get_revision_list(self):
0.5.1 by John Arbash Meinel
Just an initial working step.
159
        """This generates the list of all revisions from->to.
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
160
        It fills out the internal self.revision_list with Revision
161
        entries which should be in the changeset.
0.5.1 by John Arbash Meinel
Just an initial working step.
162
        """
0.5.113 by John Arbash Meinel
Small performance enhancement.
163
        # Performance, without locking here, a new lock is taken and
164
        # broken for every revision (6k+ total locks for the bzr.dev tree)
165
        self.target_branch.lock_read()
166
        self.base_branch.lock_read()
167
        try:
168
            source = MultipleRevisionSources(self.target_branch, self.base_branch)
169
            if self.starting_rev_id is None:
0.5.115 by John Arbash Meinel
Getting closer to being able to read back the changesets, still broken, though.
170
                if self.base_rev_id is None:
171
                    self.starting_rev_id = NULL_REVISION
172
                else:
173
                    self.starting_rev_id = common_ancestor(self.target_rev_id, 
174
                        self.base_rev_id, source)
0.5.113 by John Arbash Meinel
Small performance enhancement.
175
176
            rev_id_list = get_intervening_revisions(self.starting_rev_id,
177
                self.target_rev_id, source, self.target_branch.revision_history())
178
179
            self.revision_list = [source.get_revision(rid) for rid in rev_id_list]
180
        finally:
181
            self.base_branch.unlock()
182
            self.target_branch.unlock()
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
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
184
    def _write(self, txt, key=None, encode=True, indent=1):
185
        from common import encode as _encode
186
        if encode:
187
            def write(txt):
188
                self.to_file.write(_encode(txt))
189
        else:
190
            def write(txt):
191
                self.to_file.write(txt)
192
        if indent > 0:
193
            write('#' + (' ' * indent))
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
194
        if key:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
195
            if txt:
196
                write('%s: %s\n' % (key, txt))
197
            else:
198
                write('%s:\n' % key)
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
199
        else:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
200
            write('%s\n' % (txt,))
0.5.1 by John Arbash Meinel
Just an initial working step.
201
202
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
203
        """Write out the meta-info portion to the supplied file.
204
205
        :param to_file: Write out the meta information to the supplied
206
                        file
207
        """
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
208
        self.to_file = to_file
209
210
        self._write_header()
211
        self._write_diffs()
212
        self._write_footer()
213
214
    def _write_header(self):
215
        """Write the stuff that comes before the patches."""
0.5.81 by John Arbash Meinel
Cleaning up from pychecker.
216
        from common import format_highres_date, get_header
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
        write = self._write
218
0.5.81 by John Arbash Meinel
Cleaning up from pychecker.
219
        for line in get_header():
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
220
            write(line)
221
0.5.27 by John Arbash Meinel
Now capable of generating rollup changesets.
222
        # Print out the basic information about the 'target' revision
223
        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.
224
        write(rev.committer, key='committer')
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
225
        self.committer = rev.committer
226
        self.date = format_highres_date(rev.timestamp, offset=rev.timezone)
227
        write(self.date, key='date')
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
228
        if self.message is None:
229
            if rev.message is not None:
230
                self.message = rev.message
231
        if self.message:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
232
            write('', key='message')
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
233
            for line in self.message.split('\n'):
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
234
                write(txt=line, indent=4)
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
235
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
236
        write('') # line with just '#'
237
        write('', indent=0) # Empty line
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
238
239
    def _write_footer(self):
240
        """Write the stuff that comes after the patches.
241
242
        This is meant to be more meta-information, which people probably don't want
243
        to read, but which is required for proper bzr operation.
244
        """
245
        write = self._write
246
0.5.57 by John Arbash Meinel
Simplified the header, only output base if it is not the expected one.
247
        # What should we print out for an Empty base revision?
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
248
        if len(self.revision_list[0].parent_ids) == 0:
0.5.59 by John Arbash Meinel
Several fixes for handling the case where you are doing a changeset against revno=0 (Null base)
249
            assumed_base = None
250
        else:
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
251
            assumed_base = self.revision_list[0].parent_ids[0]
252
0.5.59 by John Arbash Meinel
Several fixes for handling the case where you are doing a changeset against revno=0 (Null base)
253
        if (self.base_revision is not None 
254
                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.
255
            base = self.base_revision.revision_id
256
            write(base, key='base')
0.5.74 by John Arbash Meinel
Fixed handling when base does not exist in local tree, and workaround for older revisions without precursor sha hashes.
257
            write(self.base_branch.get_revision_sha1(base), key='base sha1')
0.5.17 by John Arbash Meinel
adding apply-changset, plus more meta information.
258
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
259
        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.
260
261
    def _write_revisions(self):
262
        """Not used. Used for writing multiple revisions."""
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
263
        from common import format_highres_date, encode
264
265
        write = self._write
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
266
0.5.3 by John Arbash Meinel
Added a couple more bits
267
        for rev in self.revision_list:
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
268
            rev_id = rev.revision_id
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
269
            write(rev_id, key='revision')
270
            write(self.target_branch.get_revision_sha1(rev_id),
271
                    key = 'sha1', indent=4)
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
272
            if rev.committer != self.committer:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
273
                write(rev.committer, key='committer', indent=4)
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
274
            date = format_highres_date(rev.timestamp, rev.timezone)
275
            if date != self.date:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
276
                write(date, key='date', indent=4)
277
            write(rev.inventory_sha1, key='inventory sha1', indent=4)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
278
            if len(rev.parent_ids) > 0:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
279
                write(txt='', key='parents', indent=4)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
280
                for p_id in rev.parent_ids:
281
                    p_sha1 = self.target_branch.get_revision_sha1(p_id)
0.5.74 by John Arbash Meinel
Fixed handling when base does not exist in local tree, and workaround for older revisions without precursor sha hashes.
282
                    if p_sha1 is None:
283
                        warning('Rev id {%s} parent {%s} missing sha hash.'
284
                                % (rev_id, p_id))
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
285
                        write(p_id + '\t' + p_sha1, indent=7)
286
                    else:
287
                        write(p_id, indent=7)
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
288
            if rev.message and rev.message != self.message:
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
289
                write('', key='message', indent=4)
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
290
                for line in rev.message.split('\n'):
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
291
                    write(line, indent=7)
0.5.25 by John Arbash Meinel
Added some work to allow rollup revisions, and handling multiple parents.
292
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
293
    def _write_diffs(self):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
294
        """Write out the specific diffs"""
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
295
        def pjoin(*args):
296
            # Only forward slashes in changesets
297
            return os.path.join(*args).replace('\\', '/')
298
299
        def _maybe_diff(old_label, old_path, old_tree, file_id,
300
                        new_label, new_path, new_tree, text_modified,
301
                        kind, to_file, diff_file):
302
            if text_modified:
303
                new_entry = new_tree.inventory[file_id]
304
                old_tree.inventory[file_id].diff(diff_file,
305
                                                 pjoin(old_label, old_path), old_tree,
306
                                                 pjoin(new_label, new_path), new_entry, 
307
                                                 new_tree, to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
308
        DEVNULL = '/dev/null'
309
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
310
        diff_file = internal_diff
311
        # Get the target tree so that we can check for
312
        # Appropriate text ids.
0.5.73 by John Arbash Meinel
Some fixups for gen_changeset.
313
        rev_id = self.target_rev_id
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
314
315
        new_label = self.target_label
316
        new_tree = self.target_tree
317
318
        old_tree = self.base_tree
319
        old_label = self.base_label
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
320
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
321
        write = self._write
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
322
        to_file = self.to_file
323
324
325
        def get_rev_id_str(file_id, kind):
326
            last_changed_rev_id = new_tree.inventory[file_id].revision
327
328
            if rev_id != last_changed_rev_id:
329
                return ' // last-changed:' + last_changed_rev_id
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
330
            else:
331
                return ''
332
0.5.5 by John Arbash Meinel
Updated to now include the diffs
333
        for path, file_id, kind in self.delta.removed:
0.5.100 by John Arbash Meinel
Switching from *** to ===
334
            write('=== removed %s %s' % (kind, path), indent=0)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
335
            if self.full_remove:
336
                old_tree.inventory[file_id].diff(diff_file, pjoin(old_label, path), old_tree,
337
                                                 DEVNULL, None, None, to_file)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
338
        for path, file_id, kind in self.delta.added:
0.5.100 by John Arbash Meinel
Switching from *** to ===
339
            write('=== added %s %s // file-id:%s%s' % (kind,
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
340
                    path, file_id, get_rev_id_str(file_id, kind)),
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
341
                    indent=0)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
342
            new_tree.inventory[file_id].diff(diff_file, pjoin(new_label, path), new_tree,
343
                                             DEVNULL, None, None, to_file, 
344
                                             reverse=True)
345
        for (old_path, new_path, file_id, kind,
346
             text_modified, meta_modified) in self.delta.renamed:
347
            # TODO: Handle meta_modified
348
            #prop_str = get_prop_change(meta_modified)
0.5.100 by John Arbash Meinel
Switching from *** to ===
349
            write('=== renamed %s %s // %s%s' % (kind,
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
350
                    old_path, new_path,
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
351
                    get_rev_id_str(file_id, kind)),
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
352
                    indent=0)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
353
            if self.full_rename:
354
                # Looks like a delete + add
355
                old_tree.inventory[file_id].diff(diff_file, pjoin(old_label, path), old_tree,
356
                                                 DEVNULL, None, None, to_file)
357
                new_tree.inventory[file_id].diff(diff_file, pjoin(new_label, path), new_tree,
358
                                                 DEVNULL, None, None, to_file, 
359
                                                 reverse=True)
360
            else:
361
                _maybe_diff(old_label, old_path, old_tree, file_id,
362
                            new_label, new_path, new_tree,
363
                            text_modified, kind, to_file, diff_file)
364
365
        for (path, file_id, kind,
366
             text_modified, meta_modified) in self.delta.modified:
367
            # TODO: Handle meta_modified
368
            #prop_str = get_prop_change(meta_modified)
0.5.100 by John Arbash Meinel
Switching from *** to ===
369
            write('=== modified %s %s%s' % (kind,
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
370
                    path, get_rev_id_str(file_id, kind)),
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
371
                    indent=0)
0.5.112 by John Arbash Meinel
Upgrading to v5 (ignoring compatibility)
372
            _maybe_diff(old_label, path, old_tree, file_id,
373
                        new_label, path, new_tree,
374
                        text_modified, kind, to_file, diff_file)
375
 
0.5.1 by John Arbash Meinel
Just an initial working step.
376
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
377
def show_changeset(base_branch, base_rev_id,
378
        target_branch, target_rev_id,
379
        starting_rev_id = None,
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
380
        to_file=None, include_full_diff=False,
381
        message=None):
0.5.1 by John Arbash Meinel
Just an initial working step.
382
383
    if to_file is None:
384
        import sys
385
        to_file = sys.stdout
0.5.71 by John Arbash Meinel
Cleaning up code for latest bzr.
386
    base_tree = base_branch.revision_tree(base_rev_id)
387
    target_tree = target_branch.revision_tree(target_rev_id)
0.5.68 by John Arbash Meinel
(broken), starting to change the syntax of the command to allow cset to take a base and a target.
388
389
    delta = compare_trees(base_tree, target_tree, want_unchanged=False)
390
391
    meta = MetaInfoHeader(base_branch, base_rev_id, base_tree,
392
            target_branch, target_rev_id, target_tree,
393
            delta,
394
            starting_rev_id=starting_rev_id,
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
395
            full_rename=include_full_diff, full_remove=include_full_diff,
396
            message=message)
0.5.1 by John Arbash Meinel
Just an initial working step.
397
    meta.write_meta_info(to_file)
398