/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.5 by John Arbash Meinel
Updated to now include the diffs
8
try:
9
    set
10
except NameError:
11
    from sets import Set as set
12
0.5.1 by John Arbash Meinel
Just an initial working step.
13
def _canonicalize_revision(branch, revision=None):
14
    """Turn some sort of revision information into a single
15
    set of from-to revision ids.
16
0.5.3 by John Arbash Meinel
Added a couple more bits
17
    A revision id can be None if there is no associated revison.
18
19
    :return: (old, new)
0.5.1 by John Arbash Meinel
Just an initial working step.
20
    """
21
    # This is a little clumsy because revision parsing may return
22
    # a single entry, or a list
23
    if revision is None:
24
        old, new = None, None
25
    elif isinstance(revision, (list, tuple)):
26
        if len(revision) == 0:
27
            old, new = None, None
28
        elif len(revision) == 1:
29
            old = revision[0]
30
            new = None
31
        elif len(revision) == 2:
32
            old = revision[0]
33
            new = revision[1]
34
        else:
35
            raise bzrlib.errors.BzrCommandError('revision can be'
36
                    ' at most 2 entries.')
37
    else:
38
        old = revision
39
        new = None
40
41
    if new is not None:
42
        new = branch.lookup_revision(new)
0.5.3 by John Arbash Meinel
Added a couple more bits
43
    if old is None:
44
        old = branch.last_patch()
0.5.1 by John Arbash Meinel
Just an initial working step.
45
    else:
0.5.3 by John Arbash Meinel
Added a couple more bits
46
        old = branch.lookup_revision(old)
0.5.1 by John Arbash Meinel
Just an initial working step.
47
48
    return old, new
49
50
def _get_trees(branch, revisions):
51
    """Get the old and new trees based on revision.
52
    """
53
    if revisions[0] is None:
54
        old_tree = branch.basis_tree()
55
    else:
56
        old_tree = branch.revision_tree(revisions[0])
57
58
    if revisions[1] is None:
59
        new_tree = branch.working_tree()
60
    else:
61
        new_tree = branch.revision_tree(revisions[1])
62
    return old_tree, new_tree
63
64
def _fake_working_revision(branch):
65
    """Fake a Revision object for the working tree."""
66
    from bzrlib.revision import Revision
67
    import time
68
    from bzrlib.osutils import local_time_offset, \
69
            username
70
71
    precursor = branch.last_patch()
72
    precursor_sha1 = branch.get_revision_sha1(precursor)
73
74
    return Revision(timestamp=time.time(),
75
            timezone=local_time_offset(),
76
            committer=username(),
77
            precursor=precursor,
78
            precursor_sha1=precursor_sha1)
79
80
81
class MetaInfoHeader(object):
82
    """Maintain all of the header information about this
83
    changeset.
84
    """
85
0.5.5 by John Arbash Meinel
Updated to now include the diffs
86
    def __init__(self, branch, revisions, delta,
87
            full_remove=False, full_rename=False,
88
            external_diff_options = None,
89
            new_tree=None, old_tree=None,
90
            old_label = '', new_label = ''):
91
        """
92
        :param full_remove: Include the full-text for a delete
93
        :param full_rename: Include an add+delete patch for a rename
94
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
95
        self.branch = branch
96
        self.delta = delta
97
        self._get_revision_list(revisions)
0.5.5 by John Arbash Meinel
Updated to now include the diffs
98
        self.full_remove=full_remove
99
        self.full_rename=full_rename
100
        self.external_diff_options = external_diff_options
101
        self.old_label = old_label
102
        self.new_label = new_label
103
        self.old_tree = old_tree
104
        self.new_tree = new_tree
0.5.1 by John Arbash Meinel
Just an initial working step.
105
106
    def _get_revision_list(self, revisions):
107
        """This generates the list of all revisions from->to.
108
        """
109
        old_revno = None
110
        new_revno = None
111
        rh = self.branch.revision_history()
112
        for revno, rev in enumerate(rh):
113
            if rev == revisions[0]:
114
                old_revno = revno
115
            if rev == revisions[1]:
116
                new_revno = revno
117
0.5.3 by John Arbash Meinel
Added a couple more bits
118
        self.revision_list = []
0.5.1 by John Arbash Meinel
Just an initial working step.
119
        if old_revno is None:
0.5.3 by John Arbash Meinel
Added a couple more bits
120
            self.base_revision = None
121
            old_revno = 1
122
        else:
123
            self.base_revision = self.branch.get_revision(rh[old_revno])
0.5.1 by John Arbash Meinel
Just an initial working step.
124
        if new_revno is not None:
0.5.3 by John Arbash Meinel
Added a couple more bits
125
            for rev_id in rh[old_revno+1:new_revno+1]:
0.5.1 by John Arbash Meinel
Just an initial working step.
126
                self.revision_list.append(self.branch.get_revision(rev_id))
127
        else:
0.5.3 by John Arbash Meinel
Added a couple more bits
128
            for rev_id in rh[old_revno+1:]:
0.5.1 by John Arbash Meinel
Just an initial working step.
129
                self.revision_list.append(self.branch.get_revision(rev_id))
130
            self.revision_list.append(_fake_working_revision(self.branch))
131
132
    def write_meta_info(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
133
        """Write out the meta-info portion to the supplied file.
134
135
        :param to_file: Write out the meta information to the supplied
136
                        file
137
        """
0.5.1 by John Arbash Meinel
Just an initial working step.
138
        from bzrlib.osutils import username
0.5.3 by John Arbash Meinel
Added a couple more bits
139
        def write(txt, key=None):
140
            if key:
141
                to_file.write('# ' + key + ': ' + txt + '\n')
142
            else:
143
                to_file.write('# ' + txt + '\n')
144
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
145
        write('Bazaar-NG (bzr) changeset v0.0.5')
146
        write('This changeset can be applied with bzr apply-changeset')
147
        write('')
148
0.5.3 by John Arbash Meinel
Added a couple more bits
149
        write(username(), key='committer')
150
151
        if self.base_revision:
152
            write(self.base_revision.revision_id, key='precursor')
153
154
        first = True
155
        for rev in self.revision_list:
156
            if rev.revision_id is not None:
157
                if first:
158
                    write(rev.revision_id, key='revisions')
159
                    first = False
160
                else:
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
161
                    write(' '*11 + rev.revision_id)
162
0.5.6 by John Arbash Meinel
Moving id info to end.
163
        self._write_diffs(to_file)
164
        self._write_ids(to_file)
165
166
    def _write_ids(self, to_file):
0.5.5 by John Arbash Meinel
Updated to now include the diffs
167
        seen_ids = set(['TREE_ROOT'])
168
        need_ids = set()
169
170
        def _write_entry(file_id, path=None):
171
            if file_id in self.new_tree.inventory:
172
                ie = self.new_tree.inventory[file_id]
173
            elif file_id in self.old_tree.inventory:
174
                ie = self.new_tree.inventory[file_id]
175
            else:
176
                ie = None
177
            if not path and ie:
178
                path = ie.name
179
            to_file.write(path.encode('utf-8'))
180
            to_file.write('\t')
181
            to_file.write(file_id.encode('utf-8'))
182
            if ie and ie.parent_id:
183
                to_file.write('\t')
184
                to_file.write(ie.parent_id.encode('utf-8'))
185
                if ie.parent_id not in seen_ids:
186
                    need_ids.add(ie.parent_id)
187
            seen_ids.add(ie.file_id)
188
            to_file.write('\n')
189
190
        class _write_kind(object):
191
            def __init__(self, kind):
192
                self.first = True
193
                self.kind = kind
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
194
            def __call__(self, info):
195
                if self.first:
196
                    self.first = False
0.5.5 by John Arbash Meinel
Updated to now include the diffs
197
                    to_file.write('# %s ids: ' % self.kind)
0.5.4 by John Arbash Meinel
Added printout of file ids, need directory ids
198
                else:
0.5.5 by John Arbash Meinel
Updated to now include the diffs
199
                    to_file.write('#')
200
                    to_file.write(' ' * (len(self.kind) + 7))
201
                _write_entry(info[1], info[0])
202
203
        def _write_all(kind):
204
            writer = _write_kind(kind)
205
            for info in self.delta.removed:
206
                if info[2] == kind:
207
                    writer(info)
208
            for info in self.delta.added:
209
                if info[2] == kind:
210
                    writer(info)
211
            for info in self.delta.renamed:
212
                if info[3] == kind:
213
                    writer(info[1:2])
214
            for info in self.delta.modified:
215
                if info[2] == kind:
216
                    writer(info)
217
218
        _write_all('file')
219
        _write_all('directory')
220
221
        first = True
222
        while len(need_ids) > 0:
223
            file_id = need_ids.pop()
224
            if file_id in seen_ids:
225
                continue
226
            seen_ids.add(file_id)
227
            if first:
228
                to_file.write('# parent ids: ')
229
                first = False
230
            else:
231
                to_file.write('#             ')
232
            _write_entry(file_id)
233
234
235
    def _write_diffs(self, to_file):
236
        """Write out the specific diffs"""
237
        from bzrlib.diff import internal_diff, external_diff
238
        DEVNULL = '/dev/null'
239
240
        if self.external_diff_options:
241
            assert isinstance(self.external_diff_options, basestring)
242
            opts = self.external_diff_options.split()
243
            def diff_file(olab, olines, nlab, nlines, to_file):
244
                external_diff(olab, olines, nlab, nlines, to_file, opts)
245
        else:
246
            diff_file = internal_diff
247
248
        for path, file_id, kind in self.delta.removed:
249
            print >>to_file, '*** removed %s %r' % (kind, path)
250
            if kind == 'file' and self.full_remove:
251
                diff_file(self.old_label + path,
252
                          self.old_tree.get_file(file_id).readlines(),
253
                          DEVNULL, 
254
                          [],
255
                          to_file)
256
    
257
        for path, file_id, kind in self.delta.added:
258
            print >>to_file, '*** added %s %r' % (kind, path)
259
            if kind == 'file':
260
                diff_file(DEVNULL,
261
                          [],
262
                          self.new_label + path,
263
                          self.new_tree.get_file(file_id).readlines(),
264
                          to_file)
265
    
266
        for old_path, new_path, file_id, kind, text_modified in self.delta.renamed:
267
            print >>to_file, '*** renamed %s %r => %r' % (kind, old_path, new_path)
268
            if self.full_rename and kind == 'file':
269
                diff_file(self.old_label + old_path,
270
                          self.old_tree.get_file(file_id).readlines(),
271
                          DEVNULL, 
272
                          [],
273
                          to_file)
274
                diff_file(DEVNULL,
275
                          [],
276
                          self.new_label + new_path,
277
                          self.new_tree.get_file(file_id).readlines(),
278
                          to_file)
279
            elif text_modified:
280
                    diff_file(self.old_label + old_path,
281
                              self.old_tree.get_file(file_id).readlines(),
282
                              self.new_label + new_path,
283
                              self.new_tree.get_file(file_id).readlines(),
284
                              to_file)
285
    
286
        for path, file_id, kind in self.delta.modified:
287
            print >>to_file, '*** modified %s %r' % (kind, path)
288
            if kind == 'file':
289
                diff_file(self.old_label + path,
290
                          self.old_tree.get_file(file_id).readlines(),
291
                          self.new_label + path,
292
                          self.new_tree.get_file(file_id).readlines(),
293
                          to_file)
0.5.1 by John Arbash Meinel
Just an initial working step.
294
295
def show_changeset(branch, revision=None, specific_files=None,
0.5.5 by John Arbash Meinel
Updated to now include the diffs
296
        external_diff_options=None, to_file=None,
297
        include_full_diff=False):
0.5.1 by John Arbash Meinel
Just an initial working step.
298
    from bzrlib.diff import compare_trees
299
300
    if to_file is None:
301
        import sys
302
        to_file = sys.stdout
303
    revisions = _canonicalize_revision(branch, revision)
304
305
    old_tree, new_tree = _get_trees(branch, revisions)
306
307
    delta = compare_trees(old_tree, new_tree, want_unchanged=False,
308
                          specific_files=specific_files)
309
0.5.5 by John Arbash Meinel
Updated to now include the diffs
310
    meta = MetaInfoHeader(branch, revisions, delta,
311
            external_diff_options=external_diff_options,
312
            old_tree=old_tree, new_tree=new_tree)
0.5.1 by John Arbash Meinel
Just an initial working step.
313
    meta.write_meta_info(to_file)
314
315