/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/status.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
17
import sys
20
18
 
21
 
from . import (
 
19
from bzrlib import (
22
20
    delta as _mod_delta,
23
 
    hooks as _mod_hooks,
24
21
    log,
25
22
    osutils,
26
23
    tsort,
27
24
    revision as _mod_revision,
28
25
    )
29
 
from . import errors as errors
30
 
from .sixish import text_type
31
 
from .trace import mutter, warning
32
 
from .workingtree import ShelvingUnsupported
33
 
 
 
26
import bzrlib.errors as errors
 
27
from bzrlib.trace import mutter, warning
34
28
 
35
29
# TODO: when showing single-line logs, truncate to the width of the terminal
36
30
# if known, but only if really going to the terminal (not into a file)
37
31
 
38
32
 
39
 
def report_changes(to_file, old, new, specific_files,
40
 
                   show_short_reporter, show_long_callback,
41
 
                   short=False, want_unchanged=False,
42
 
                   want_unversioned=False, show_ids=False, classify=True):
 
33
def report_changes(to_file, old, new, specific_files, 
 
34
                   show_short_reporter, show_long_callback, 
 
35
                   short=False, want_unchanged=False, 
 
36
                   want_unversioned=False, show_ids=False):
43
37
    """Display summary of changes.
44
38
 
45
 
    This compares two trees with regards to a list of files, and delegates
 
39
    This compares two trees with regards to a list of files, and delegates 
46
40
    the display to underlying elements.
47
41
 
48
42
    For short output, it creates an iterator on all changes, and lets a given
64
58
        files.
65
59
    :param show_ids: If set, includes each file's id.
66
60
    :param want_unversioned: If False, only shows versioned files.
67
 
    :param classify: Add special symbols to indicate file kind.
68
61
    """
69
62
 
70
63
    if short:
71
64
        changes = new.iter_changes(old, want_unchanged, specific_files,
72
65
            require_versioned=False, want_unversioned=want_unversioned)
73
66
        _mod_delta.report_changes(changes, show_short_reporter)
 
67
        
74
68
    else:
75
69
        delta = new.changes_from(old, want_unchanged=want_unchanged,
76
70
                              specific_files=specific_files,
79
73
        # this
80
74
        delta.unversioned = [unversioned for unversioned in
81
75
            delta.unversioned if not new.is_ignored(unversioned[0])]
82
 
        show_long_callback(to_file, delta,
 
76
        show_long_callback(to_file, delta, 
83
77
                           show_ids=show_ids,
84
 
                           show_unchanged=want_unchanged,
85
 
                           classify=classify)
86
 
 
87
 
 
88
 
def show_tree_status(wt,
 
78
                           show_unchanged=want_unchanged)
 
79
 
 
80
 
 
81
def show_tree_status(wt, show_unchanged=None,
89
82
                     specific_files=None,
90
83
                     show_ids=False,
91
84
                     to_file=None,
94
87
                     short=False,
95
88
                     verbose=False,
96
89
                     versioned=False,
97
 
                     classify=True,
98
90
                     show_long_callback=_mod_delta.report_delta):
99
91
    """Display summary of changes.
100
92
 
108
100
    If showing the status of a working tree, extra information is included
109
101
    about unknown files, conflicts, and pending merges.
110
102
 
 
103
    :param show_unchanged: Deprecated parameter. If set, includes unchanged
 
104
        files.
111
105
    :param specific_files: If set, a list of filenames whose status should be
112
106
        shown.  It is an error to give a filename that is not in the working
113
107
        tree, or in the working inventory or in the basis inventory.
122
116
    :param verbose: If True, show all merged revisions, not just
123
117
        the merge tips
124
118
    :param versioned: If True, only shows versioned files.
125
 
    :param classify: Add special symbols to indicate file kind.
126
 
    :param show_long_callback: A callback: message = show_long_callback(to_file, delta,
 
119
    :param show_long_callback: A callback: message = show_long_callback(to_file, delta, 
127
120
        show_ids, show_unchanged, indent, filter), only used with the long output
128
121
    """
 
122
    if show_unchanged is not None:
 
123
        warn("show_tree_status with show_unchanged has been deprecated "
 
124
             "since bzrlib 0.9", DeprecationWarning, stacklevel=2)
 
125
 
129
126
    if to_file is None:
130
127
        to_file = sys.stdout
131
128
 
134
131
        new_is_working_tree = True
135
132
        if revision is None:
136
133
            if wt.last_revision() != wt.branch.last_revision():
137
 
                warning("working tree is out of date, run 'brz update'")
 
134
                warning("working tree is out of date, run 'bzr update'")
138
135
            new = wt
139
136
            old = new.basis_tree()
140
137
        elif len(revision) > 0:
141
138
            try:
142
139
                old = revision[0].as_tree(wt.branch)
143
 
            except errors.NoSuchRevision as e:
 
140
            except errors.NoSuchRevision, e:
144
141
                raise errors.BzrCommandError(str(e))
145
142
            if (len(revision) > 1) and (revision[1].spec is not None):
146
143
                try:
147
144
                    new = revision[1].as_tree(wt.branch)
148
145
                    new_is_working_tree = False
149
 
                except errors.NoSuchRevision as e:
 
146
                except errors.NoSuchRevision, e:
150
147
                    raise errors.BzrCommandError(str(e))
151
148
            else:
152
149
                new = wt
153
150
        old.lock_read()
154
151
        new.lock_read()
155
152
        try:
156
 
            for hook in hooks['pre_status']:
157
 
                hook(StatusHookParams(old, new, to_file, versioned,
158
 
                    show_ids, short, verbose, specific_files=specific_files))
159
 
 
160
153
            specific_files, nonexistents \
161
154
                = _filter_nonexistent(specific_files, old, new)
162
155
            want_unversioned = not versioned
163
156
 
164
157
            # Reporter used for short outputs
165
158
            reporter = _mod_delta._ChangeReporter(output_file=to_file,
166
 
                unversioned_filter=new.is_ignored, classify=classify)
167
 
            report_changes(to_file, old, new, specific_files,
168
 
                           reporter, show_long_callback,
169
 
                           short=short, want_unversioned=want_unversioned,
170
 
                           show_ids=show_ids, classify=classify)
 
159
                unversioned_filter=new.is_ignored)
 
160
            report_changes(to_file, old, new, specific_files, 
 
161
                           reporter, show_long_callback, 
 
162
                           short=short, want_unchanged=show_unchanged, 
 
163
                           want_unversioned=want_unversioned, show_ids=show_ids)
171
164
 
172
165
            # show the ignored files among specific files (i.e. show the files
173
 
            # identified from input that we choose to ignore).
 
166
            # identified from input that we choose to ignore). 
174
167
            if specific_files is not None:
175
168
                # Ignored files is sorted because specific_files is already sorted
176
169
                ignored_files = [specific for specific in
196
189
                    prefix = 'C  '
197
190
                else:
198
191
                    prefix = ' '
199
 
                to_file.write("%s %s\n" % (prefix, conflict.describe()))
 
192
                to_file.write("%s %s\n" % (prefix, conflict))
200
193
            # Show files that were requested but don't exist (and are
201
194
            # not versioned).  We don't involve delta in this; these
202
195
            # paths are really the province of just the status
217
210
                show_pending_merges(new, to_file, short, verbose=verbose)
218
211
            if nonexistents:
219
212
                raise errors.PathsDoNotExist(nonexistents)
220
 
            for hook in hooks['post_status']:
221
 
                hook(StatusHookParams(old, new, to_file, versioned,
222
 
                    show_ids, short, verbose, specific_files=specific_files))
223
213
        finally:
224
214
            old.unlock()
225
215
            new.unlock()
292
282
    log_formatter = log.LineLogFormatter(to_file)
293
283
    for merge in pending:
294
284
        try:
295
 
            rev = branch.repository.get_revision(merge)
 
285
            rev = branch.repository.get_revisions([merge])[0]
296
286
        except errors.NoSuchRevision:
297
287
            # If we are missing a revision, just print out the revision id
298
288
            to_file.write(first_prefix + '(ghost) ' + merge + '\n')
311
301
        merge_extra.discard(_mod_revision.NULL_REVISION)
312
302
 
313
303
        # Get a handle to all of the revisions we will need
314
 
        revisions = dict(branch.repository.iter_revisions(merge_extra))
 
304
        try:
 
305
            revisions = dict((rev.revision_id, rev) for rev in
 
306
                             branch.repository.get_revisions(merge_extra))
 
307
        except errors.NoSuchRevision:
 
308
            # One of the sub nodes is a ghost, check each one
 
309
            revisions = {}
 
310
            for revision_id in merge_extra:
 
311
                try:
 
312
                    rev = branch.repository.get_revisions([revision_id])[0]
 
313
                except errors.NoSuchRevision:
 
314
                    revisions[revision_id] = None
 
315
                else:
 
316
                    revisions[revision_id] = rev
315
317
 
316
318
        # Display the revisions brought in by this merge.
317
319
        rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
318
320
                            branch.repository.get_parent_map(merge_extra))
319
321
        # Skip the first node
320
 
        num, first, depth, eom = next(rev_id_iterator)
 
322
        num, first, depth, eom = rev_id_iterator.next()
321
323
        if first != merge:
322
324
            raise AssertionError('Somehow we misunderstood how'
323
325
                ' iter_topo_order works %s != %s' % (first, merge))
339
341
 
340
342
    If either of the two lists is empty, return it as an empty list.
341
343
 
342
 
    This can be used by operations such as brz status that can accept
 
344
    This can be used by operations such as bzr status that can accept
343
345
    unknown or ignored files.
344
346
    """
345
347
    mutter("check paths: %r", orig_paths)
354
356
    # their groups individually.  But for consistency of this
355
357
    # function's API, it's better to sort both than just 'nonexistent'.
356
358
    return sorted(remaining), sorted(nonexistent)
357
 
 
358
 
 
359
 
class StatusHooks(_mod_hooks.Hooks):
360
 
    """A dictionary mapping hook name to a list of callables for status hooks.
361
 
 
362
 
    e.g. ['post_status'] Is the list of items to be called when the
363
 
    status command has finished printing the status.
364
 
    """
365
 
 
366
 
    def __init__(self):
367
 
        """Create the default hooks.
368
 
 
369
 
        These are all empty initially, because by default nothing should get
370
 
        notified.
371
 
        """
372
 
        _mod_hooks.Hooks.__init__(self, "breezy.status", "hooks")
373
 
        self.add_hook('post_status',
374
 
            "Called with argument StatusHookParams after Bazaar has "
375
 
            "displayed the status. StatusHookParams has the attributes "
376
 
            "(old_tree, new_tree, to_file, versioned, show_ids, short, "
377
 
            "verbose). The last four arguments correspond to the command "
378
 
            "line options specified by the user for the status command. "
379
 
            "to_file is the output stream for writing.",
380
 
            (2, 3))
381
 
        self.add_hook('pre_status',
382
 
            "Called with argument StatusHookParams before Bazaar "
383
 
            "displays the status. StatusHookParams has the attributes "
384
 
            "(old_tree, new_tree, to_file, versioned, show_ids, short, "
385
 
            "verbose). The last four arguments correspond to the command "
386
 
            "line options specified by the user for the status command. "
387
 
            "to_file is the output stream for writing.",
388
 
            (2, 3))
389
 
 
390
 
 
391
 
class StatusHookParams(object):
392
 
    """Object holding parameters passed to post_status hooks.
393
 
 
394
 
    :ivar old_tree: Start tree (basis tree) for comparison.
395
 
    :ivar new_tree: Working tree.
396
 
    :ivar to_file: If set, write to this file.
397
 
    :ivar versioned: Show only versioned files.
398
 
    :ivar show_ids: Show internal object ids.
399
 
    :ivar short: Use short status indicators.
400
 
    :ivar verbose: Verbose flag.
401
 
    """
402
 
 
403
 
    def __init__(self, old_tree, new_tree, to_file, versioned, show_ids,
404
 
            short, verbose, specific_files=None):
405
 
        """Create a group of post_status hook parameters.
406
 
 
407
 
        :param old_tree: Start tree (basis tree) for comparison.
408
 
        :param new_tree: Working tree.
409
 
        :param to_file: If set, write to this file.
410
 
        :param versioned: Show only versioned files.
411
 
        :param show_ids: Show internal object ids.
412
 
        :param short: Use short status indicators.
413
 
        :param verbose: Verbose flag.
414
 
        :param specific_files: If set, a list of filenames whose status should be
415
 
            shown.  It is an error to give a filename that is not in the working
416
 
            tree, or in the working inventory or in the basis inventory.
417
 
        """
418
 
        self.old_tree = old_tree
419
 
        self.new_tree = new_tree
420
 
        self.to_file = to_file
421
 
        self.versioned = versioned
422
 
        self.show_ids = show_ids
423
 
        self.short = short
424
 
        self.verbose = verbose
425
 
        self.specific_files = specific_files
426
 
 
427
 
    def __eq__(self, other):
428
 
        return self.__dict__ == other.__dict__
429
 
 
430
 
    def __repr__(self):
431
 
        return "<%s(%s, %s, %s, %s, %s, %s, %s, %s)>" % (self.__class__.__name__,
432
 
            self.old_tree, self.new_tree, self.to_file, self.versioned,
433
 
            self.show_ids, self.short, self.verbose, self.specific_files)
434
 
 
435
 
 
436
 
def _show_shelve_summary(params):
437
 
    """post_status hook to display a summary of shelves.
438
 
 
439
 
    :param params: StatusHookParams.
440
 
    """
441
 
    # Don't show shelves if status of specific files is being shown, only if
442
 
    # no file arguments have been passed
443
 
    if params.specific_files:
444
 
        return
445
 
    get_shelf_manager = getattr(params.new_tree, 'get_shelf_manager', None)
446
 
    if get_shelf_manager is None:
447
 
        return
448
 
    try:
449
 
        manager = get_shelf_manager()
450
 
    except ShelvingUnsupported:
451
 
        mutter('shelving not supported by tree, not displaying shelves.')
452
 
    else:
453
 
        shelves = manager.active_shelves()
454
 
        if shelves:
455
 
            singular = '%d shelf exists. '
456
 
            plural = '%d shelves exist. '
457
 
            if len(shelves) == 1:
458
 
                fmt = singular
459
 
            else:
460
 
                fmt = plural
461
 
            params.to_file.write(fmt % len(shelves))
462
 
            params.to_file.write('See "brz shelve --list" for details.\n')
463
 
 
464
 
 
465
 
hooks = StatusHooks()
466
 
 
467
 
 
468
 
hooks.install_named_hook('post_status', _show_shelve_summary,
469
 
    'brz status')
470