/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/delta.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
 
from breezy import (
 
17
from bzrlib import (
20
18
    osutils,
21
19
    )
22
 
from .sixish import (
23
 
    StringIO,
24
 
    )
25
 
from .trace import is_quiet
 
20
from bzrlib.trace import is_quiet
26
21
 
27
22
 
28
23
class TreeDelta(object):
58
53
 
59
54
    The lists are normally sorted when the delta is created.
60
55
    """
61
 
 
62
56
    def __init__(self):
63
57
        self.added = []
64
58
        self.removed = []
67
61
        self.modified = []
68
62
        self.unchanged = []
69
63
        self.unversioned = []
70
 
        self.missing = []
71
64
 
72
65
    def __eq__(self, other):
73
66
        if not isinstance(other, TreeDelta):
74
67
            return False
75
68
        return self.added == other.added \
76
 
            and self.removed == other.removed \
77
 
            and self.renamed == other.renamed \
78
 
            and self.modified == other.modified \
79
 
            and self.unchanged == other.unchanged \
80
 
            and self.kind_changed == other.kind_changed \
81
 
            and self.unversioned == other.unversioned
 
69
               and self.removed == other.removed \
 
70
               and self.renamed == other.renamed \
 
71
               and self.modified == other.modified \
 
72
               and self.unchanged == other.unchanged \
 
73
               and self.kind_changed == other.kind_changed \
 
74
               and self.unversioned == other.unversioned
82
75
 
83
76
    def __ne__(self, other):
84
77
        return not (self == other)
87
80
        return "TreeDelta(added=%r, removed=%r, renamed=%r," \
88
81
            " kind_changed=%r, modified=%r, unchanged=%r," \
89
82
            " unversioned=%r)" % (self.added,
90
 
                                  self.removed, self.renamed, self.kind_changed, self.modified,
91
 
                                  self.unchanged, self.unversioned)
 
83
            self.removed, self.renamed, self.kind_changed, self.modified,
 
84
            self.unchanged, self.unversioned)
92
85
 
93
86
    def has_changed(self):
94
87
        return bool(self.modified
113
106
 
114
107
    def get_changes_as_text(self, show_ids=False, show_unchanged=False,
115
108
                            short_status=False):
116
 
        output = StringIO()
 
109
        import StringIO
 
110
        output = StringIO.StringIO()
117
111
        report_delta(output, self, short_status, show_ids, show_unchanged)
118
112
        return output.getvalue()
119
113
 
127
121
 
128
122
    for (file_id, path, content_change, versioned, parent_id, name, kind,
129
123
         executable) in new_tree.iter_changes(old_tree, want_unchanged,
130
 
                                              specific_files, extra_trees=extra_trees,
131
 
                                              require_versioned=require_versioned,
132
 
                                              want_unversioned=want_unversioned):
 
124
            specific_files, extra_trees=extra_trees,
 
125
            require_versioned=require_versioned,
 
126
            want_unversioned=want_unversioned):
133
127
        if versioned == (False, False):
134
128
            delta.unversioned.append((path[1], None, kind[1]))
135
129
            continue
143
137
            else:
144
138
                delta.removed.append((path[0], file_id, kind[0]))
145
139
        elif fully_present[0] is False:
146
 
            delta.missing.append((path[1], file_id, kind[1]))
 
140
            continue
147
141
        elif name[0] != name[1] or parent_id[0] != parent_id[1]:
148
142
            # If the name changes, or the parent_id changes, we have a rename
149
143
            # (if we move a parent, that doesn't count as a rename for the
166
160
    delta.removed.sort()
167
161
    delta.added.sort()
168
162
    delta.renamed.sort()
169
 
 
170
 
    def missing_key(change):
171
 
        return (change[0] or '', change[1])
172
 
    delta.missing.sort(key=missing_key)
173
163
    # TODO: jam 20060529 These lists shouldn't need to be sorted
174
164
    #       since we added them in alphabetical order.
175
165
    delta.modified.sort()
176
166
    delta.unchanged.sort()
177
 
    delta.unversioned.sort()
178
167
 
179
168
    return delta
180
169
 
183
172
    """Report changes between two trees"""
184
173
 
185
174
    def __init__(self, output=None, suppress_root_add=True,
186
 
                 output_file=None, unversioned_filter=None, view_info=None,
187
 
                 classify=True):
 
175
                 output_file=None, unversioned_filter=None, view_info=None):
188
176
        """Constructor
189
177
 
190
178
        :param output: a function with the signature of trace.note, i.e.
199
187
        :param view_info: A tuple of view_name,view_files if only
200
188
            items inside a view are to be reported on, or None for
201
189
            no view filtering.
202
 
        :param classify: Add special symbols to indicate file kind.
203
190
        """
204
191
        if output_file is not None:
205
192
            if output is not None:
206
193
                raise BzrError('Cannot specify both output and output_file')
207
 
 
208
194
            def output(fmt, *args):
209
195
                output_file.write((fmt % args) + '\n')
210
196
        self.output = output
211
197
        if self.output is None:
212
 
            from . import trace
 
198
            from bzrlib import trace
213
199
            self.output = trace.note
214
200
        self.suppress_root_add = suppress_root_add
215
201
        self.modified_map = {'kind changed': 'K',
216
202
                             'unchanged': ' ',
217
203
                             'created': 'N',
218
204
                             'modified': 'M',
219
 
                             'deleted': 'D',
220
 
                             'missing': '!',
221
 
                             }
222
 
        self.versioned_map = {'added': '+',  # versioned target
223
 
                              'unchanged': ' ',  # versioned in both
224
 
                              'removed': '-',  # versioned in source
225
 
                              'unversioned': '?',  # versioned in neither
 
205
                             'deleted': 'D'}
 
206
        self.versioned_map = {'added': '+', # versioned target
 
207
                              'unchanged': ' ', # versioned in both
 
208
                              'removed': '-', # versioned in source
 
209
                              'unversioned': '?', # versioned in neither
226
210
                              }
227
211
        self.unversioned_filter = unversioned_filter
228
 
        if classify:
229
 
            self.kind_marker = osutils.kind_marker
230
 
        else:
231
 
            self.kind_marker = lambda kind: ''
232
212
        if view_info is None:
233
213
            self.view_name = None
234
214
            self.view_files = []
258
238
        if paths[1] == '' and versioned == 'added' and self.suppress_root_add:
259
239
            return
260
240
        if self.view_files and not osutils.is_inside_any(self.view_files,
261
 
                                                         paths[1]):
 
241
            paths[1]):
262
242
            return
263
243
        if versioned == 'unversioned':
264
244
            # skip ignored unversioned files if needed.
272
252
        # ( the path is different OR
273
253
        #   the kind is different)
274
254
        if (versioned == 'unchanged' and
275
 
                (renamed or modified == 'kind changed')):
 
255
            (renamed or modified == 'kind changed')):
276
256
            if renamed:
277
257
                # on a rename, we show old and new
278
258
                old_path, path = paths
283
263
            # if the file is not missing in the source, we show its kind
284
264
            # when we show two paths.
285
265
            if kind[0] is not None:
286
 
                old_path += self.kind_marker(kind[0])
 
266
                old_path += osutils.kind_marker(kind[0])
287
267
            old_path += " => "
288
268
        elif versioned == 'removed':
289
269
            # not present in target
298
278
            rename = self.versioned_map[versioned]
299
279
        # we show the old kind on the new path when the content is deleted.
300
280
        if modified == 'deleted':
301
 
            path += self.kind_marker(kind[0])
 
281
            path += osutils.kind_marker(kind[0])
302
282
        # otherwise we always show the current kind when there is one
303
283
        elif kind[1] is not None:
304
 
            path += self.kind_marker(kind[1])
 
284
            path += osutils.kind_marker(kind[1])
305
285
        if exe_change:
306
286
            exe = '*'
307
287
        else:
309
289
        self.output("%s%s%s %s%s", rename, self.modified_map[modified], exe,
310
290
                    old_path, path)
311
291
 
312
 
 
313
292
def report_changes(change_iterator, reporter):
314
293
    """Report the changes from a change iterator.
315
294
 
321
300
    :param reporter: The _ChangeReporter that will report the changes.
322
301
    """
323
302
    versioned_change_map = {
324
 
        (True, True): 'unchanged',
325
 
        (True, False): 'removed',
326
 
        (False, True): 'added',
 
303
        (True, True)  : 'unchanged',
 
304
        (True, False) : 'removed',
 
305
        (False, True) : 'added',
327
306
        (False, False): 'unversioned',
328
307
        }
329
 
 
330
 
    def path_key(change):
331
 
        if change[1][0] is not None:
332
 
            path = change[1][0]
333
 
        else:
334
 
            path = change[1][1]
335
 
        return osutils.splitpath(path)
336
308
    for (file_id, path, content_change, versioned, parent_id, name, kind,
337
 
         executable) in sorted(change_iterator, key=path_key):
 
309
         executable) in change_iterator:
338
310
        exe_change = False
339
311
        # files are "renamed" if they are moved or if name changes, as long
340
312
        # as it had a value
341
313
        if None not in name and None not in parent_id and\
342
 
                (name[0] != name[1] or parent_id[0] != parent_id[1]):
 
314
            (name[0] != name[1] or parent_id[0] != parent_id[1]):
343
315
            renamed = True
344
316
        else:
345
317
            renamed = False
353
325
        else:
354
326
            if content_change:
355
327
                modified = "modified"
356
 
            elif kind[0] is None:
357
 
                modified = "missing"
358
328
            else:
359
329
                modified = "unchanged"
360
330
            if kind[1] == "file":
363
333
        reporter.report(file_id, path, versioned_change, renamed, modified,
364
334
                        exe_change, kind)
365
335
 
366
 
 
367
 
def report_delta(to_file, delta, short_status=False, show_ids=False,
368
 
                 show_unchanged=False, indent='', predicate=None, classify=True):
 
336
def report_delta(to_file, delta, short_status=False, show_ids=False, 
 
337
         show_unchanged=False, indent='', filter=None):
369
338
    """Output this delta in status-like form to to_file.
370
339
 
371
340
    :param to_file: A file-like object where the output is displayed.
381
350
    :param indent: Added at the beginning of all output lines (for merged
382
351
        revisions).
383
352
 
384
 
    :param predicate: A callable receiving a path and a file id and
 
353
    :param filter: A callable receiving a path and a file id and
385
354
        returning True if the path should be displayed.
386
 
 
387
 
    :param classify: Add special symbols to indicate file kind.
388
355
    """
389
356
 
390
357
    def decorate_path(path, kind, meta_modified=None):
391
 
        if not classify:
392
 
            return path
393
358
        if kind == 'directory':
394
359
            path += '/'
395
360
        elif kind == 'symlink':
432
397
 
433
398
            for item in files:
434
399
                path, file_id, kind = item[:3]
435
 
                if (predicate is not None and not predicate(path, file_id)):
 
400
                if (filter is not None and not filter(path, file_id)):
436
401
                    continue
437
402
                if not header_shown and not short_status:
438
403
                    to_file.write(indent + long_status_name + ':\n')
447
412
                if show_more is not None:
448
413
                    show_more(item)
449
414
                if show_ids:
450
 
                    to_file.write(' %s' % file_id.decode('utf-8'))
 
415
                    to_file.write(' %s' % file_id)
451
416
                to_file.write('\n')
452
417
 
453
418
    show_list(delta.removed, 'removed', 'D')
454
419
    show_list(delta.added, 'added', 'A')
455
 
    show_list(delta.missing, 'missing', '!')
456
420
    extra_modified = []
457
421
    # Reorder delta.renamed tuples so that all lists share the same
458
422
    # order for their 3 first fields and that they also begin like
459
423
    # the delta.modified tuples
460
424
    renamed = [(p, i, k, tm, mm, np)
461
 
               for p, np, i, k, tm, mm in delta.renamed]
 
425
               for  p, np, i, k, tm, mm  in delta.renamed]
462
426
    show_list(renamed, 'renamed', 'R', with_file_id_format='%s',
463
427
              show_more=show_more_renamed)
464
428
    show_list(delta.kind_changed, 'kind changed', 'K',
469
433
        show_list(delta.unchanged, 'unchanged', 'S')
470
434
 
471
435
    show_list(delta.unversioned, 'unknown', ' ')
 
436