~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/info.py

  • Committer: Martin Packman
  • Date: 2011-12-23 19:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6405.
  • Revision ID: martin.packman@canonical.com-20111223193822-hesheea4o8aqwexv
Accept and document passing the medium rather than transport for smart connections

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
 
 
1
# Copyright (C) 2005-2010 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
12
12
#
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
__all__ = ['show_bzrdir_info']
18
18
 
 
19
from cStringIO import StringIO
19
20
import time
20
 
 
 
21
import sys
21
22
 
22
23
from bzrlib import (
23
24
    bzrdir,
24
 
    diff,
 
25
    controldir,
 
26
    errors,
 
27
    hooks as _mod_hooks,
25
28
    osutils,
26
29
    urlutils,
27
30
    )
28
31
from bzrlib.errors import (NoWorkingTree, NotBranchError,
29
32
                           NoRepositoryPresent, NotLocalUrl)
30
33
from bzrlib.missing import find_unmerged
31
 
from bzrlib.symbol_versioning import (deprecated_function,
32
 
        zero_eight, zero_eighteen)
33
34
 
34
35
 
35
36
def plural(n, base='', pl=None):
41
42
        return 's'
42
43
 
43
44
 
44
 
def _repo_rel_url(repo_url, inner_url):
45
 
    """Return path with common prefix of repository path removed.
46
 
 
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
49
 
    returned.
50
 
    Otherwise, a relative path is returned, with trailing '/' stripped.
51
 
    """
52
 
    inner_url = urlutils.normalize_url(inner_url)
53
 
    repo_url = urlutils.normalize_url(repo_url)
54
 
    if inner_url == repo_url:
55
 
        return '.'
56
 
    result = urlutils.relative_url(repo_url, inner_url)
57
 
    if result != inner_url:
58
 
        result = result.rstrip('/')
59
 
    return result
60
 
 
61
 
class _UrlList(object):
62
 
 
63
 
    def __init__(self):
64
 
        self.urls = []
65
 
 
66
 
    def add_url(self, label, url):
67
 
        self.add_path(label, urlutils.unescape_for_display(url, 'ascii'))
68
 
 
69
 
    def add_url(self, label, url):
70
 
        self.add_path(label, url)
 
45
class LocationList(object):
 
46
 
 
47
    def __init__(self, base_path):
 
48
        self.locs = []
 
49
        self.base_path = base_path
 
50
 
 
51
    def add_url(self, label, url):
 
52
        """Add a URL to the list, converting it to a path if possible"""
 
53
        if url is None:
 
54
            return
 
55
        try:
 
56
            path = urlutils.local_path_from_url(url)
 
57
        except errors.InvalidURL:
 
58
            self.locs.append((label, url))
 
59
        else:
 
60
            self.add_path(label, path)
71
61
 
72
62
    def add_path(self, label, path):
73
 
        self.urls.append((label, path))
74
 
 
75
 
    def print_lines(self):
76
 
        max_len = max(len(l) for l, u in self.urls)
77
 
        for label, url in self.urls:
78
 
            print "  %*s: %s" % (max_len, label, url)
79
 
 
80
 
 
81
 
def gather_location_info(repository, branch=None, working=None):
 
63
        """Add a path, converting it to a relative path if possible"""
 
64
        try:
 
65
            path = osutils.relpath(self.base_path, path)
 
66
        except errors.PathNotChild:
 
67
            pass
 
68
        else:
 
69
            if path == '':
 
70
                path = '.'
 
71
        if path != '/':
 
72
            path = path.rstrip('/')
 
73
        self.locs.append((label, path))
 
74
 
 
75
    def get_lines(self):
 
76
        max_len = max(len(l) for l, u in self.locs)
 
77
        return ["  %*s: %s\n" % (max_len, l, u) for l, u in self.locs ]
 
78
 
 
79
 
 
80
def gather_location_info(repository=None, branch=None, working=None,
 
81
        control=None):
82
82
    locs = {}
83
 
    repository_path = repository.bzrdir.root_transport.base
84
83
    if branch is not None:
85
 
        branch_path = branch.bzrdir.root_transport.base
 
84
        branch_path = branch.user_url
86
85
        master_path = branch.get_bound_location()
87
86
        if master_path is None:
88
87
            master_path = branch_path
89
88
    else:
90
89
        branch_path = None
91
90
        master_path = None
 
91
        try:
 
92
            if control is not None and control.get_branch_reference():
 
93
                locs['checkout of branch'] = control.get_branch_reference()
 
94
        except NotBranchError:
 
95
            pass
92
96
    if working:
93
 
        working_path = working.bzrdir.root_transport.base
 
97
        working_path = working.user_url
94
98
        if working_path != branch_path:
95
99
            locs['light checkout root'] = working_path
96
100
        if master_path != branch_path:
101
105
        if working_path != master_path:
102
106
            locs['checkout of branch'] = master_path
103
107
        elif repository.is_shared():
104
 
            locs['repository branch'] = _repo_rel_url(repository_path,
105
 
                branch_path)
 
108
            locs['repository branch'] = branch_path
106
109
        elif branch_path is not None:
107
110
            # standalone
108
111
            locs['branch root'] = branch_path
109
112
    else:
110
113
        working_path = None
111
 
        if repository.is_shared():
 
114
        if repository is not None and repository.is_shared():
112
115
            # lightweight checkout of branch in shared repository
113
116
            if branch_path is not None:
114
 
                locs['repository branch'] = _repo_rel_url(repository_path,
115
 
                                                          branch_path)
 
117
                locs['repository branch'] = branch_path
116
118
        elif branch_path is not None:
117
119
            # standalone
118
120
            locs['branch root'] = branch_path
119
 
            if master_path != branch_path:
120
 
                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
121
125
        else:
122
 
            locs['repository'] = repository_path
123
 
    if repository.is_shared():
 
126
            # Really, at least a control directory should be
 
127
            # passed in for this method to be useful.
 
128
            pass
 
129
        if master_path != branch_path:
 
130
            locs['bound to branch'] = master_path
 
131
    if repository is not None and repository.is_shared():
124
132
        # lightweight checkout of branch in shared repository
125
 
        locs['shared repository'] = repository_path
126
 
    order = ['light checkout root', 'repository checkout root',
127
 
             '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',
128
137
             'repository', 'repository branch', 'branch root',
129
138
             'bound to branch']
130
139
    return [(n, locs[n]) for n in order if n in locs]
131
140
 
132
141
 
133
 
def _show_location_info(locs):
 
142
def _show_location_info(locs, outfile):
134
143
    """Show known locations for working, branch and repository."""
135
 
    print 'Location:'
136
 
    path_list = _UrlList()
 
144
    outfile.write('Location:\n')
 
145
    path_list = LocationList(osutils.getcwd())
137
146
    for name, loc in locs:
138
147
        path_list.add_url(name, loc)
139
 
    path_list.print_lines()
140
 
 
141
 
 
142
 
def _show_related_info(branch):
 
148
    outfile.writelines(path_list.get_lines())
 
149
 
 
150
 
 
151
def _gather_related_branches(branch):
 
152
    locs = LocationList(osutils.getcwd())
 
153
    locs.add_url('public branch', branch.get_public_branch())
 
154
    locs.add_url('push branch', branch.get_push_location())
 
155
    locs.add_url('parent branch', branch.get_parent())
 
156
    locs.add_url('submit branch', branch.get_submit_branch())
 
157
    try:
 
158
        locs.add_url('stacked on', branch.get_stacked_on_url())
 
159
    except (errors.UnstackableBranchFormat, errors.UnstackableRepositoryFormat,
 
160
        errors.NotStacked):
 
161
        pass
 
162
    return locs
 
163
 
 
164
 
 
165
def _show_related_info(branch, outfile):
143
166
    """Show parent and push location of branch."""
144
 
    if branch.get_parent() or branch.get_push_location():
145
 
        print
146
 
        print 'Related branches:'
147
 
        if branch.get_parent():
148
 
            if branch.get_push_location():
149
 
                print '      parent branch: %s' % branch.get_parent()
150
 
            else:
151
 
                print '  parent branch: %s' % branch.get_parent()
152
 
        if branch.get_push_location():
153
 
            print '  publish to branch: %s' % branch.get_push_location()
154
 
 
155
 
 
156
 
def _show_format_info(control=None, repository=None, branch=None, working=None):
 
167
    locs = _gather_related_branches(branch)
 
168
    if len(locs.locs) > 0:
 
169
        outfile.write('\n')
 
170
        outfile.write('Related branches:\n')
 
171
        outfile.writelines(locs.get_lines())
 
172
 
 
173
 
 
174
def _show_control_dir_info(control, outfile):
 
175
    """Show control dir information."""
 
176
    if control._format.colocated_branches:
 
177
        outfile.write('\n')
 
178
        outfile.write('Control directory:\n')
 
179
        outfile.write('         %d branches\n' % len(control.list_branches()))
 
180
 
 
181
 
 
182
def _show_format_info(control=None, repository=None, branch=None,
 
183
                      working=None, outfile=None):
157
184
    """Show known formats for control, working, branch and repository."""
158
 
    print
159
 
    print 'Format:'
 
185
    outfile.write('\n')
 
186
    outfile.write('Format:\n')
160
187
    if control:
161
 
        print '       control: %s' % control._format.get_format_description()
 
188
        outfile.write('       control: %s\n' %
 
189
            control._format.get_format_description())
162
190
    if working:
163
 
        print '  working tree: %s' % working._format.get_format_description()
 
191
        outfile.write('  working tree: %s\n' %
 
192
            working._format.get_format_description())
164
193
    if branch:
165
 
        print '        branch: %s' % branch._format.get_format_description()
 
194
        outfile.write('        branch: %s\n' %
 
195
            branch._format.get_format_description())
166
196
    if repository:
167
 
        print '    repository: %s' % repository._format.get_format_description()
168
 
 
169
 
 
170
 
def _show_locking_info(repository, branch=None, working=None):
 
197
        outfile.write('    repository: %s\n' %
 
198
            repository._format.get_format_description())
 
199
 
 
200
 
 
201
def _show_locking_info(repository, branch=None, working=None, outfile=None):
171
202
    """Show locking status of working, branch and repository."""
172
203
    if (repository.get_physical_lock_status() or
173
204
        (branch and branch.get_physical_lock_status()) or
174
205
        (working and working.get_physical_lock_status())):
175
 
        print
176
 
        print 'Lock status:'
 
206
        outfile.write('\n')
 
207
        outfile.write('Lock status:\n')
177
208
        if working:
178
209
            if working.get_physical_lock_status():
179
210
                status = 'locked'
180
211
            else:
181
212
                status = 'unlocked'
182
 
            print '  working tree: %s' % status
 
213
            outfile.write('  working tree: %s\n' % status)
183
214
        if branch:
184
215
            if branch.get_physical_lock_status():
185
216
                status = 'locked'
186
217
            else:
187
218
                status = 'unlocked'
188
 
            print '        branch: %s' % status
 
219
            outfile.write('        branch: %s\n' % status)
189
220
        if repository:
190
221
            if repository.get_physical_lock_status():
191
222
                status = 'locked'
192
223
            else:
193
224
                status = 'unlocked'
194
 
            print '    repository: %s' % status
195
 
 
196
 
 
197
 
def _show_missing_revisions_branch(branch):
 
225
            outfile.write('    repository: %s\n' % status)
 
226
 
 
227
 
 
228
def _show_missing_revisions_branch(branch, outfile):
198
229
    """Show missing master revisions in branch."""
199
230
    # Try with inaccessible branch ?
200
231
    master = branch.get_master_branch()
201
232
    if master:
202
233
        local_extra, remote_extra = find_unmerged(branch, master)
203
234
        if remote_extra:
204
 
            print
205
 
            print 'Branch is out of date: missing %d revision%s.' % (
206
 
                len(remote_extra), plural(len(remote_extra)))
207
 
 
208
 
 
209
 
def _show_missing_revisions_working(working):
 
235
            outfile.write('\n')
 
236
            outfile.write(('Branch is out of date: missing %d '
 
237
                'revision%s.\n') % (len(remote_extra),
 
238
                plural(len(remote_extra))))
 
239
 
 
240
 
 
241
def _show_missing_revisions_working(working, outfile):
210
242
    """Show missing revisions in working tree."""
211
243
    branch = working.branch
212
244
    basis = working.basis_tree()
213
 
    work_inv = working.inventory
214
 
    branch_revno, branch_last_revision = branch.last_revision_info()
 
245
    try:
 
246
        branch_revno, branch_last_revision = branch.last_revision_info()
 
247
    except errors.UnsupportedOperation:
 
248
        return
215
249
    try:
216
250
        tree_last_id = working.get_parent_ids()[0]
217
251
    except IndexError:
220
254
    if branch_revno and tree_last_id != branch_last_revision:
221
255
        tree_last_revno = branch.revision_id_to_revno(tree_last_id)
222
256
        missing_count = branch_revno - tree_last_revno
223
 
        print
224
 
        print 'Working tree is out of date: missing %d revision%s.' % (
225
 
            missing_count, plural(missing_count))
226
 
 
227
 
 
228
 
def _show_working_stats(working):
 
257
        outfile.write('\n')
 
258
        outfile.write(('Working tree is out of date: missing %d '
 
259
            'revision%s.\n') % (missing_count, plural(missing_count)))
 
260
 
 
261
 
 
262
def _show_working_stats(working, outfile):
229
263
    """Show statistics about a working tree."""
230
264
    basis = working.basis_tree()
231
 
    work_inv = working.inventory
232
265
    delta = working.changes_from(basis, want_unchanged=True)
233
266
 
234
 
    print
235
 
    print 'In the working tree:'
236
 
    print '  %8s unchanged' % len(delta.unchanged)
237
 
    print '  %8d modified' % len(delta.modified)
238
 
    print '  %8d added' % len(delta.added)
239
 
    print '  %8d removed' % len(delta.removed)
240
 
    print '  %8d renamed' % len(delta.renamed)
 
267
    outfile.write('\n')
 
268
    outfile.write('In the working tree:\n')
 
269
    outfile.write('  %8s unchanged\n' % len(delta.unchanged))
 
270
    outfile.write('  %8d modified\n' % len(delta.modified))
 
271
    outfile.write('  %8d added\n' % len(delta.added))
 
272
    outfile.write('  %8d removed\n' % len(delta.removed))
 
273
    outfile.write('  %8d renamed\n' % len(delta.renamed))
241
274
 
242
275
    ignore_cnt = unknown_cnt = 0
243
276
    for path in working.extras():
245
278
            ignore_cnt += 1
246
279
        else:
247
280
            unknown_cnt += 1
248
 
    print '  %8d unknown' % unknown_cnt
249
 
    print '  %8d ignored' % ignore_cnt
 
281
    outfile.write('  %8d unknown\n' % unknown_cnt)
 
282
    outfile.write('  %8d ignored\n' % ignore_cnt)
250
283
 
251
284
    dir_cnt = 0
252
 
    for file_id in work_inv:
253
 
        if (work_inv.get_file_kind(file_id) == 'directory' and 
254
 
            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:
255
288
            dir_cnt += 1
256
 
    print '  %8d versioned %s' \
257
 
          % (dir_cnt,
258
 
             plural(dir_cnt, 'subdirectory', 'subdirectories'))
259
 
 
260
 
 
261
 
def _show_branch_stats(branch, verbose):
 
289
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
 
290
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
 
291
 
 
292
 
 
293
def _show_branch_stats(branch, verbose, outfile):
262
294
    """Show statistics about a branch."""
263
 
    revno, head = branch.last_revision_info()
264
 
    print
265
 
    print 'Branch history:'
266
 
    print '  %8d revision%s' % (revno, plural(revno))
 
295
    try:
 
296
        revno, head = branch.last_revision_info()
 
297
    except errors.UnsupportedOperation:
 
298
        return {}
 
299
    outfile.write('\n')
 
300
    outfile.write('Branch history:\n')
 
301
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
267
302
    stats = branch.repository.gather_stats(head, committers=verbose)
268
303
    if verbose:
269
304
        committers = stats['committers']
270
 
        print '  %8d committer%s' % (committers, plural(committers))
 
305
        outfile.write('  %8d committer%s\n' % (committers,
 
306
            plural(committers)))
271
307
    if revno:
272
308
        timestamp, timezone = stats['firstrev']
273
309
        age = int((time.time() - timestamp) / 3600 / 24)
274
 
        print '  %8d day%s old' % (age, plural(age))
275
 
        print '   first revision: %s' % osutils.format_date(timestamp,
276
 
            timezone)
 
310
        outfile.write('  %8d day%s old\n' % (age, plural(age)))
 
311
        outfile.write('   first revision: %s\n' %
 
312
            osutils.format_date(timestamp, timezone))
277
313
        timestamp, timezone = stats['latestrev']
278
 
        print '  latest revision: %s' % osutils.format_date(timestamp,
279
 
            timezone)
 
314
        outfile.write('  latest revision: %s\n' %
 
315
            osutils.format_date(timestamp, timezone))
280
316
    return stats
281
317
 
282
318
 
283
 
def _show_repository_info(repository):
 
319
def _show_repository_info(repository, outfile):
284
320
    """Show settings of a repository."""
285
321
    if repository.make_working_trees():
286
 
        print
287
 
        print 'Create working tree for new branches inside the repository.'
288
 
 
289
 
 
290
 
def _show_repository_stats(stats):
 
322
        outfile.write('\n')
 
323
        outfile.write('Create working tree for new branches inside '
 
324
            'the repository.\n')
 
325
 
 
326
 
 
327
def _show_repository_stats(repository, stats, outfile):
291
328
    """Show statistics about a repository."""
292
 
    if 'revisions' in stats or 'size' in stats:
293
 
        print
294
 
        print 'Repository:'
 
329
    f = StringIO()
295
330
    if 'revisions' in stats:
296
331
        revisions = stats['revisions']
297
 
        print '  %8d revision%s' % (revisions, plural(revisions))
 
332
        f.write('  %8d revision%s\n' % (revisions, plural(revisions)))
298
333
    if 'size' in stats:
299
 
        print '  %8d KiB' % (stats['size']/1024)
300
 
 
301
 
def show_bzrdir_info(a_bzrdir, verbose=False):
 
334
        f.write('  %8d KiB\n' % (stats['size']/1024))
 
335
    for hook in hooks['repository']:
 
336
        hook(repository, stats, f)
 
337
    if f.getvalue() != "":
 
338
        outfile.write('\n')
 
339
        outfile.write('Repository:\n')
 
340
        outfile.write(f.getvalue())
 
341
 
 
342
 
 
343
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
302
344
    """Output to stdout the 'info' for a_bzrdir."""
 
345
    if outfile is None:
 
346
        outfile = sys.stdout
303
347
    try:
304
348
        tree = a_bzrdir.open_workingtree(
305
349
            recommend_upgrade=False)
306
 
    except (NoWorkingTree, NotLocalUrl):
 
350
    except (NoWorkingTree, NotLocalUrl, NotBranchError):
307
351
        tree = None
308
352
        try:
309
353
            branch = a_bzrdir.open_branch()
312
356
            try:
313
357
                repository = a_bzrdir.open_repository()
314
358
            except NoRepositoryPresent:
315
 
                # Return silently; cmd_info already returned NotBranchError
316
 
                # if no bzrdir could be opened.
317
 
                return
 
359
                lockable = None
 
360
                repository = None
318
361
            else:
319
362
                lockable = repository
320
363
        else:
325
368
        repository = branch.repository
326
369
        lockable = tree
327
370
 
328
 
    lockable.lock_read()
 
371
    if lockable is not None:
 
372
        lockable.lock_read()
329
373
    try:
330
 
        show_component_info(a_bzrdir, repository, branch, tree, verbose)
 
374
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
 
375
                            outfile)
331
376
    finally:
332
 
        lockable.unlock()
 
377
        if lockable is not None:
 
378
            lockable.unlock()
333
379
 
334
380
 
335
381
def show_component_info(control, repository, branch=None, working=None,
336
 
    verbose=1):
 
382
    verbose=1, outfile=None):
337
383
    """Write info about all bzrdir components to stdout"""
 
384
    if outfile is None:
 
385
        outfile = sys.stdout
338
386
    if verbose is False:
339
387
        verbose = 1
340
388
    if verbose is True:
341
389
        verbose = 2
342
 
    layout = describe_layout(repository, branch, working)
 
390
    layout = describe_layout(repository, branch, working, control)
343
391
    format = describe_format(control, repository, branch, working)
344
 
    print "%s (format: %s)" % (layout, format)
345
 
    _show_location_info(gather_location_info(repository, branch, working))
 
392
    outfile.write("%s (format: %s)\n" % (layout, format))
 
393
    _show_location_info(
 
394
        gather_location_info(control=control, repository=repository,
 
395
            branch=branch, working=working),
 
396
        outfile)
 
397
    if branch is not None:
 
398
        _show_related_info(branch, outfile)
346
399
    if verbose == 0:
347
400
        return
348
 
    if branch is not None:
349
 
        _show_related_info(branch)
350
 
    _show_format_info(control, repository, branch, working)
351
 
    _show_locking_info(repository, branch, working)
352
 
    if branch is not None:
353
 
        _show_missing_revisions_branch(branch)
 
401
    _show_format_info(control, repository, branch, working, outfile)
 
402
    _show_locking_info(repository, branch, working, outfile)
 
403
    _show_control_dir_info(control, outfile)
 
404
    if branch is not None:
 
405
        _show_missing_revisions_branch(branch, outfile)
354
406
    if working is not None:
355
 
        _show_missing_revisions_working(working)
356
 
        _show_working_stats(working)
 
407
        _show_missing_revisions_working(working, outfile)
 
408
        _show_working_stats(working, outfile)
357
409
    elif branch is not None:
358
 
        _show_missing_revisions_branch(branch)
 
410
        _show_missing_revisions_branch(branch, outfile)
359
411
    if branch is not None:
360
 
        stats = _show_branch_stats(branch, verbose==2)
 
412
        show_committers = verbose >= 2
 
413
        stats = _show_branch_stats(branch, show_committers, outfile)
361
414
    else:
362
415
        stats = repository.gather_stats()
363
416
    if branch is None and working is None:
364
 
        _show_repository_info(repository)
365
 
    _show_repository_stats(stats)
366
 
 
367
 
 
368
 
def describe_layout(repository=None, branch=None, tree=None):
 
417
        _show_repository_info(repository, outfile)
 
418
    _show_repository_stats(repository, stats, outfile)
 
419
 
 
420
 
 
421
def describe_layout(repository=None, branch=None, tree=None, control=None):
369
422
    """Convert a control directory layout into a user-understandable term
370
423
 
371
424
    Common outputs include "Standalone tree", "Repository branch" and
372
425
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
373
426
    and "Empty control directory"
374
427
    """
 
428
    if branch is None and control is not None:
 
429
        try:
 
430
            branch_reference = control.get_branch_reference()
 
431
        except NotBranchError:
 
432
            pass
 
433
        else:
 
434
            if branch_reference is not None:
 
435
                return "Dangling branch reference"
375
436
    if repository is None:
376
437
        return 'Empty control directory'
377
438
    if branch is None and tree is None:
394
455
        if branch is None and tree is not None:
395
456
            phrase = "branchless tree"
396
457
        else:
397
 
            if (tree is not None and tree.bzrdir.root_transport.base !=
398
 
                branch.bzrdir.root_transport.base):
 
458
            if (tree is not None and tree.user_url !=
 
459
                branch.user_url):
399
460
                independence = ''
400
461
                phrase = "Lightweight checkout"
401
462
            elif branch.get_bound_location() is not None:
420
481
    """
421
482
    candidates  = []
422
483
    if (branch is not None and tree is not None and
423
 
        branch.bzrdir.root_transport.base !=
424
 
        tree.bzrdir.root_transport.base):
 
484
        branch.user_url != tree.user_url):
425
485
        branch = None
426
486
        repository = None
427
 
    for key in bzrdir.format_registry.keys():
428
 
        format = bzrdir.format_registry.make_bzrdir(key)
 
487
    non_aliases = set(controldir.format_registry.keys())
 
488
    non_aliases.difference_update(controldir.format_registry.aliases())
 
489
    for key in non_aliases:
 
490
        format = controldir.format_registry.make_bzrdir(key)
429
491
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
430
492
            if (tree and format.workingtree_format !=
431
493
                tree._format):
441
503
        candidates.append(key)
442
504
    if len(candidates) == 0:
443
505
        return 'unnamed'
444
 
    new_candidates = [c for c in candidates if c != 'default']
445
 
    if len(new_candidates) > 0:
446
 
        candidates = new_candidates
 
506
    candidates.sort()
447
507
    new_candidates = [c for c in candidates if not
448
 
        bzrdir.format_registry.get_info(c).hidden]
 
508
        controldir.format_registry.get_info(c).hidden]
449
509
    if len(new_candidates) > 0:
 
510
        # If there are any non-hidden formats that match, only return those to
 
511
        # avoid listing hidden formats except when only a hidden format will
 
512
        # do.
450
513
        candidates = new_candidates
451
514
    return ' or '.join(candidates)
452
515
 
453
 
@deprecated_function(zero_eight)
454
 
def show_info(b):
455
 
    """Please see show_bzrdir_info."""
456
 
    return show_bzrdir_info(b.bzrdir)
457
 
 
458
 
 
459
 
@deprecated_function(zero_eighteen)
460
 
def show_tree_info(working, verbose):
461
 
    """Output to stdout the 'info' for working."""
462
 
    branch = working.branch
463
 
    repository = branch.repository
464
 
    control = working.bzrdir
465
 
    show_component_info(control, repository, branch, working, verbose)
466
 
 
467
 
 
468
 
@deprecated_function(zero_eighteen)
469
 
def show_branch_info(branch, verbose):
470
 
    """Output to stdout the 'info' for branch."""
471
 
    repository = branch.repository
472
 
    control = branch.bzrdir
473
 
    show_component_info(control, repository, branch, verbose=verbose)
474
 
 
475
 
 
476
 
@deprecated_function(zero_eighteen)
477
 
def show_repository_info(repository, verbose):
478
 
    """Output to stdout the 'info' for repository."""
479
 
    control = repository.bzrdir
480
 
    show_component_info(control, repository, verbose=verbose)
 
516
 
 
517
class InfoHooks(_mod_hooks.Hooks):
 
518
    """Hooks for the info command."""
 
519
 
 
520
    def __init__(self):
 
521
        super(InfoHooks, self).__init__("bzrlib.info", "hooks")
 
522
        self.add_hook('repository',
 
523
            "Invoked when displaying the statistics for a repository. "
 
524
            "repository is called with a statistics dictionary as returned "
 
525
            "by the repository and a file-like object to write to.", (1, 15))
 
526
 
 
527
 
 
528
hooks = InfoHooks()