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