~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/info.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

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
 
 
17
from __future__ import absolute_import
16
18
 
17
19
__all__ = ['show_bzrdir_info']
18
20
 
19
 
import os
 
21
from cStringIO import StringIO
20
22
import time
21
23
import sys
22
24
 
23
25
from bzrlib import (
24
26
    bzrdir,
25
 
    diff,
 
27
    controldir,
26
28
    errors,
 
29
    hooks as _mod_hooks,
27
30
    osutils,
28
31
    urlutils,
29
32
    )
76
79
        return ["  %*s: %s\n" % (max_len, l, u) for l, u in self.locs ]
77
80
 
78
81
 
79
 
def gather_location_info(repository, branch=None, working=None):
 
82
def gather_location_info(repository=None, branch=None, working=None,
 
83
        control=None):
80
84
    locs = {}
81
 
    repository_path = repository.bzrdir.root_transport.base
82
85
    if branch is not None:
83
 
        branch_path = branch.bzrdir.root_transport.base
 
86
        branch_path = branch.user_url
84
87
        master_path = branch.get_bound_location()
85
88
        if master_path is None:
86
89
            master_path = branch_path
87
90
    else:
88
91
        branch_path = None
89
92
        master_path = None
 
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
90
98
    if working:
91
 
        working_path = working.bzrdir.root_transport.base
 
99
        working_path = working.user_url
92
100
        if working_path != branch_path:
93
101
            locs['light checkout root'] = working_path
94
102
        if master_path != branch_path:
105
113
            locs['branch root'] = branch_path
106
114
    else:
107
115
        working_path = None
108
 
        if repository.is_shared():
 
116
        if repository is not None and repository.is_shared():
109
117
            # lightweight checkout of branch in shared repository
110
118
            if branch_path is not None:
111
119
                locs['repository branch'] = branch_path
112
120
        elif branch_path is not None:
113
121
            # standalone
114
122
            locs['branch root'] = branch_path
115
 
            if master_path != branch_path:
116
 
                locs['bound to branch'] = master_path
 
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
117
127
        else:
118
 
            locs['repository'] = repository_path
119
 
    if repository.is_shared():
 
128
            # Really, at least a control directory should be
 
129
            # passed in for this method to be useful.
 
130
            pass
 
131
        if master_path != branch_path:
 
132
            locs['bound to branch'] = master_path
 
133
    if repository is not None and repository.is_shared():
120
134
        # lightweight checkout of branch in shared repository
121
 
        locs['shared repository'] = repository_path
122
 
    order = ['light checkout root', 'repository checkout root',
123
 
             'checkout root', 'checkout of branch', 'shared repository',
 
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',
124
139
             'repository', 'repository branch', 'branch root',
125
140
             'bound to branch']
126
141
    return [(n, locs[n]) for n in order if n in locs]
158
173
        outfile.writelines(locs.get_lines())
159
174
 
160
175
 
 
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
 
161
184
def _show_format_info(control=None, repository=None, branch=None,
162
185
                      working=None, outfile=None):
163
186
    """Show known formats for control, working, branch and repository."""
177
200
            repository._format.get_format_description())
178
201
 
179
202
 
180
 
def _show_locking_info(repository, branch=None, working=None, outfile=None):
 
203
def _show_locking_info(repository=None, branch=None, working=None,
 
204
        outfile=None):
181
205
    """Show locking status of working, branch and repository."""
182
 
    if (repository.get_physical_lock_status() or
 
206
    if (repository and repository.get_physical_lock_status() or
183
207
        (branch and branch.get_physical_lock_status()) or
184
208
        (working and working.get_physical_lock_status())):
185
209
        outfile.write('\n')
221
245
    """Show missing revisions in working tree."""
222
246
    branch = working.branch
223
247
    basis = working.basis_tree()
224
 
    work_inv = working.inventory
225
 
    branch_revno, branch_last_revision = branch.last_revision_info()
 
248
    try:
 
249
        branch_revno, branch_last_revision = branch.last_revision_info()
 
250
    except errors.UnsupportedOperation:
 
251
        return
226
252
    try:
227
253
        tree_last_id = working.get_parent_ids()[0]
228
254
    except IndexError:
239
265
def _show_working_stats(working, outfile):
240
266
    """Show statistics about a working tree."""
241
267
    basis = working.basis_tree()
242
 
    work_inv = working.inventory
243
268
    delta = working.changes_from(basis, want_unchanged=True)
244
269
 
245
270
    outfile.write('\n')
260
285
    outfile.write('  %8d ignored\n' % ignore_cnt)
261
286
 
262
287
    dir_cnt = 0
263
 
    for file_id in work_inv:
264
 
        if (work_inv.get_file_kind(file_id) == 'directory' and 
265
 
            not work_inv.is_root(file_id)):
 
288
    root_id = working.get_root_id()
 
289
    for path, entry in working.iter_entries_by_dir():
 
290
        if entry.kind == 'directory' and entry.file_id != root_id:
266
291
            dir_cnt += 1
267
292
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
268
293
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
270
295
 
271
296
def _show_branch_stats(branch, verbose, outfile):
272
297
    """Show statistics about a branch."""
273
 
    revno, head = branch.last_revision_info()
 
298
    try:
 
299
        revno, head = branch.last_revision_info()
 
300
    except errors.UnsupportedOperation:
 
301
        return {}
274
302
    outfile.write('\n')
275
303
    outfile.write('Branch history:\n')
276
304
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
299
327
            'the repository.\n')
300
328
 
301
329
 
302
 
def _show_repository_stats(stats, outfile):
 
330
def _show_repository_stats(repository, stats, outfile):
303
331
    """Show statistics about a repository."""
304
 
    if 'revisions' in stats or 'size' in stats:
305
 
        outfile.write('\n')
306
 
        outfile.write('Repository:\n')
 
332
    f = StringIO()
307
333
    if 'revisions' in stats:
308
334
        revisions = stats['revisions']
309
 
        outfile.write('  %8d revision%s\n' % (revisions, plural(revisions)))
 
335
        f.write('  %8d revision%s\n' % (revisions, plural(revisions)))
310
336
    if 'size' in stats:
311
 
        outfile.write('  %8d KiB\n' % (stats['size']/1024))
 
337
        f.write('  %8d KiB\n' % (stats['size']/1024))
 
338
    for hook in hooks['repository']:
 
339
        hook(repository, stats, f)
 
340
    if f.getvalue() != "":
 
341
        outfile.write('\n')
 
342
        outfile.write('Repository:\n')
 
343
        outfile.write(f.getvalue())
312
344
 
313
345
 
314
346
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
318
350
    try:
319
351
        tree = a_bzrdir.open_workingtree(
320
352
            recommend_upgrade=False)
321
 
    except (NoWorkingTree, NotLocalUrl):
 
353
    except (NoWorkingTree, NotLocalUrl, NotBranchError):
322
354
        tree = None
323
355
        try:
324
 
            branch = a_bzrdir.open_branch()
 
356
            branch = a_bzrdir.open_branch(name="")
325
357
        except NotBranchError:
326
358
            branch = None
327
359
            try:
328
360
                repository = a_bzrdir.open_repository()
329
361
            except NoRepositoryPresent:
330
 
                # Return silently; cmd_info already returned NotBranchError
331
 
                # if no bzrdir could be opened.
332
 
                return
 
362
                lockable = None
 
363
                repository = None
333
364
            else:
334
365
                lockable = repository
335
366
        else:
340
371
        repository = branch.repository
341
372
        lockable = tree
342
373
 
343
 
    lockable.lock_read()
 
374
    if lockable is not None:
 
375
        lockable.lock_read()
344
376
    try:
345
377
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
346
378
                            outfile)
347
379
    finally:
348
 
        lockable.unlock()
 
380
        if lockable is not None:
 
381
            lockable.unlock()
349
382
 
350
383
 
351
384
def show_component_info(control, repository, branch=None, working=None,
357
390
        verbose = 1
358
391
    if verbose is True:
359
392
        verbose = 2
360
 
    layout = describe_layout(repository, branch, working)
 
393
    layout = describe_layout(repository, branch, working, control)
361
394
    format = describe_format(control, repository, branch, working)
362
395
    outfile.write("%s (format: %s)\n" % (layout, format))
363
 
    _show_location_info(gather_location_info(repository, branch, working),
364
 
                        outfile)
 
396
    _show_location_info(
 
397
        gather_location_info(control=control, repository=repository,
 
398
            branch=branch, working=working),
 
399
        outfile)
365
400
    if branch is not None:
366
401
        _show_related_info(branch, outfile)
367
402
    if verbose == 0:
368
403
        return
369
404
    _show_format_info(control, repository, branch, working, outfile)
370
405
    _show_locking_info(repository, branch, working, outfile)
 
406
    _show_control_dir_info(control, outfile)
371
407
    if branch is not None:
372
408
        _show_missing_revisions_branch(branch, outfile)
373
409
    if working is not None:
376
412
    elif branch is not None:
377
413
        _show_missing_revisions_branch(branch, outfile)
378
414
    if branch is not None:
379
 
        stats = _show_branch_stats(branch, verbose==2, outfile)
380
 
    else:
 
415
        show_committers = verbose >= 2
 
416
        stats = _show_branch_stats(branch, show_committers, outfile)
 
417
    elif repository is not None:
381
418
        stats = repository.gather_stats()
382
 
    if branch is None and working is None:
 
419
    if branch is None and working is None and repository is not None:
383
420
        _show_repository_info(repository, outfile)
384
 
    _show_repository_stats(stats, outfile)
385
 
 
386
 
 
387
 
def describe_layout(repository=None, branch=None, tree=None):
 
421
    if repository is not None:
 
422
        _show_repository_stats(repository, stats, outfile)
 
423
 
 
424
 
 
425
def describe_layout(repository=None, branch=None, tree=None, control=None):
388
426
    """Convert a control directory layout into a user-understandable term
389
427
 
390
428
    Common outputs include "Standalone tree", "Repository branch" and
391
429
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
392
430
    and "Empty control directory"
393
431
    """
 
432
    if branch is None and control is not None:
 
433
        try:
 
434
            branch_reference = control.get_branch_reference()
 
435
        except NotBranchError:
 
436
            pass
 
437
        else:
 
438
            if branch_reference is not None:
 
439
                return "Dangling branch reference"
394
440
    if repository is None:
395
441
        return 'Empty control directory'
396
442
    if branch is None and tree is None:
398
444
            phrase = 'Shared repository'
399
445
        else:
400
446
            phrase = 'Unshared repository'
 
447
        extra = []
401
448
        if repository.make_working_trees():
402
 
            phrase += ' with trees'
 
449
            extra.append('trees')
 
450
        if len(control.get_branches()) > 0:
 
451
            extra.append('colocated branches')
 
452
        if extra:
 
453
            phrase += ' with ' + " and ".join(extra)
403
454
        return phrase
404
455
    else:
405
456
        if repository.is_shared():
413
464
        if branch is None and tree is not None:
414
465
            phrase = "branchless tree"
415
466
        else:
416
 
            if (tree is not None and tree.bzrdir.root_transport.base !=
417
 
                branch.bzrdir.root_transport.base):
 
467
            if (tree is not None and tree.user_url !=
 
468
                branch.user_url):
418
469
                independence = ''
419
470
                phrase = "Lightweight checkout"
420
471
            elif branch.get_bound_location() is not None:
439
490
    """
440
491
    candidates  = []
441
492
    if (branch is not None and tree is not None and
442
 
        branch.bzrdir.root_transport.base !=
443
 
        tree.bzrdir.root_transport.base):
 
493
        branch.user_url != tree.user_url):
444
494
        branch = None
445
495
        repository = None
446
 
    non_aliases = set(bzrdir.format_registry.keys())
447
 
    non_aliases.difference_update(bzrdir.format_registry.aliases())
 
496
    non_aliases = set(controldir.format_registry.keys())
 
497
    non_aliases.difference_update(controldir.format_registry.aliases())
448
498
    for key in non_aliases:
449
 
        format = bzrdir.format_registry.make_bzrdir(key)
 
499
        format = controldir.format_registry.make_bzrdir(key)
450
500
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
451
501
            if (tree and format.workingtree_format !=
452
502
                tree._format):
464
514
        return 'unnamed'
465
515
    candidates.sort()
466
516
    new_candidates = [c for c in candidates if not
467
 
        bzrdir.format_registry.get_info(c).hidden]
 
517
        controldir.format_registry.get_info(c).hidden]
468
518
    if len(new_candidates) > 0:
469
519
        # If there are any non-hidden formats that match, only return those to
470
520
        # avoid listing hidden formats except when only a hidden format will
471
521
        # do.
472
522
        candidates = new_candidates
473
523
    return ' or '.join(candidates)
 
524
 
 
525
 
 
526
class InfoHooks(_mod_hooks.Hooks):
 
527
    """Hooks for the info command."""
 
528
 
 
529
    def __init__(self):
 
530
        super(InfoHooks, self).__init__("bzrlib.info", "hooks")
 
531
        self.add_hook('repository',
 
532
            "Invoked when displaying the statistics for a repository. "
 
533
            "repository is called with a statistics dictionary as returned "
 
534
            "by the repository and a file-like object to write to.", (1, 15))
 
535
 
 
536
 
 
537
hooks = InfoHooks()