76
77
return [" %*s: %s\n" % (max_len, l, u) for l, u in self.locs ]
79
def gather_location_info(repository, branch=None, working=None):
80
def gather_location_info(repository=None, branch=None, working=None,
81
repository_path = repository.user_url
82
83
if branch is not None:
83
84
branch_path = branch.user_url
84
85
master_path = branch.get_bound_location()
105
111
locs['branch root'] = branch_path
107
113
working_path = None
108
if repository.is_shared():
114
if repository is not None and repository.is_shared():
109
115
# lightweight checkout of branch in shared repository
110
116
if branch_path is not None:
111
117
locs['repository branch'] = branch_path
112
118
elif branch_path is not None:
114
120
locs['branch root'] = branch_path
115
if master_path != branch_path:
116
locs['bound to branch'] = master_path
121
elif repository is not None:
122
locs['repository'] = repository.user_url
123
elif control is not None:
124
locs['control directory'] = control.user_url
118
locs['repository'] = repository_path
119
if repository.is_shared():
126
# Really, at least a control directory should be
127
# passed in for this method to be useful.
129
if master_path != branch_path:
130
locs['bound to branch'] = master_path
131
if repository is not None and repository.is_shared():
120
132
# lightweight checkout of branch in shared repository
121
locs['shared repository'] = repository_path
122
order = ['light checkout root', 'repository checkout root',
123
'checkout root', 'checkout of branch', 'shared repository',
133
locs['shared repository'] = repository.user_url
134
order = ['control directory', 'light checkout root',
135
'repository checkout root', 'checkout root',
136
'checkout of branch', 'shared repository',
124
137
'repository', 'repository branch', 'branch root',
125
138
'bound to branch']
126
139
return [(n, locs[n]) for n in order if n in locs]
158
171
outfile.writelines(locs.get_lines())
174
def _show_control_dir_info(control, outfile):
175
"""Show control dir information."""
176
if control._format.colocated_branches:
178
outfile.write('Control directory:\n')
179
outfile.write(' %d branches\n' % len(control.list_branches()))
161
182
def _show_format_info(control=None, repository=None, branch=None,
162
183
working=None, outfile=None):
163
184
"""Show known formats for control, working, branch and repository."""
221
242
"""Show missing revisions in working tree."""
222
243
branch = working.branch
223
244
basis = working.basis_tree()
224
work_inv = working.inventory
225
branch_revno, branch_last_revision = branch.last_revision_info()
246
branch_revno, branch_last_revision = branch.last_revision_info()
247
except errors.UnsupportedOperation:
227
250
tree_last_id = working.get_parent_ids()[0]
228
251
except IndexError:
239
262
def _show_working_stats(working, outfile):
240
263
"""Show statistics about a working tree."""
241
264
basis = working.basis_tree()
242
work_inv = working.inventory
243
265
delta = working.changes_from(basis, want_unchanged=True)
245
267
outfile.write('\n')
260
282
outfile.write(' %8d ignored\n' % ignore_cnt)
263
for file_id in work_inv:
264
if (work_inv.get_file_kind(file_id) == 'directory' and
265
not work_inv.is_root(file_id)):
285
root_id = working.get_root_id()
286
for path, entry in working.iter_entries_by_dir():
287
if entry.kind == 'directory' and entry.file_id != root_id:
267
289
outfile.write(' %8d versioned %s\n' % (dir_cnt,
268
290
plural(dir_cnt, 'subdirectory', 'subdirectories')))
271
293
def _show_branch_stats(branch, verbose, outfile):
272
294
"""Show statistics about a branch."""
273
revno, head = branch.last_revision_info()
296
revno, head = branch.last_revision_info()
297
except errors.UnsupportedOperation:
274
299
outfile.write('\n')
275
300
outfile.write('Branch history:\n')
276
301
outfile.write(' %8d revision%s\n' % (revno, plural(revno)))
323
348
tree = a_bzrdir.open_workingtree(
324
349
recommend_upgrade=False)
325
except (NoWorkingTree, NotLocalUrl):
350
except (NoWorkingTree, NotLocalUrl, NotBranchError):
328
353
branch = a_bzrdir.open_branch()
344
368
repository = branch.repository
371
if lockable is not None:
349
374
show_component_info(a_bzrdir, repository, branch, tree, verbose,
377
if lockable is not None:
355
381
def show_component_info(control, repository, branch=None, working=None,
362
388
if verbose is True:
364
layout = describe_layout(repository, branch, working)
390
layout = describe_layout(repository, branch, working, control)
365
391
format = describe_format(control, repository, branch, working)
366
392
outfile.write("%s (format: %s)\n" % (layout, format))
367
_show_location_info(gather_location_info(repository, branch, working),
394
gather_location_info(control=control, repository=repository,
395
branch=branch, working=working),
369
397
if branch is not None:
370
398
_show_related_info(branch, outfile)
373
401
_show_format_info(control, repository, branch, working, outfile)
374
402
_show_locking_info(repository, branch, working, outfile)
403
_show_control_dir_info(control, outfile)
375
404
if branch is not None:
376
405
_show_missing_revisions_branch(branch, outfile)
377
406
if working is not None:
389
418
_show_repository_stats(repository, stats, outfile)
392
def describe_layout(repository=None, branch=None, tree=None):
421
def describe_layout(repository=None, branch=None, tree=None, control=None):
393
422
"""Convert a control directory layout into a user-understandable term
395
424
Common outputs include "Standalone tree", "Repository branch" and
396
425
"Checkout". Uncommon outputs include "Unshared repository with trees"
397
426
and "Empty control directory"
428
if branch is None and control is not None:
430
branch_reference = control.get_branch_reference()
431
except NotBranchError:
434
if branch_reference is not None:
435
return "Dangling branch reference"
399
436
if repository is None:
400
437
return 'Empty control directory'
401
438
if branch is None and tree is None:
447
484
branch.user_url != tree.user_url):
449
486
repository = None
450
non_aliases = set(bzrdir.format_registry.keys())
451
non_aliases.difference_update(bzrdir.format_registry.aliases())
487
non_aliases = set(controldir.format_registry.keys())
488
non_aliases.difference_update(controldir.format_registry.aliases())
452
489
for key in non_aliases:
453
format = bzrdir.format_registry.make_bzrdir(key)
490
format = controldir.format_registry.make_bzrdir(key)
454
491
if isinstance(format, bzrdir.BzrDirMetaFormat1):
455
492
if (tree and format.workingtree_format !=
469
506
candidates.sort()
470
507
new_candidates = [c for c in candidates if not
471
bzrdir.format_registry.get_info(c).hidden]
508
controldir.format_registry.get_info(c).hidden]
472
509
if len(new_candidates) > 0:
473
510
# If there are any non-hidden formats that match, only return those to
474
511
# avoid listing hidden formats except when only a hidden format will
481
518
"""Hooks for the info command."""
483
520
def __init__(self):
484
super(InfoHooks, self).__init__()
485
self.create_hook(_mod_hooks.HookPoint('repository',
521
super(InfoHooks, self).__init__("bzrlib.info", "hooks")
522
self.add_hook('repository',
486
523
"Invoked when displaying the statistics for a repository. "
487
524
"repository is called with a statistics dictionary as returned "
488
"by the repository and a file-like object to write to.", (1, 15),
525
"by the repository and a file-like object to write to.", (1, 15))
492
528
hooks = InfoHooks()