/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/info.py

  • Committer: Jelmer Vernooij
  • Date: 2019-02-04 01:01:24 UTC
  • mto: This revision was merged to the branch mainline in revision 7268.
  • Revision ID: jelmer@jelmer.uk-20190204010124-ni0i4qc6f5tnbvux
Fix source tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
__all__ = ['show_bzrdir_info']
18
20
 
19
 
from cStringIO import StringIO
 
21
from io import StringIO
20
22
import time
21
23
import sys
22
24
 
23
 
from bzrlib import (
24
 
    bzrdir,
 
25
from . import (
 
26
    branch as _mod_branch,
 
27
    controldir,
25
28
    errors,
26
29
    hooks as _mod_hooks,
27
30
    osutils,
28
31
    urlutils,
29
32
    )
30
 
from bzrlib.errors import (NoWorkingTree, NotBranchError,
31
 
                           NoRepositoryPresent, NotLocalUrl)
32
 
from bzrlib.missing import find_unmerged
33
 
 
34
 
 
35
 
def plural(n, base='', pl=None):
 
33
from .bzr import (
 
34
    bzrdir,
 
35
    )
 
36
from .errors import (NoWorkingTree, NotBranchError,
 
37
                     NoRepositoryPresent, NotLocalUrl)
 
38
from .missing import find_unmerged
 
39
 
 
40
 
 
41
def plural(n, base=u'', pl=None):
36
42
    if n == 1:
37
43
        return base
38
44
    elif pl is not None:
39
45
        return pl
40
46
    else:
41
 
        return 's'
 
47
        return u's'
42
48
 
43
49
 
44
50
class LocationList(object):
53
59
            return
54
60
        try:
55
61
            path = urlutils.local_path_from_url(url)
56
 
        except errors.InvalidURL:
 
62
        except urlutils.InvalidURL:
57
63
            self.locs.append((label, url))
58
64
        else:
59
65
            self.add_path(label, path)
73
79
 
74
80
    def get_lines(self):
75
81
        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 ]
77
 
 
78
 
 
79
 
def gather_location_info(repository, branch=None, working=None):
 
82
        return ["  %*s: %s\n" % (max_len, l, u) for l, u in self.locs]
 
83
 
 
84
 
 
85
def gather_location_info(repository=None, branch=None, working=None,
 
86
                         control=None):
80
87
    locs = {}
81
 
    repository_path = repository.user_url
82
88
    if branch is not None:
83
89
        branch_path = branch.user_url
84
90
        master_path = branch.get_bound_location()
87
93
    else:
88
94
        branch_path = None
89
95
        master_path = None
 
96
        try:
 
97
            if control is not None and control.get_branch_reference():
 
98
                locs['checkout of branch'] = control.get_branch_reference()
 
99
        except NotBranchError:
 
100
            pass
90
101
    if working:
91
102
        working_path = working.user_url
92
103
        if working_path != branch_path:
97
108
            else:
98
109
                locs['checkout root'] = branch_path
99
110
        if working_path != master_path:
100
 
            locs['checkout of branch'] = master_path
 
111
            (master_path_base, params) = urlutils.split_segment_parameters(
 
112
                master_path)
 
113
            if working_path == master_path_base:
 
114
                locs['checkout of co-located branch'] = params['branch']
 
115
            elif 'branch' in params:
 
116
                locs['checkout of branch'] = "%s, branch %s" (
 
117
                    master_path_base, params['branch'])
 
118
            else:
 
119
                locs['checkout of branch'] = master_path
101
120
        elif repository.is_shared():
102
121
            locs['repository branch'] = branch_path
103
122
        elif branch_path is not None:
105
124
            locs['branch root'] = branch_path
106
125
    else:
107
126
        working_path = None
108
 
        if repository.is_shared():
 
127
        if repository is not None and repository.is_shared():
109
128
            # lightweight checkout of branch in shared repository
110
129
            if branch_path is not None:
111
130
                locs['repository branch'] = branch_path
112
131
        elif branch_path is not None:
113
132
            # standalone
114
133
            locs['branch root'] = branch_path
115
 
            if master_path != branch_path:
116
 
                locs['bound to branch'] = master_path
 
134
        elif repository is not None:
 
135
            locs['repository'] = repository.user_url
 
136
        elif control is not None:
 
137
            locs['control directory'] = control.user_url
117
138
        else:
118
 
            locs['repository'] = repository_path
119
 
    if repository.is_shared():
 
139
            # Really, at least a control directory should be
 
140
            # passed in for this method to be useful.
 
141
            pass
 
142
        if master_path != branch_path:
 
143
            locs['bound to branch'] = master_path
 
144
    if repository is not None and repository.is_shared():
120
145
        # 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',
124
 
             'repository', 'repository branch', 'branch root',
125
 
             'bound to branch']
 
146
        locs['shared repository'] = repository.user_url
 
147
    order = ['control directory', 'light checkout root',
 
148
             'repository checkout root', 'checkout root',
 
149
             'checkout of branch', 'checkout of co-located branch',
 
150
             'shared repository', 'repository', 'repository branch',
 
151
             'branch root', 'bound to branch']
126
152
    return [(n, locs[n]) for n in order if n in locs]
127
153
 
128
154
 
143
169
    locs.add_url('submit branch', branch.get_submit_branch())
144
170
    try:
145
171
        locs.add_url('stacked on', branch.get_stacked_on_url())
146
 
    except (errors.UnstackableBranchFormat, errors.UnstackableRepositoryFormat,
147
 
        errors.NotStacked):
 
172
    except (_mod_branch.UnstackableBranchFormat, errors.UnstackableRepositoryFormat,
 
173
            errors.NotStacked):
148
174
        pass
149
175
    return locs
150
176
 
158
184
        outfile.writelines(locs.get_lines())
159
185
 
160
186
 
 
187
def _show_control_dir_info(control, outfile):
 
188
    """Show control dir information."""
 
189
    if control._format.colocated_branches:
 
190
        outfile.write('\n')
 
191
        outfile.write('Control directory:\n')
 
192
        outfile.write('         %d branches\n' % len(control.list_branches()))
 
193
 
 
194
 
161
195
def _show_format_info(control=None, repository=None, branch=None,
162
196
                      working=None, outfile=None):
163
197
    """Show known formats for control, working, branch and repository."""
165
199
    outfile.write('Format:\n')
166
200
    if control:
167
201
        outfile.write('       control: %s\n' %
168
 
            control._format.get_format_description())
 
202
                      control._format.get_format_description())
169
203
    if working:
170
204
        outfile.write('  working tree: %s\n' %
171
 
            working._format.get_format_description())
 
205
                      working._format.get_format_description())
172
206
    if branch:
173
207
        outfile.write('        branch: %s\n' %
174
 
            branch._format.get_format_description())
 
208
                      branch._format.get_format_description())
175
209
    if repository:
176
210
        outfile.write('    repository: %s\n' %
177
 
            repository._format.get_format_description())
178
 
 
179
 
 
180
 
def _show_locking_info(repository, branch=None, working=None, outfile=None):
 
211
                      repository._format.get_format_description())
 
212
 
 
213
 
 
214
def _show_locking_info(repository=None, branch=None, working=None,
 
215
                       outfile=None):
181
216
    """Show locking status of working, branch and repository."""
182
 
    if (repository.get_physical_lock_status() or
 
217
    if (repository and repository.get_physical_lock_status() or
183
218
        (branch and branch.get_physical_lock_status()) or
184
 
        (working and working.get_physical_lock_status())):
 
219
            (working and working.get_physical_lock_status())):
185
220
        outfile.write('\n')
186
221
        outfile.write('Lock status:\n')
187
222
        if working:
213
248
        if remote_extra:
214
249
            outfile.write('\n')
215
250
            outfile.write(('Branch is out of date: missing %d '
216
 
                'revision%s.\n') % (len(remote_extra),
217
 
                plural(len(remote_extra))))
 
251
                           'revision%s.\n') % (len(remote_extra),
 
252
                                               plural(len(remote_extra))))
218
253
 
219
254
 
220
255
def _show_missing_revisions_working(working, outfile):
221
256
    """Show missing revisions in working tree."""
222
257
    branch = working.branch
223
 
    basis = working.basis_tree()
224
 
    work_inv = working.inventory
225
 
    branch_revno, branch_last_revision = branch.last_revision_info()
 
258
    try:
 
259
        branch_revno, branch_last_revision = branch.last_revision_info()
 
260
    except errors.UnsupportedOperation:
 
261
        return
226
262
    try:
227
263
        tree_last_id = working.get_parent_ids()[0]
228
264
    except IndexError:
233
269
        missing_count = branch_revno - tree_last_revno
234
270
        outfile.write('\n')
235
271
        outfile.write(('Working tree is out of date: missing %d '
236
 
            'revision%s.\n') % (missing_count, plural(missing_count)))
 
272
                       'revision%s.\n') % (missing_count, plural(missing_count)))
237
273
 
238
274
 
239
275
def _show_working_stats(working, outfile):
240
276
    """Show statistics about a working tree."""
241
277
    basis = working.basis_tree()
242
 
    work_inv = working.inventory
243
278
    delta = working.changes_from(basis, want_unchanged=True)
244
279
 
245
280
    outfile.write('\n')
260
295
    outfile.write('  %8d ignored\n' % ignore_cnt)
261
296
 
262
297
    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)):
 
298
    for path, entry in working.iter_entries_by_dir():
 
299
        if entry.kind == 'directory' and path != '':
266
300
            dir_cnt += 1
267
301
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
268
 
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
 
302
                                            plural(dir_cnt, 'subdirectory', 'subdirectories')))
269
303
 
270
304
 
271
305
def _show_branch_stats(branch, verbose, outfile):
272
306
    """Show statistics about a branch."""
273
 
    revno, head = branch.last_revision_info()
 
307
    try:
 
308
        revno, head = branch.last_revision_info()
 
309
    except errors.UnsupportedOperation:
 
310
        return {}
274
311
    outfile.write('\n')
275
312
    outfile.write('Branch history:\n')
276
313
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
278
315
    if verbose:
279
316
        committers = stats['committers']
280
317
        outfile.write('  %8d committer%s\n' % (committers,
281
 
            plural(committers)))
 
318
                                               plural(committers)))
282
319
    if revno:
283
320
        timestamp, timezone = stats['firstrev']
284
321
        age = int((time.time() - timestamp) / 3600 / 24)
285
322
        outfile.write('  %8d day%s old\n' % (age, plural(age)))
286
323
        outfile.write('   first revision: %s\n' %
287
 
            osutils.format_date(timestamp, timezone))
 
324
                      osutils.format_date(timestamp, timezone))
288
325
        timestamp, timezone = stats['latestrev']
289
326
        outfile.write('  latest revision: %s\n' %
290
 
            osutils.format_date(timestamp, timezone))
 
327
                      osutils.format_date(timestamp, timezone))
291
328
    return stats
292
329
 
293
330
 
296
333
    if repository.make_working_trees():
297
334
        outfile.write('\n')
298
335
        outfile.write('Create working tree for new branches inside '
299
 
            'the repository.\n')
 
336
                      'the repository.\n')
300
337
 
301
338
 
302
339
def _show_repository_stats(repository, stats, outfile):
306
343
        revisions = stats['revisions']
307
344
        f.write('  %8d revision%s\n' % (revisions, plural(revisions)))
308
345
    if 'size' in stats:
309
 
        f.write('  %8d KiB\n' % (stats['size']/1024))
 
346
        f.write('  %8d KiB\n' % (stats['size'] / 1024))
310
347
    for hook in hooks['repository']:
311
348
        hook(repository, stats, f)
312
349
    if f.getvalue() != "":
315
352
        outfile.write(f.getvalue())
316
353
 
317
354
 
318
 
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
319
 
    """Output to stdout the 'info' for a_bzrdir."""
 
355
def show_bzrdir_info(a_controldir, verbose=False, outfile=None):
 
356
    """Output to stdout the 'info' for a_controldir."""
320
357
    if outfile is None:
321
358
        outfile = sys.stdout
322
359
    try:
323
 
        tree = a_bzrdir.open_workingtree(
 
360
        tree = a_controldir.open_workingtree(
324
361
            recommend_upgrade=False)
325
 
    except (NoWorkingTree, NotLocalUrl):
 
362
    except (NoWorkingTree, NotLocalUrl, NotBranchError):
326
363
        tree = None
327
364
        try:
328
 
            branch = a_bzrdir.open_branch()
 
365
            branch = a_controldir.open_branch(name="")
329
366
        except NotBranchError:
330
367
            branch = None
331
368
            try:
332
 
                repository = a_bzrdir.open_repository()
 
369
                repository = a_controldir.open_repository()
333
370
            except NoRepositoryPresent:
334
 
                # Return silently; cmd_info already returned NotBranchError
335
 
                # if no bzrdir could be opened.
336
 
                return
 
371
                lockable = None
 
372
                repository = None
337
373
            else:
338
374
                lockable = repository
339
375
        else:
344
380
        repository = branch.repository
345
381
        lockable = tree
346
382
 
347
 
    lockable.lock_read()
 
383
    if lockable is not None:
 
384
        lockable.lock_read()
348
385
    try:
349
 
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
 
386
        show_component_info(a_controldir, repository, branch, tree, verbose,
350
387
                            outfile)
351
388
    finally:
352
 
        lockable.unlock()
 
389
        if lockable is not None:
 
390
            lockable.unlock()
353
391
 
354
392
 
355
393
def show_component_info(control, repository, branch=None, working=None,
356
 
    verbose=1, outfile=None):
 
394
                        verbose=1, outfile=None):
357
395
    """Write info about all bzrdir components to stdout"""
358
396
    if outfile is None:
359
397
        outfile = sys.stdout
361
399
        verbose = 1
362
400
    if verbose is True:
363
401
        verbose = 2
364
 
    layout = describe_layout(repository, branch, working)
 
402
    layout = describe_layout(repository, branch, working, control)
365
403
    format = describe_format(control, repository, branch, working)
366
404
    outfile.write("%s (format: %s)\n" % (layout, format))
367
 
    _show_location_info(gather_location_info(repository, branch, working),
368
 
                        outfile)
 
405
    _show_location_info(
 
406
        gather_location_info(control=control, repository=repository,
 
407
                             branch=branch, working=working),
 
408
        outfile)
369
409
    if branch is not None:
370
410
        _show_related_info(branch, outfile)
371
411
    if verbose == 0:
372
412
        return
373
413
    _show_format_info(control, repository, branch, working, outfile)
374
414
    _show_locking_info(repository, branch, working, outfile)
 
415
    _show_control_dir_info(control, outfile)
375
416
    if branch is not None:
376
417
        _show_missing_revisions_branch(branch, outfile)
377
418
    if working is not None:
382
423
    if branch is not None:
383
424
        show_committers = verbose >= 2
384
425
        stats = _show_branch_stats(branch, show_committers, outfile)
385
 
    else:
 
426
    elif repository is not None:
386
427
        stats = repository.gather_stats()
387
 
    if branch is None and working is None:
 
428
    if branch is None and working is None and repository is not None:
388
429
        _show_repository_info(repository, outfile)
389
 
    _show_repository_stats(repository, stats, outfile)
390
 
 
391
 
 
392
 
def describe_layout(repository=None, branch=None, tree=None):
 
430
    if repository is not None:
 
431
        _show_repository_stats(repository, stats, outfile)
 
432
 
 
433
 
 
434
def describe_layout(repository=None, branch=None, tree=None, control=None):
393
435
    """Convert a control directory layout into a user-understandable term
394
436
 
395
437
    Common outputs include "Standalone tree", "Repository branch" and
396
438
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
397
439
    and "Empty control directory"
398
440
    """
 
441
    if branch is None and control is not None:
 
442
        try:
 
443
            branch_reference = control.get_branch_reference()
 
444
        except NotBranchError:
 
445
            pass
 
446
        else:
 
447
            if branch_reference is not None:
 
448
                return "Dangling branch reference"
399
449
    if repository is None:
400
450
        return 'Empty control directory'
401
451
    if branch is None and tree is None:
403
453
            phrase = 'Shared repository'
404
454
        else:
405
455
            phrase = 'Unshared repository'
 
456
        extra = []
406
457
        if repository.make_working_trees():
407
 
            phrase += ' with trees'
 
458
            extra.append('trees')
 
459
        if len(control.get_branches()) > 0:
 
460
            extra.append('colocated branches')
 
461
        if extra:
 
462
            phrase += ' with ' + " and ".join(extra)
408
463
        return phrase
409
464
    else:
410
465
        if repository.is_shared():
418
473
        if branch is None and tree is not None:
419
474
            phrase = "branchless tree"
420
475
        else:
421
 
            if (tree is not None and tree.user_url !=
422
 
                branch.user_url):
 
476
            if (tree is not None and tree.controldir.control_url !=
 
477
                    branch.controldir.control_url):
423
478
                independence = ''
424
479
                phrase = "Lightweight checkout"
425
480
            elif branch.get_bound_location() is not None:
442
497
 
443
498
    If no matching candidate is found, "unnamed" is returned.
444
499
    """
445
 
    candidates  = []
 
500
    candidates = []
446
501
    if (branch is not None and tree is not None and
447
 
        branch.user_url != tree.user_url):
 
502
            branch.user_url != tree.user_url):
448
503
        branch = None
449
504
        repository = None
450
 
    non_aliases = set(bzrdir.format_registry.keys())
451
 
    non_aliases.difference_update(bzrdir.format_registry.aliases())
 
505
    non_aliases = set(controldir.format_registry.keys())
 
506
    non_aliases.difference_update(controldir.format_registry.aliases())
452
507
    for key in non_aliases:
453
 
        format = bzrdir.format_registry.make_bzrdir(key)
 
508
        format = controldir.format_registry.make_controldir(key)
454
509
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
455
510
            if (tree and format.workingtree_format !=
456
 
                tree._format):
 
511
                    tree._format):
457
512
                continue
458
513
            if (branch and format.get_branch_format() !=
459
 
                branch._format):
 
514
                    branch._format):
460
515
                continue
461
516
            if (repository and format.repository_format !=
462
 
                repository._format):
 
517
                    repository._format):
463
518
                continue
464
519
        if format.__class__ is not control._format.__class__:
465
520
            continue
468
523
        return 'unnamed'
469
524
    candidates.sort()
470
525
    new_candidates = [c for c in candidates if not
471
 
        bzrdir.format_registry.get_info(c).hidden]
 
526
                      controldir.format_registry.get_info(c).hidden]
472
527
    if len(new_candidates) > 0:
473
528
        # If there are any non-hidden formats that match, only return those to
474
529
        # avoid listing hidden formats except when only a hidden format will
481
536
    """Hooks for the info command."""
482
537
 
483
538
    def __init__(self):
484
 
        super(InfoHooks, self).__init__()
485
 
        self.create_hook(_mod_hooks.HookPoint('repository',
 
539
        super(InfoHooks, self).__init__("breezy.info", "hooks")
 
540
        self.add_hook(
 
541
            'repository',
486
542
            "Invoked when displaying the statistics for a repository. "
487
543
            "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))
 
544
            "by the repository and a file-like object to write to.", (1, 15))
490
545
 
491
546
 
492
547
hooks = InfoHooks()