13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
__all__ = ['show_bzrdir_info']
19
from cStringIO import StringIO
23
23
from bzrlib import (
30
30
from bzrlib.errors import (NoWorkingTree, NotBranchError,
31
31
NoRepositoryPresent, NotLocalUrl)
32
32
from bzrlib.missing import find_unmerged
33
from bzrlib.symbol_versioning import (deprecated_function,
34
zero_eight, zero_eighteen)
35
37
def plural(n, base='', pl=None):
44
46
class LocationList(object):
46
48
def __init__(self, base_path):
48
50
self.base_path = base_path
50
52
def add_url(self, label, url):
51
"""Add a URL to the list, converting it to a path if possible"""
55
path = urlutils.local_path_from_url(url)
56
except errors.InvalidURL:
57
self.locs.append((label, url))
55
path = urlutils.unescape_for_display(url, 'ascii')
59
57
self.add_path(label, path)
59
self.urls.append((label, url))
61
61
def add_path(self, label, path):
62
"""Add a path, converting it to a relative path if possible"""
64
63
path = osutils.relpath(self.base_path, path)
65
64
except errors.PathNotChild:
71
70
path = path.rstrip('/')
72
self.locs.append((label, path))
71
self.urls.append((label, path))
75
max_len = max(len(l) for l, u in self.locs)
76
return [" %*s: %s\n" % (max_len, l, u) for l, u in self.locs ]
73
def print_lines(self):
74
max_len = max(len(l) for l, u in self.urls)
75
for label, url in self.urls:
76
print " %*s: %s" % (max_len, label, url)
79
79
def gather_location_info(repository, branch=None, working=None):
81
repository_path = repository.user_url
81
repository_path = repository.bzrdir.root_transport.base
82
82
if branch is not None:
83
branch_path = branch.user_url
83
branch_path = branch.bzrdir.root_transport.base
84
84
master_path = branch.get_bound_location()
85
85
if master_path is None:
86
86
master_path = branch_path
126
126
return [(n, locs[n]) for n in order if n in locs]
129
def _show_location_info(locs, outfile):
129
def _show_location_info(locs):
130
130
"""Show known locations for working, branch and repository."""
131
outfile.write('Location:\n')
132
path_list = LocationList(osutils.getcwd())
132
path_list = LocationList(os.getcwd())
133
133
for name, loc in locs:
134
134
path_list.add_url(name, loc)
135
outfile.writelines(path_list.get_lines())
135
path_list.print_lines()
138
137
def _gather_related_branches(branch):
139
locs = LocationList(osutils.getcwd())
138
locs = LocationList(os.getcwd())
140
139
locs.add_url('public branch', branch.get_public_branch())
141
140
locs.add_url('push branch', branch.get_push_location())
142
141
locs.add_url('parent branch', branch.get_parent())
143
142
locs.add_url('submit branch', branch.get_submit_branch())
145
locs.add_url('stacked on', branch.get_stacked_on_url())
146
except (errors.UnstackableBranchFormat, errors.UnstackableRepositoryFormat,
152
def _show_related_info(branch, outfile):
145
def _show_related_info(branch):
153
146
"""Show parent and push location of branch."""
154
147
locs = _gather_related_branches(branch)
155
if len(locs.locs) > 0:
157
outfile.write('Related branches:\n')
158
outfile.writelines(locs.get_lines())
161
def _show_format_info(control=None, repository=None, branch=None,
162
working=None, outfile=None):
148
if len(locs.urls) > 0:
150
print 'Related branches:'
154
def _show_format_info(control=None, repository=None, branch=None, working=None):
163
155
"""Show known formats for control, working, branch and repository."""
165
outfile.write('Format:\n')
167
outfile.write(' control: %s\n' %
168
control._format.get_format_description())
159
print ' control: %s' % control._format.get_format_description()
170
outfile.write(' working tree: %s\n' %
171
working._format.get_format_description())
161
print ' working tree: %s' % working._format.get_format_description()
173
outfile.write(' branch: %s\n' %
174
branch._format.get_format_description())
163
print ' branch: %s' % branch._format.get_format_description()
176
outfile.write(' repository: %s\n' %
177
repository._format.get_format_description())
180
def _show_locking_info(repository, branch=None, working=None, outfile=None):
165
print ' repository: %s' % repository._format.get_format_description()
168
def _show_locking_info(repository, branch=None, working=None):
181
169
"""Show locking status of working, branch and repository."""
182
170
if (repository.get_physical_lock_status() or
183
171
(branch and branch.get_physical_lock_status()) or
184
172
(working and working.get_physical_lock_status())):
186
outfile.write('Lock status:\n')
188
176
if working.get_physical_lock_status():
189
177
status = 'locked'
191
179
status = 'unlocked'
192
outfile.write(' working tree: %s\n' % status)
180
print ' working tree: %s' % status
194
182
if branch.get_physical_lock_status():
195
183
status = 'locked'
197
185
status = 'unlocked'
198
outfile.write(' branch: %s\n' % status)
186
print ' branch: %s' % status
200
188
if repository.get_physical_lock_status():
201
189
status = 'locked'
203
191
status = 'unlocked'
204
outfile.write(' repository: %s\n' % status)
207
def _show_missing_revisions_branch(branch, outfile):
192
print ' repository: %s' % status
195
def _show_missing_revisions_branch(branch):
208
196
"""Show missing master revisions in branch."""
209
197
# Try with inaccessible branch ?
210
198
master = branch.get_master_branch()
212
200
local_extra, remote_extra = find_unmerged(branch, master)
215
outfile.write(('Branch is out of date: missing %d '
216
'revision%s.\n') % (len(remote_extra),
217
plural(len(remote_extra))))
220
def _show_missing_revisions_working(working, outfile):
203
print 'Branch is out of date: missing %d revision%s.' % (
204
len(remote_extra), plural(len(remote_extra)))
207
def _show_missing_revisions_working(working):
221
208
"""Show missing revisions in working tree."""
222
209
branch = working.branch
223
210
basis = working.basis_tree()
231
218
if branch_revno and tree_last_id != branch_last_revision:
232
219
tree_last_revno = branch.revision_id_to_revno(tree_last_id)
233
220
missing_count = branch_revno - tree_last_revno
235
outfile.write(('Working tree is out of date: missing %d '
236
'revision%s.\n') % (missing_count, plural(missing_count)))
239
def _show_working_stats(working, outfile):
222
print 'Working tree is out of date: missing %d revision%s.' % (
223
missing_count, plural(missing_count))
226
def _show_working_stats(working):
240
227
"""Show statistics about a working tree."""
241
228
basis = working.basis_tree()
242
229
work_inv = working.inventory
243
230
delta = working.changes_from(basis, want_unchanged=True)
246
outfile.write('In the working tree:\n')
247
outfile.write(' %8s unchanged\n' % len(delta.unchanged))
248
outfile.write(' %8d modified\n' % len(delta.modified))
249
outfile.write(' %8d added\n' % len(delta.added))
250
outfile.write(' %8d removed\n' % len(delta.removed))
251
outfile.write(' %8d renamed\n' % len(delta.renamed))
233
print 'In the working tree:'
234
print ' %8s unchanged' % len(delta.unchanged)
235
print ' %8d modified' % len(delta.modified)
236
print ' %8d added' % len(delta.added)
237
print ' %8d removed' % len(delta.removed)
238
print ' %8d renamed' % len(delta.renamed)
253
240
ignore_cnt = unknown_cnt = 0
254
241
for path in working.extras():
259
outfile.write(' %8d unknown\n' % unknown_cnt)
260
outfile.write(' %8d ignored\n' % ignore_cnt)
246
print ' %8d unknown' % unknown_cnt
247
print ' %8d ignored' % ignore_cnt
263
250
for file_id in work_inv:
264
if (work_inv.get_file_kind(file_id) == 'directory' and
251
if (work_inv.get_file_kind(file_id) == 'directory' and
265
252
not work_inv.is_root(file_id)):
267
outfile.write(' %8d versioned %s\n' % (dir_cnt,
268
plural(dir_cnt, 'subdirectory', 'subdirectories')))
271
def _show_branch_stats(branch, verbose, outfile):
254
print ' %8d versioned %s' \
256
plural(dir_cnt, 'subdirectory', 'subdirectories'))
259
def _show_branch_stats(branch, verbose):
272
260
"""Show statistics about a branch."""
273
261
revno, head = branch.last_revision_info()
275
outfile.write('Branch history:\n')
276
outfile.write(' %8d revision%s\n' % (revno, plural(revno)))
263
print 'Branch history:'
264
print ' %8d revision%s' % (revno, plural(revno))
277
265
stats = branch.repository.gather_stats(head, committers=verbose)
279
267
committers = stats['committers']
280
outfile.write(' %8d committer%s\n' % (committers,
268
print ' %8d committer%s' % (committers, plural(committers))
283
270
timestamp, timezone = stats['firstrev']
284
271
age = int((time.time() - timestamp) / 3600 / 24)
285
outfile.write(' %8d day%s old\n' % (age, plural(age)))
286
outfile.write(' first revision: %s\n' %
287
osutils.format_date(timestamp, timezone))
272
print ' %8d day%s old' % (age, plural(age))
273
print ' first revision: %s' % osutils.format_date(timestamp,
288
275
timestamp, timezone = stats['latestrev']
289
outfile.write(' latest revision: %s\n' %
290
osutils.format_date(timestamp, timezone))
276
print ' latest revision: %s' % osutils.format_date(timestamp,
294
def _show_repository_info(repository, outfile):
281
def _show_repository_info(repository):
295
282
"""Show settings of a repository."""
296
283
if repository.make_working_trees():
298
outfile.write('Create working tree for new branches inside '
302
def _show_repository_stats(repository, stats, outfile):
285
print 'Create working tree for new branches inside the repository.'
288
def _show_repository_stats(stats):
303
289
"""Show statistics about a repository."""
290
if 'revisions' in stats or 'size' in stats:
305
293
if 'revisions' in stats:
306
294
revisions = stats['revisions']
307
f.write(' %8d revision%s\n' % (revisions, plural(revisions)))
295
print ' %8d revision%s' % (revisions, plural(revisions))
308
296
if 'size' in stats:
309
f.write(' %8d KiB\n' % (stats['size']/1024))
310
for hook in hooks['repository']:
311
hook(repository, stats, f)
312
if f.getvalue() != "":
314
outfile.write('Repository:\n')
315
outfile.write(f.getvalue())
318
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
297
print ' %8d KiB' % (stats['size']/1024)
299
def show_bzrdir_info(a_bzrdir, verbose=False):
319
300
"""Output to stdout the 'info' for a_bzrdir."""
323
302
tree = a_bzrdir.open_workingtree(
324
303
recommend_upgrade=False)
347
326
lockable.lock_read()
349
show_component_info(a_bzrdir, repository, branch, tree, verbose,
328
show_component_info(a_bzrdir, repository, branch, tree, verbose)
352
330
lockable.unlock()
355
333
def show_component_info(control, repository, branch=None, working=None,
356
verbose=1, outfile=None):
357
335
"""Write info about all bzrdir components to stdout"""
360
336
if verbose is False:
362
338
if verbose is True:
364
340
layout = describe_layout(repository, branch, working)
365
341
format = describe_format(control, repository, branch, working)
366
outfile.write("%s (format: %s)\n" % (layout, format))
367
_show_location_info(gather_location_info(repository, branch, working),
342
print "%s (format: %s)" % (layout, format)
343
_show_location_info(gather_location_info(repository, branch, working))
369
344
if branch is not None:
370
_show_related_info(branch, outfile)
345
_show_related_info(branch)
373
_show_format_info(control, repository, branch, working, outfile)
374
_show_locking_info(repository, branch, working, outfile)
348
_show_format_info(control, repository, branch, working)
349
_show_locking_info(repository, branch, working)
375
350
if branch is not None:
376
_show_missing_revisions_branch(branch, outfile)
351
_show_missing_revisions_branch(branch)
377
352
if working is not None:
378
_show_missing_revisions_working(working, outfile)
379
_show_working_stats(working, outfile)
353
_show_missing_revisions_working(working)
354
_show_working_stats(working)
380
355
elif branch is not None:
381
_show_missing_revisions_branch(branch, outfile)
356
_show_missing_revisions_branch(branch)
382
357
if branch is not None:
383
show_committers = verbose >= 2
384
stats = _show_branch_stats(branch, show_committers, outfile)
358
stats = _show_branch_stats(branch, verbose==2)
386
360
stats = repository.gather_stats()
387
361
if branch is None and working is None:
388
_show_repository_info(repository, outfile)
389
_show_repository_stats(repository, stats, outfile)
362
_show_repository_info(repository)
363
_show_repository_stats(stats)
392
366
def describe_layout(repository=None, branch=None, tree=None):
466
439
candidates.append(key)
467
440
if len(candidates) == 0:
442
new_candidates = [c for c in candidates if c != 'default']
443
if len(new_candidates) > 0:
444
candidates = new_candidates
470
445
new_candidates = [c for c in candidates if not
471
446
bzrdir.format_registry.get_info(c).hidden]
472
447
if len(new_candidates) > 0:
473
# If there are any non-hidden formats that match, only return those to
474
# avoid listing hidden formats except when only a hidden format will
476
448
candidates = new_candidates
477
449
return ' or '.join(candidates)
480
class InfoHooks(_mod_hooks.Hooks):
481
"""Hooks for the info command."""
484
super(InfoHooks, self).__init__()
485
self.create_hook(_mod_hooks.HookPoint('repository',
486
"Invoked when displaying the statistics for a repository. "
487
"repository is called with a statistics dictionary as returned "
488
"by the repository and a file-like object to write to.", (1, 15),
451
@deprecated_function(zero_eight)
453
"""Please see show_bzrdir_info."""
454
return show_bzrdir_info(b.bzrdir)
457
@deprecated_function(zero_eighteen)
458
def show_tree_info(working, verbose):
459
"""Output to stdout the 'info' for working."""
460
branch = working.branch
461
repository = branch.repository
462
control = working.bzrdir
463
show_component_info(control, repository, branch, working, verbose)
466
@deprecated_function(zero_eighteen)
467
def show_branch_info(branch, verbose):
468
"""Output to stdout the 'info' for branch."""
469
repository = branch.repository
470
control = branch.bzrdir
471
show_component_info(control, repository, branch, verbose=verbose)
474
@deprecated_function(zero_eighteen)
475
def show_repository_info(repository, verbose):
476
"""Output to stdout the 'info' for repository."""
477
control = repository.bzrdir
478
show_component_info(control, repository, verbose=verbose)