~bzr-pqm/bzr/bzr.dev

4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2005-2010 Canonical Ltd
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2
#
77 by mbp at sourcefrog
- split info command out into separate file
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.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
7
#
77 by mbp at sourcefrog
- split info command out into separate file
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.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
12
#
77 by mbp at sourcefrog
- split info command out into separate file
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
77 by mbp at sourcefrog
- split info command out into separate file
16
1534.5.1 by Robert Collins
Give info some reasonable output and tests.
17
__all__ = ['show_bzrdir_info']
18
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
19
from cStringIO import StringIO
77 by mbp at sourcefrog
- split info command out into separate file
20
import time
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
21
import sys
1534.5.1 by Robert Collins
Give info some reasonable output and tests.
22
1551.9.22 by Aaron Bentley
Use urlutils for info. Fixes bug #76229
23
from bzrlib import (
2363.5.5 by Aaron Bentley
add info.describe_format
24
    bzrdir,
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
25
    errors,
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
26
    hooks as _mod_hooks,
1551.9.22 by Aaron Bentley
Use urlutils for info. Fixes bug #76229
27
    osutils,
28
    urlutils,
29
    )
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
30
from bzrlib.errors import (NoWorkingTree, NotBranchError,
31
                           NoRepositoryPresent, NotLocalUrl)
1587.1.14 by Robert Collins
Make bound branch creation happen via 'checkout'
32
from bzrlib.missing import find_unmerged
77 by mbp at sourcefrog
- split info command out into separate file
33
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
34
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
35
def plural(n, base='', pl=None):
36
    if n == 1:
37
        return base
1963.2.6 by Robey Pointer
pychecker is on crack; go back to using 'is None'.
38
    elif pl is not None:
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
39
        return pl
40
    else:
41
        return 's'
42
43
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
44
class LocationList(object):
45
46
    def __init__(self, base_path):
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
47
        self.locs = []
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
48
        self.base_path = base_path
49
50
    def add_url(self, label, url):
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
51
        """Add a URL to the list, converting it to a path if possible"""
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
52
        if url is None:
53
            return
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
54
        try:
55
            path = urlutils.local_path_from_url(url)
56
        except errors.InvalidURL:
57
            self.locs.append((label, url))
58
        else:
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
59
            self.add_path(label, path)
2363.5.18 by Aaron Bentley
Get all tests passing
60
61
    def add_path(self, label, path):
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
62
        """Add a path, converting it to a relative path if possible"""
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
63
        try:
64
            path = osutils.relpath(self.base_path, path)
65
        except errors.PathNotChild:
66
            pass
67
        else:
68
            if path == '':
69
                path = '.'
70
        if path != '/':
71
            path = path.rstrip('/')
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
72
        self.locs.append((label, path))
2363.5.18 by Aaron Bentley
Get all tests passing
73
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
74
    def get_lines(self):
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 ]
2363.5.18 by Aaron Bentley
Get all tests passing
77
78
79
def gather_location_info(repository, branch=None, working=None):
80
    locs = {}
5158.6.6 by Martin Pool
Change info code to use user_url etc
81
    repository_path = repository.user_url
2363.5.18 by Aaron Bentley
Get all tests passing
82
    if branch is not None:
5158.6.6 by Martin Pool
Change info code to use user_url etc
83
        branch_path = branch.user_url
2363.5.18 by Aaron Bentley
Get all tests passing
84
        master_path = branch.get_bound_location()
85
        if master_path is None:
86
            master_path = branch_path
87
    else:
88
        branch_path = None
89
        master_path = None
90
    if working:
5158.6.6 by Martin Pool
Change info code to use user_url etc
91
        working_path = working.user_url
1694.2.6 by Martin Pool
[merge] bzr.dev
92
        if working_path != branch_path:
2363.5.18 by Aaron Bentley
Get all tests passing
93
            locs['light checkout root'] = working_path
94
        if master_path != branch_path:
1694.2.6 by Martin Pool
[merge] bzr.dev
95
            if repository.is_shared():
2363.5.18 by Aaron Bentley
Get all tests passing
96
                locs['repository checkout root'] = branch_path
1694.2.6 by Martin Pool
[merge] bzr.dev
97
            else:
2363.5.18 by Aaron Bentley
Get all tests passing
98
                locs['checkout root'] = branch_path
99
        if working_path != master_path:
100
            locs['checkout of branch'] = master_path
1694.2.6 by Martin Pool
[merge] bzr.dev
101
        elif repository.is_shared():
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
102
            locs['repository branch'] = branch_path
2363.5.18 by Aaron Bentley
Get all tests passing
103
        elif branch_path is not None:
1694.2.6 by Martin Pool
[merge] bzr.dev
104
            # standalone
2363.5.18 by Aaron Bentley
Get all tests passing
105
            locs['branch root'] = branch_path
106
    else:
107
        working_path = None
1624.3.48 by Olaf Conradi
Add info on standalone branches without a working tree.
108
        if repository.is_shared():
2363.5.18 by Aaron Bentley
Get all tests passing
109
            # lightweight checkout of branch in shared repository
110
            if branch_path is not None:
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
111
                locs['repository branch'] = branch_path
2363.5.18 by Aaron Bentley
Get all tests passing
112
        elif branch_path is not None:
113
            # standalone
114
            locs['branch root'] = branch_path
2363.5.19 by Aaron Bentley
Add support for bound branches
115
            if master_path != branch_path:
116
                locs['bound to branch'] = master_path
1624.3.48 by Olaf Conradi
Add info on standalone branches without a working tree.
117
        else:
2363.5.18 by Aaron Bentley
Get all tests passing
118
            locs['repository'] = repository_path
119
    if repository.is_shared():
120
        # lightweight checkout of branch in shared repository
121
        locs['shared repository'] = repository_path
2363.5.23 by Aaron Bentley
Output 2-tuples from gather_locations
122
    order = ['light checkout root', 'repository checkout root',
123
             'checkout root', 'checkout of branch', 'shared repository',
124
             'repository', 'repository branch', 'branch root',
125
             'bound to branch']
126
    return [(n, locs[n]) for n in order if n in locs]
2363.5.18 by Aaron Bentley
Get all tests passing
127
128
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
129
def _show_location_info(locs, outfile):
2363.5.18 by Aaron Bentley
Get all tests passing
130
    """Show known locations for working, branch and repository."""
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
131
    outfile.write('Location:\n')
2804.4.3 by Alexander Belchenko
fix for test_info-tests: using osutils.getcwd instead of os.getcwd (sigh)
132
    path_list = LocationList(osutils.getcwd())
2363.5.23 by Aaron Bentley
Output 2-tuples from gather_locations
133
    for name, loc in locs:
134
        path_list.add_url(name, loc)
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
135
    outfile.writelines(path_list.get_lines())
136
1694.2.6 by Martin Pool
[merge] bzr.dev
137
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
138
def _gather_related_branches(branch):
2804.4.3 by Alexander Belchenko
fix for test_info-tests: using osutils.getcwd instead of os.getcwd (sigh)
139
    locs = LocationList(osutils.getcwd())
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
140
    locs.add_url('public branch', branch.get_public_branch())
141
    locs.add_url('push branch', branch.get_push_location())
142
    locs.add_url('parent branch', branch.get_parent())
143
    locs.add_url('submit branch', branch.get_submit_branch())
3221.11.21 by Robert Collins
Have info report on stacked branches.
144
    try:
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
145
        locs.add_url('stacked on', branch.get_stacked_on_url())
3221.11.21 by Robert Collins
Have info report on stacked branches.
146
    except (errors.UnstackableBranchFormat, errors.UnstackableRepositoryFormat,
147
        errors.NotStacked):
148
        pass
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
149
    return locs
1694.2.6 by Martin Pool
[merge] bzr.dev
150
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
151
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
152
def _show_related_info(branch, outfile):
1694.2.6 by Martin Pool
[merge] bzr.dev
153
    """Show parent and push location of branch."""
1551.15.41 by Aaron Bentley
Make info provide more related brances, and format all branches nicely
154
    locs = _gather_related_branches(branch)
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
155
    if len(locs.locs) > 0:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
156
        outfile.write('\n')
157
        outfile.write('Related branches:\n')
1551.15.43 by Aaron Bentley
Provide ways of getting at unicode-clean output
158
        outfile.writelines(locs.get_lines())
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
159
160
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
161
def _show_format_info(control=None, repository=None, branch=None,
162
                      working=None, outfile=None):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
163
    """Show known formats for control, working, branch and repository."""
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
164
    outfile.write('\n')
165
    outfile.write('Format:\n')
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
166
    if control:
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
167
        outfile.write('       control: %s\n' %
168
            control._format.get_format_description())
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
169
    if working:
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
170
        outfile.write('  working tree: %s\n' %
171
            working._format.get_format_description())
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
172
    if branch:
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
173
        outfile.write('        branch: %s\n' %
174
            branch._format.get_format_description())
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
175
    if repository:
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
176
        outfile.write('    repository: %s\n' %
177
            repository._format.get_format_description())
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
178
179
180
def _show_locking_info(repository, branch=None, working=None, outfile=None):
1694.2.6 by Martin Pool
[merge] bzr.dev
181
    """Show locking status of working, branch and repository."""
182
    if (repository.get_physical_lock_status() or
183
        (branch and branch.get_physical_lock_status()) or
184
        (working and working.get_physical_lock_status())):
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
185
        outfile.write('\n')
186
        outfile.write('Lock status:\n')
1694.2.6 by Martin Pool
[merge] bzr.dev
187
        if working:
188
            if working.get_physical_lock_status():
189
                status = 'locked'
190
            else:
191
                status = 'unlocked'
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
192
            outfile.write('  working tree: %s\n' % status)
1694.2.6 by Martin Pool
[merge] bzr.dev
193
        if branch:
194
            if branch.get_physical_lock_status():
195
                status = 'locked'
196
            else:
197
                status = 'unlocked'
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
198
            outfile.write('        branch: %s\n' % status)
1694.2.6 by Martin Pool
[merge] bzr.dev
199
        if repository:
200
            if repository.get_physical_lock_status():
201
                status = 'locked'
202
            else:
203
                status = 'unlocked'
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
204
            outfile.write('    repository: %s\n' % status)
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
205
206
207
def _show_missing_revisions_branch(branch, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
208
    """Show missing master revisions in branch."""
1587.1.14 by Robert Collins
Make bound branch creation happen via 'checkout'
209
    # Try with inaccessible branch ?
1624.3.2 by Olaf Conradi
Implemented table of constructs from BzrInfo specification.
210
    master = branch.get_master_branch()
1587.1.14 by Robert Collins
Make bound branch creation happen via 'checkout'
211
    if master:
1624.3.2 by Olaf Conradi
Implemented table of constructs from BzrInfo specification.
212
        local_extra, remote_extra = find_unmerged(branch, master)
1587.1.14 by Robert Collins
Make bound branch creation happen via 'checkout'
213
        if remote_extra:
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
214
            outfile.write('\n')
215
            outfile.write(('Branch is out of date: missing %d '
216
                'revision%s.\n') % (len(remote_extra),
217
                plural(len(remote_extra))))
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
218
219
220
def _show_missing_revisions_working(working, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
221
    """Show missing revisions in working tree."""
222
    branch = working.branch
223
    basis = working.basis_tree()
224
    work_inv = working.inventory
2249.4.2 by Wouter van Heyst
Convert callers of Branch.revision_history() to Branch.last_revision_info() where sensible.
225
    branch_revno, branch_last_revision = branch.last_revision_info()
1908.7.6 by Robert Collins
Deprecate WorkingTree.last_revision.
226
    try:
227
        tree_last_id = working.get_parent_ids()[0]
228
    except IndexError:
229
        tree_last_id = None
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
230
2249.4.2 by Wouter van Heyst
Convert callers of Branch.revision_history() to Branch.last_revision_info() where sensible.
231
    if branch_revno and tree_last_id != branch_last_revision:
1624.3.11 by Olaf Conradi
Test cases exposed a bug in missing revisions count of working tree. It
232
        tree_last_revno = branch.revision_id_to_revno(tree_last_id)
2249.4.2 by Wouter van Heyst
Convert callers of Branch.revision_history() to Branch.last_revision_info() where sensible.
233
        missing_count = branch_revno - tree_last_revno
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
234
        outfile.write('\n')
235
        outfile.write(('Working tree is out of date: missing %d '
236
            'revision%s.\n') % (missing_count, plural(missing_count)))
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
237
238
239
def _show_working_stats(working, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
240
    """Show statistics about a working tree."""
241
    basis = working.basis_tree()
242
    work_inv = working.inventory
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
243
    delta = working.changes_from(basis, want_unchanged=True)
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
244
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
245
    outfile.write('\n')
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))
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
252
253
    ignore_cnt = unknown_cnt = 0
254
    for path in working.extras():
255
        if working.is_ignored(path):
256
            ignore_cnt += 1
257
        else:
258
            unknown_cnt += 1
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
259
    outfile.write('  %8d unknown\n' % unknown_cnt)
260
    outfile.write('  %8d ignored\n' % ignore_cnt)
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
261
262
    dir_cnt = 0
1731.1.39 by Aaron Bentley
Reject removing is_root
263
    for file_id in work_inv:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
264
        if (work_inv.get_file_kind(file_id) == 'directory' and
1731.1.39 by Aaron Bentley
Reject removing is_root
265
            not work_inv.is_root(file_id)):
266
            dir_cnt += 1
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
267
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
268
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
77 by mbp at sourcefrog
- split info command out into separate file
269
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
270
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
271
def _show_branch_stats(branch, verbose, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
272
    """Show statistics about a branch."""
2258.1.1 by Robert Collins
Move info branch statistics gathering into the repository to allow smart server optimisation (Robert Collins).
273
    revno, head = branch.last_revision_info()
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
274
    outfile.write('\n')
275
    outfile.write('Branch history:\n')
276
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
2258.1.1 by Robert Collins
Move info branch statistics gathering into the repository to allow smart server optimisation (Robert Collins).
277
    stats = branch.repository.gather_stats(head, committers=verbose)
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
278
    if verbose:
2258.1.1 by Robert Collins
Move info branch statistics gathering into the repository to allow smart server optimisation (Robert Collins).
279
        committers = stats['committers']
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
280
        outfile.write('  %8d committer%s\n' % (committers,
281
            plural(committers)))
2258.1.1 by Robert Collins
Move info branch statistics gathering into the repository to allow smart server optimisation (Robert Collins).
282
    if revno:
283
        timestamp, timezone = stats['firstrev']
284
        age = int((time.time() - timestamp) / 3600 / 24)
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
285
        outfile.write('  %8d day%s old\n' % (age, plural(age)))
286
        outfile.write('   first revision: %s\n' %
287
            osutils.format_date(timestamp, timezone))
2258.1.1 by Robert Collins
Move info branch statistics gathering into the repository to allow smart server optimisation (Robert Collins).
288
        timestamp, timezone = stats['latestrev']
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
289
        outfile.write('  latest revision: %s\n' %
290
            osutils.format_date(timestamp, timezone))
2258.1.2 by Robert Collins
New version of gather_stats which gathers aggregate data too.
291
    return stats
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
292
293
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
294
def _show_repository_info(repository, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
295
    """Show settings of a repository."""
296
    if repository.make_working_trees():
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
297
        outfile.write('\n')
298
        outfile.write('Create working tree for new branches inside '
299
            'the repository.\n')
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
300
301
4307.3.3 by Jelmer Vernooij
Add repository argument to 'repository' info hook, per Roberts review.
302
def _show_repository_stats(repository, stats, outfile):
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
303
    """Show statistics about a repository."""
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
304
    f = StringIO()
2258.1.2 by Robert Collins
New version of gather_stats which gathers aggregate data too.
305
    if 'revisions' in stats:
306
        revisions = stats['revisions']
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
307
        f.write('  %8d revision%s\n' % (revisions, plural(revisions)))
2258.1.2 by Robert Collins
New version of gather_stats which gathers aggregate data too.
308
    if 'size' in stats:
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
309
        f.write('  %8d KiB\n' % (stats['size']/1024))
310
    for hook in hooks['repository']:
4307.3.3 by Jelmer Vernooij
Add repository argument to 'repository' info hook, per Roberts review.
311
        hook(repository, stats, f)
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
312
    if f.getvalue() != "":
313
        outfile.write('\n')
314
        outfile.write('Repository:\n')
315
        outfile.write(f.getvalue())
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
316
1624.3.21 by Olaf Conradi
Make bzr info command work on both local and remote locations. Support
317
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
318
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
319
    """Output to stdout the 'info' for a_bzrdir."""
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
320
    if outfile is None:
321
        outfile = sys.stdout
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
322
    try:
2363.5.9 by Aaron Bentley
Merge from bzr.dev
323
        tree = a_bzrdir.open_workingtree(
324
            recommend_upgrade=False)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
325
    except (NoWorkingTree, NotLocalUrl):
326
        tree = None
327
        try:
328
            branch = a_bzrdir.open_branch()
329
        except NotBranchError:
330
            branch = None
331
            try:
332
                repository = a_bzrdir.open_repository()
333
            except NoRepositoryPresent:
334
                # Return silently; cmd_info already returned NotBranchError
335
                # if no bzrdir could be opened.
336
                return
337
            else:
338
                lockable = repository
339
        else:
340
            repository = branch.repository
341
            lockable = branch
342
    else:
343
        branch = tree.branch
344
        repository = branch.repository
345
        lockable = tree
346
347
    lockable.lock_read()
348
    try:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
349
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
350
                            outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
351
    finally:
352
        lockable.unlock()
353
354
355
def show_component_info(control, repository, branch=None, working=None,
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
356
    verbose=1, outfile=None):
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
357
    """Write info about all bzrdir components to stdout"""
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
358
    if outfile is None:
359
        outfile = sys.stdout
2363.5.7 by Aaron Bentley
Make verbose mean what I want
360
    if verbose is False:
361
        verbose = 1
362
    if verbose is True:
363
        verbose = 2
2363.5.6 by Aaron Bentley
Add short format description
364
    layout = describe_layout(repository, branch, working)
365
    format = describe_format(control, repository, branch, working)
2968.2.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``
366
    outfile.write("%s (format: %s)\n" % (layout, format))
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
367
    _show_location_info(gather_location_info(repository, branch, working),
368
                        outfile)
2584.2.1 by Adeodato Simó
Make `bzr info` show related branches in non-verbose mode.
369
    if branch is not None:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
370
        _show_related_info(branch, outfile)
2363.5.7 by Aaron Bentley
Make verbose mean what I want
371
    if verbose == 0:
372
        return
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
373
    _show_format_info(control, repository, branch, working, outfile)
374
    _show_locking_info(repository, branch, working, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
375
    if branch is not None:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
376
        _show_missing_revisions_branch(branch, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
377
    if working is not None:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
378
        _show_missing_revisions_working(working, outfile)
379
        _show_working_stats(working, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
380
    elif branch is not None:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
381
        _show_missing_revisions_branch(branch, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
382
    if branch is not None:
4032.2.1 by Ian Clatworthy
omit branch committers from info -v (now requires -vv)
383
        show_committers = verbose >= 2
384
        stats = _show_branch_stats(branch, show_committers, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
385
    else:
386
        stats = repository.gather_stats()
387
    if branch is None and working is None:
2904.3.1 by Lukáš Lalinský
Unicode-safe output from ``bzr info``.
388
        _show_repository_info(repository, outfile)
4307.3.3 by Jelmer Vernooij
Add repository argument to 'repository' info hook, per Roberts review.
389
    _show_repository_stats(repository, stats, outfile)
2363.5.1 by Aaron Bentley
Unify info display into show_component_info
390
391
2363.5.2 by Aaron Bentley
Implement layout description
392
def describe_layout(repository=None, branch=None, tree=None):
393
    """Convert a control directory layout into a user-understandable term
394
395
    Common outputs include "Standalone tree", "Repository branch" and
396
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
397
    and "Empty control directory"
398
    """
399
    if repository is None:
400
        return 'Empty control directory'
401
    if branch is None and tree is None:
402
        if repository.is_shared():
403
            phrase = 'Shared repository'
404
        else:
405
            phrase = 'Unshared repository'
406
        if repository.make_working_trees():
407
            phrase += ' with trees'
408
        return phrase
409
    else:
410
        if repository.is_shared():
411
            independence = "Repository "
412
        else:
413
            independence = "Standalone "
414
        if tree is not None:
415
            phrase = "tree"
416
        else:
417
            phrase = "branch"
418
        if branch is None and tree is not None:
419
            phrase = "branchless tree"
420
        else:
5158.6.6 by Martin Pool
Change info code to use user_url etc
421
            if (tree is not None and tree.user_url !=
422
                branch.user_url):
2363.5.4 by Aaron Bentley
Eliminate the concept of a 'repository lightweight checkout'
423
                independence = ''
2363.5.2 by Aaron Bentley
Implement layout description
424
                phrase = "Lightweight checkout"
425
            elif branch.get_bound_location() is not None:
426
                if independence == 'Standalone ':
427
                    independence = ''
428
                if tree is None:
429
                    phrase = "Bound branch"
430
                else:
431
                    phrase = "Checkout"
432
        if independence != "":
433
            phrase = phrase.lower()
434
        return "%s%s" % (independence, phrase)
435
436
2363.5.5 by Aaron Bentley
add info.describe_format
437
def describe_format(control, repository, branch, tree):
438
    """Determine the format of an existing control directory
439
440
    Several candidates may be found.  If so, the names are returned as a
2363.5.17 by Aaron Bentley
Change separator from '/' to 'or'
441
    single string, separated by ' or '.
2363.5.5 by Aaron Bentley
add info.describe_format
442
443
    If no matching candidate is found, "unnamed" is returned.
444
    """
445
    candidates  = []
2363.5.6 by Aaron Bentley
Add short format description
446
    if (branch is not None and tree is not None and
5158.6.6 by Martin Pool
Change info code to use user_url etc
447
        branch.user_url != tree.user_url):
2363.5.6 by Aaron Bentley
Add short format description
448
        branch = None
449
        repository = None
3152.2.2 by Robert Collins
The bzrdir format registry now accepts an ``alias`` keyword to
450
    non_aliases = set(bzrdir.format_registry.keys())
451
    non_aliases.difference_update(bzrdir.format_registry.aliases())
452
    for key in non_aliases:
2363.5.5 by Aaron Bentley
add info.describe_format
453
        format = bzrdir.format_registry.make_bzrdir(key)
454
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
455
            if (tree and format.workingtree_format !=
456
                tree._format):
457
                continue
458
            if (branch and format.get_branch_format() !=
459
                branch._format):
460
                continue
461
            if (repository and format.repository_format !=
462
                repository._format):
463
                continue
464
        if format.__class__ is not control._format.__class__:
465
            continue
466
        candidates.append(key)
467
    if len(candidates) == 0:
468
        return 'unnamed'
3152.2.2 by Robert Collins
The bzrdir format registry now accepts an ``alias`` keyword to
469
    candidates.sort()
2363.5.6 by Aaron Bentley
Add short format description
470
    new_candidates = [c for c in candidates if not
471
        bzrdir.format_registry.get_info(c).hidden]
472
    if len(new_candidates) > 0:
3152.2.2 by Robert Collins
The bzrdir format registry now accepts an ``alias`` keyword to
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
475
        # do.
2363.5.6 by Aaron Bentley
Add short format description
476
        candidates = new_candidates
2363.5.17 by Aaron Bentley
Change separator from '/' to 'or'
477
    return ' or '.join(candidates)
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
478
479
480
class InfoHooks(_mod_hooks.Hooks):
481
    """Hooks for the info command."""
482
483
    def __init__(self):
4781.1.1 by Vincent Ladeuil
Hooks daughter classes should always call the base constructor
484
        super(InfoHooks, self).__init__()
4307.3.1 by Jelmer Vernooij
Allow registering hooks that extend the Repository section in 'bzr info -v'.
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), 
489
            None))
490
491
492
hooks = InfoHooks()