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
17
from __future__ import absolute_import
20
22
delta as _mod_delta,
24
27
revision as _mod_revision,
26
import bzrlib.errors as errors
27
from bzrlib.trace import mutter, warning
29
from . import errors as errors
30
from .sixish import text_type
31
from .trace import mutter, warning
32
from .workingtree import ShelvingUnsupported
29
35
# TODO: when showing single-line logs, truncate to the width of the terminal
30
36
# if known, but only if really going to the terminal (not into a file)
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):
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):
37
43
"""Display summary of changes.
39
This compares two trees with regards to a list of files, and delegates
45
This compares two trees with regards to a list of files, and delegates
40
46
the display to underlying elements.
42
48
For short output, it creates an iterator on all changes, and lets a given
131
134
new_is_working_tree = True
132
135
if revision is None:
133
136
if wt.last_revision() != wt.branch.last_revision():
134
warning("working tree is out of date, run 'bzr update'")
137
warning("working tree is out of date, run 'brz update'")
136
139
old = new.basis_tree()
137
140
elif len(revision) > 0:
139
142
old = revision[0].as_tree(wt.branch)
140
except errors.NoSuchRevision, e:
143
except errors.NoSuchRevision as e:
141
144
raise errors.BzrCommandError(str(e))
142
145
if (len(revision) > 1) and (revision[1].spec is not None):
144
147
new = revision[1].as_tree(wt.branch)
145
148
new_is_working_tree = False
146
except errors.NoSuchRevision, e:
149
except errors.NoSuchRevision as e:
147
150
raise errors.BzrCommandError(str(e))
156
for hook in hooks['pre_status']:
157
hook(StatusHookParams(old, new, to_file, versioned,
158
show_ids, short, verbose, specific_files=specific_files))
153
160
specific_files, nonexistents \
154
161
= _filter_nonexistent(specific_files, old, new)
155
162
want_unversioned = not versioned
157
164
# Reporter used for short outputs
158
165
reporter = _mod_delta._ChangeReporter(output_file=to_file,
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)
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)
165
172
# show the ignored files among specific files (i.e. show the files
166
# identified from input that we choose to ignore).
173
# identified from input that we choose to ignore).
167
174
if specific_files is not None:
168
175
# Ignored files is sorted because specific_files is already sorted
169
176
ignored_files = [specific for specific in
301
311
merge_extra.discard(_mod_revision.NULL_REVISION)
303
313
# Get a handle to all of the revisions we will need
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
310
for revision_id in merge_extra:
312
rev = branch.repository.get_revisions([revision_id])[0]
313
except errors.NoSuchRevision:
314
revisions[revision_id] = None
316
revisions[revision_id] = rev
314
revisions = dict(branch.repository.iter_revisions(merge_extra))
318
316
# Display the revisions brought in by this merge.
319
317
rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
320
318
branch.repository.get_parent_map(merge_extra))
321
319
# Skip the first node
322
num, first, depth, eom = rev_id_iterator.next()
320
num, first, depth, eom = next(rev_id_iterator)
323
321
if first != merge:
324
322
raise AssertionError('Somehow we misunderstood how'
325
323
' iter_topo_order works %s != %s' % (first, merge))
356
354
# their groups individually. But for consistency of this
357
355
# function's API, it's better to sort both than just 'nonexistent'.
358
356
return sorted(remaining), sorted(nonexistent)
359
class StatusHooks(_mod_hooks.Hooks):
360
"""A dictionary mapping hook name to a list of callables for status hooks.
362
e.g. ['post_status'] Is the list of items to be called when the
363
status command has finished printing the status.
367
"""Create the default hooks.
369
These are all empty initially, because by default nothing should get
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.",
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.",
391
class StatusHookParams(object):
392
"""Object holding parameters passed to post_status hooks.
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.
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.
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.
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
424
self.verbose = verbose
425
self.specific_files = specific_files
427
def __eq__(self, other):
428
return self.__dict__ == other.__dict__
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)
436
def _show_shelve_summary(params):
437
"""post_status hook to display a summary of shelves.
439
:param params: StatusHookParams.
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:
445
get_shelf_manager = getattr(params.new_tree, 'get_shelf_manager', None)
446
if get_shelf_manager is None:
449
manager = get_shelf_manager()
450
except ShelvingUnsupported:
451
mutter('shelving not supported by tree, not displaying shelves.')
453
shelves = manager.active_shelves()
455
singular = '%d shelf exists. '
456
plural = '%d shelves exist. '
457
if len(shelves) == 1:
461
params.to_file.write(fmt % len(shelves))
462
params.to_file.write('See "brz shelve --list" for details.\n')
465
hooks = StatusHooks()
468
hooks.install_named_hook('post_status', _show_shelve_summary,