1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
__all__ = ['show_bzrdir_info']
28
from bzrlib.errors import (NoWorkingTree, NotBranchError,
29
NoRepositoryPresent, NotLocalUrl)
30
from bzrlib.missing import find_unmerged
31
from bzrlib.symbol_versioning import (deprecated_function,
32
zero_eight, zero_sixteen)
35
def plural(n, base='', pl=None):
44
def _repo_rel_url(repo_url, inner_url):
45
"""Return path with common prefix of repository path removed.
47
If path is not part of the repository, the original path is returned.
48
If path is equal to the repository, the current directory marker '.' is
50
Otherwise, a relative path is returned, with trailing '/' stripped.
52
inner_url = urlutils.normalize_url(inner_url)
53
repo_url = urlutils.normalize_url(repo_url)
54
if inner_url == repo_url:
56
result = urlutils.relative_url(repo_url, inner_url)
57
if result != inner_url:
58
result = result.rstrip('/')
62
def _show_location_info(repository, branch=None, working=None):
63
"""Show known locations for working, branch and repository."""
64
repository_path = repository.bzrdir.root_transport.base
66
if working and branch:
67
working_path = working.bzrdir.root_transport.base
68
branch_path = branch.bzrdir.root_transport.base
69
if working_path != branch_path:
70
# lightweight checkout
71
print ' light checkout root: %s' % working_path
72
if repository.is_shared():
73
# lightweight checkout of branch in shared repository
74
print ' shared repository: %s' % repository_path
75
print ' repository branch: %s' % (
76
_repo_rel_url(repository_path, branch_path))
78
# lightweight checkout of standalone branch
79
print ' checkout of branch: %s' % branch_path
80
elif repository.is_shared():
81
# branch with tree inside shared repository
82
print ' shared repository: %s' % repository_path
83
print ' repository checkout: %s' % (
84
_repo_rel_url(repository_path, branch_path))
85
elif branch.get_bound_location():
87
print ' checkout root: %s' % working_path
88
print ' checkout of branch: %s' % branch.get_bound_location()
91
print ' branch root: %s' % working_path
93
branch_path = branch.bzrdir.root_transport.base
94
if repository.is_shared():
95
# branch is part of shared repository
96
print ' shared repository: %s' % repository_path
97
print ' repository branch: %s' % (
98
_repo_rel_url(repository_path, branch_path))
101
print ' branch root: %s' % branch_path
104
assert repository.is_shared()
105
print ' shared repository: %s' % repository_path
108
def _show_related_info(branch):
109
"""Show parent and push location of branch."""
110
if branch.get_parent() or branch.get_push_location():
112
print 'Related branches:'
113
if branch.get_parent():
114
if branch.get_push_location():
115
print ' parent branch: %s' % branch.get_parent()
117
print ' parent branch: %s' % branch.get_parent()
118
if branch.get_push_location():
119
print ' publish to branch: %s' % branch.get_push_location()
122
def _show_format_info(control=None, repository=None, branch=None, working=None):
123
"""Show known formats for control, working, branch and repository."""
127
print ' control: %s' % control._format.get_format_description()
129
print ' working tree: %s' % working._format.get_format_description()
131
print ' branch: %s' % branch._format.get_format_description()
133
print ' repository: %s' % repository._format.get_format_description()
136
def _show_locking_info(repository, branch=None, working=None):
137
"""Show locking status of working, branch and repository."""
138
if (repository.get_physical_lock_status() or
139
(branch and branch.get_physical_lock_status()) or
140
(working and working.get_physical_lock_status())):
144
if working.get_physical_lock_status():
148
print ' working tree: %s' % status
150
if branch.get_physical_lock_status():
154
print ' branch: %s' % status
156
if repository.get_physical_lock_status():
160
print ' repository: %s' % status
163
def _show_missing_revisions_branch(branch):
164
"""Show missing master revisions in branch."""
165
# Try with inaccessible branch ?
166
master = branch.get_master_branch()
168
local_extra, remote_extra = find_unmerged(branch, master)
171
print 'Branch is out of date: missing %d revision%s.' % (
172
len(remote_extra), plural(len(remote_extra)))
175
def _show_missing_revisions_working(working):
176
"""Show missing revisions in working tree."""
177
branch = working.branch
178
basis = working.basis_tree()
179
work_inv = working.inventory
180
branch_revno, branch_last_revision = branch.last_revision_info()
182
tree_last_id = working.get_parent_ids()[0]
186
if branch_revno and tree_last_id != branch_last_revision:
187
tree_last_revno = branch.revision_id_to_revno(tree_last_id)
188
missing_count = branch_revno - tree_last_revno
190
print 'Working tree is out of date: missing %d revision%s.' % (
191
missing_count, plural(missing_count))
194
def _show_working_stats(working):
195
"""Show statistics about a working tree."""
196
basis = working.basis_tree()
197
work_inv = working.inventory
198
delta = working.changes_from(basis, want_unchanged=True)
201
print 'In the working tree:'
202
print ' %8s unchanged' % len(delta.unchanged)
203
print ' %8d modified' % len(delta.modified)
204
print ' %8d added' % len(delta.added)
205
print ' %8d removed' % len(delta.removed)
206
print ' %8d renamed' % len(delta.renamed)
208
ignore_cnt = unknown_cnt = 0
209
for path in working.extras():
210
if working.is_ignored(path):
214
print ' %8d unknown' % unknown_cnt
215
print ' %8d ignored' % ignore_cnt
218
for file_id in work_inv:
219
if (work_inv.get_file_kind(file_id) == 'directory' and
220
not work_inv.is_root(file_id)):
222
print ' %8d versioned %s' \
224
plural(dir_cnt, 'subdirectory', 'subdirectories'))
227
def _show_branch_stats(branch, verbose):
228
"""Show statistics about a branch."""
229
revno, head = branch.last_revision_info()
231
print 'Branch history:'
232
print ' %8d revision%s' % (revno, plural(revno))
233
stats = branch.repository.gather_stats(head, committers=verbose)
235
committers = stats['committers']
236
print ' %8d committer%s' % (committers, plural(committers))
238
timestamp, timezone = stats['firstrev']
239
age = int((time.time() - timestamp) / 3600 / 24)
240
print ' %8d day%s old' % (age, plural(age))
241
print ' first revision: %s' % osutils.format_date(timestamp,
243
timestamp, timezone = stats['latestrev']
244
print ' latest revision: %s' % osutils.format_date(timestamp,
249
def _show_repository_info(repository):
250
"""Show settings of a repository."""
251
if repository.make_working_trees():
253
print 'Create working tree for new branches inside the repository.'
256
def _show_repository_stats(stats):
257
"""Show statistics about a repository."""
258
if 'revisions' in stats or 'size' in stats:
261
if 'revisions' in stats:
262
revisions = stats['revisions']
263
print ' %8d revision%s' % (revisions, plural(revisions))
265
print ' %8d KiB' % (stats['size']/1024)
268
def show_bzrdir_info(a_bzrdir, verbose=False):
269
"""Output to stdout the 'info' for a_bzrdir."""
271
tree = a_bzrdir.open_workingtree(
272
recommend_upgrade=False)
273
except (NoWorkingTree, NotLocalUrl):
276
branch = a_bzrdir.open_branch()
277
except NotBranchError:
280
repository = a_bzrdir.open_repository()
281
except NoRepositoryPresent:
282
# Return silently; cmd_info already returned NotBranchError
283
# if no bzrdir could be opened.
286
lockable = repository
288
repository = branch.repository
292
repository = branch.repository
297
show_component_info(a_bzrdir, repository, branch, tree, verbose)
302
def show_component_info(control, repository, branch=None, working=None,
304
"""Write info about all bzrdir components to stdout"""
309
layout = describe_layout(repository, branch, working)
310
format = describe_format(control, repository, branch, working)
311
print "%s (format: %s)" % (layout, format)
312
_show_location_info(repository, branch, working)
315
if branch is not None:
316
_show_related_info(branch)
317
_show_format_info(control, repository, branch, working)
318
_show_locking_info(repository, branch, working)
319
if branch is not None:
320
_show_missing_revisions_branch(branch)
321
if working is not None:
322
_show_missing_revisions_working(working)
323
_show_working_stats(working)
324
elif branch is not None:
325
_show_missing_revisions_branch(branch)
326
if branch is not None:
327
stats = _show_branch_stats(branch, verbose==2)
329
stats = repository.gather_stats()
330
if branch is None and working is None:
331
_show_repository_info(repository)
332
_show_repository_stats(stats)
335
def describe_layout(repository=None, branch=None, tree=None):
336
"""Convert a control directory layout into a user-understandable term
338
Common outputs include "Standalone tree", "Repository branch" and
339
"Checkout". Uncommon outputs include "Unshared repository with trees"
340
and "Empty control directory"
342
if repository is None:
343
return 'Empty control directory'
344
if branch is None and tree is None:
345
if repository.is_shared():
346
phrase = 'Shared repository'
348
phrase = 'Unshared repository'
349
if repository.make_working_trees():
350
phrase += ' with trees'
353
if repository.is_shared():
354
independence = "Repository "
356
independence = "Standalone "
361
if branch is None and tree is not None:
362
phrase = "branchless tree"
364
if (tree is not None and tree.bzrdir.root_transport.base !=
365
branch.bzrdir.root_transport.base):
367
phrase = "Lightweight checkout"
368
elif branch.get_bound_location() is not None:
369
if independence == 'Standalone ':
372
phrase = "Bound branch"
375
if independence != "":
376
phrase = phrase.lower()
377
return "%s%s" % (independence, phrase)
380
def describe_format(control, repository, branch, tree):
381
"""Determine the format of an existing control directory
383
Several candidates may be found. If so, the names are returned as a
384
single string, separated by slashes.
386
If no matching candidate is found, "unnamed" is returned.
389
if (branch is not None and tree is not None and
390
branch.bzrdir.root_transport.base !=
391
tree.bzrdir.root_transport.base):
394
for key in bzrdir.format_registry.keys():
395
format = bzrdir.format_registry.make_bzrdir(key)
396
if isinstance(format, bzrdir.BzrDirMetaFormat1):
397
if (tree and format.workingtree_format !=
400
if (branch and format.get_branch_format() !=
403
if (repository and format.repository_format !=
406
if format.__class__ is not control._format.__class__:
408
candidates.append(key)
409
if len(candidates) == 0:
411
new_candidates = [c for c in candidates if c != 'default']
412
if len(new_candidates) > 0:
413
candidates = new_candidates
414
new_candidates = [c for c in candidates if not
415
bzrdir.format_registry.get_info(c).hidden]
416
if len(new_candidates) > 0:
417
candidates = new_candidates
418
return ' / '.join(candidates)
420
@deprecated_function(zero_eight)
422
"""Please see show_bzrdir_info."""
423
return show_bzrdir_info(b.bzrdir)
426
@deprecated_function(zero_sixteen)
427
def show_tree_info(working, verbose):
428
"""Output to stdout the 'info' for working."""
429
branch = working.branch
430
repository = branch.repository
431
control = working.bzrdir
432
show_component_info(control, repository, branch, working, verbose)
435
@deprecated_function(zero_sixteen)
436
def show_branch_info(branch, verbose):
437
"""Output to stdout the 'info' for branch."""
438
repository = branch.repository
439
control = branch.bzrdir
440
show_component_info(control, repository, branch, verbose=verbose)
443
@deprecated_function(zero_sixteen)
444
def show_repository_info(repository, verbose):
445
"""Output to stdout the 'info' for repository."""
446
control = repository.bzrdir
447
show_component_info(control, repository, verbose=verbose)