/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: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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')
249
284
    outfile.write('  %8d added\n' % len(delta.added))
250
285
    outfile.write('  %8d removed\n' % len(delta.removed))
251
286
    outfile.write('  %8d renamed\n' % len(delta.renamed))
 
287
    outfile.write('  %8d copied\n' % len(delta.copied))
252
288
 
253
289
    ignore_cnt = unknown_cnt = 0
254
290
    for path in working.extras():
260
296
    outfile.write('  %8d ignored\n' % ignore_cnt)
261
297
 
262
298
    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)):
 
299
    for path, entry in working.iter_entries_by_dir():
 
300
        if entry.kind == 'directory' and path != '':
266
301
            dir_cnt += 1
267
302
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
268
 
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
 
303
                                            plural(dir_cnt, 'subdirectory', 'subdirectories')))
269
304
 
270
305
 
271
306
def _show_branch_stats(branch, verbose, outfile):
272
307
    """Show statistics about a branch."""
273
 
    revno, head = branch.last_revision_info()
 
308
    try:
 
309
        revno, head = branch.last_revision_info()
 
310
    except errors.UnsupportedOperation:
 
311
        return {}
274
312
    outfile.write('\n')
275
313
    outfile.write('Branch history:\n')
276
314
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
278
316
    if verbose:
279
317
        committers = stats['committers']
280
318
        outfile.write('  %8d committer%s\n' % (committers,
281
 
            plural(committers)))
 
319
                                               plural(committers)))
282
320
    if revno:
283
321
        timestamp, timezone = stats['firstrev']
284
322
        age = int((time.time() - timestamp) / 3600 / 24)
285
323
        outfile.write('  %8d day%s old\n' % (age, plural(age)))
286
324
        outfile.write('   first revision: %s\n' %
287
 
            osutils.format_date(timestamp, timezone))
 
325
                      osutils.format_date(timestamp, timezone))
288
326
        timestamp, timezone = stats['latestrev']
289
327
        outfile.write('  latest revision: %s\n' %
290
 
            osutils.format_date(timestamp, timezone))
 
328
                      osutils.format_date(timestamp, timezone))
291
329
    return stats
292
330
 
293
331
 
296
334
    if repository.make_working_trees():
297
335
        outfile.write('\n')
298
336
        outfile.write('Create working tree for new branches inside '
299
 
            'the repository.\n')
 
337
                      'the repository.\n')
300
338
 
301
339
 
302
340
def _show_repository_stats(repository, stats, outfile):
306
344
        revisions = stats['revisions']
307
345
        f.write('  %8d revision%s\n' % (revisions, plural(revisions)))
308
346
    if 'size' in stats:
309
 
        f.write('  %8d KiB\n' % (stats['size']/1024))
 
347
        f.write('  %8d KiB\n' % (stats['size'] / 1024))
310
348
    for hook in hooks['repository']:
311
349
        hook(repository, stats, f)
312
350
    if f.getvalue() != "":
315
353
        outfile.write(f.getvalue())
316
354
 
317
355
 
318
 
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
319
 
    """Output to stdout the 'info' for a_bzrdir."""
 
356
def show_bzrdir_info(a_controldir, verbose=False, outfile=None):
 
357
    """Output to stdout the 'info' for a_controldir."""
320
358
    if outfile is None:
321
359
        outfile = sys.stdout
322
360
    try:
323
 
        tree = a_bzrdir.open_workingtree(
 
361
        tree = a_controldir.open_workingtree(
324
362
            recommend_upgrade=False)
325
 
    except (NoWorkingTree, NotLocalUrl):
 
363
    except (NoWorkingTree, NotLocalUrl, NotBranchError):
326
364
        tree = None
327
365
        try:
328
 
            branch = a_bzrdir.open_branch()
 
366
            branch = a_controldir.open_branch(name="")
329
367
        except NotBranchError:
330
368
            branch = None
331
369
            try:
332
 
                repository = a_bzrdir.open_repository()
 
370
                repository = a_controldir.open_repository()
333
371
            except NoRepositoryPresent:
334
 
                # Return silently; cmd_info already returned NotBranchError
335
 
                # if no bzrdir could be opened.
336
 
                return
 
372
                lockable = None
 
373
                repository = None
337
374
            else:
338
375
                lockable = repository
339
376
        else:
344
381
        repository = branch.repository
345
382
        lockable = tree
346
383
 
347
 
    lockable.lock_read()
 
384
    if lockable is not None:
 
385
        lockable.lock_read()
348
386
    try:
349
 
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
 
387
        show_component_info(a_controldir, repository, branch, tree, verbose,
350
388
                            outfile)
351
389
    finally:
352
 
        lockable.unlock()
 
390
        if lockable is not None:
 
391
            lockable.unlock()
353
392
 
354
393
 
355
394
def show_component_info(control, repository, branch=None, working=None,
356
 
    verbose=1, outfile=None):
 
395
                        verbose=1, outfile=None):
357
396
    """Write info about all bzrdir components to stdout"""
358
397
    if outfile is None:
359
398
        outfile = sys.stdout
361
400
        verbose = 1
362
401
    if verbose is True:
363
402
        verbose = 2
364
 
    layout = describe_layout(repository, branch, working)
 
403
    layout = describe_layout(repository, branch, working, control)
365
404
    format = describe_format(control, repository, branch, working)
366
405
    outfile.write("%s (format: %s)\n" % (layout, format))
367
 
    _show_location_info(gather_location_info(repository, branch, working),
368
 
                        outfile)
 
406
    _show_location_info(
 
407
        gather_location_info(control=control, repository=repository,
 
408
                             branch=branch, working=working),
 
409
        outfile)
369
410
    if branch is not None:
370
411
        _show_related_info(branch, outfile)
371
412
    if verbose == 0:
372
413
        return
373
414
    _show_format_info(control, repository, branch, working, outfile)
374
415
    _show_locking_info(repository, branch, working, outfile)
 
416
    _show_control_dir_info(control, outfile)
375
417
    if branch is not None:
376
418
        _show_missing_revisions_branch(branch, outfile)
377
419
    if working is not None:
382
424
    if branch is not None:
383
425
        show_committers = verbose >= 2
384
426
        stats = _show_branch_stats(branch, show_committers, outfile)
385
 
    else:
 
427
    elif repository is not None:
386
428
        stats = repository.gather_stats()
387
 
    if branch is None and working is None:
 
429
    if branch is None and working is None and repository is not None:
388
430
        _show_repository_info(repository, outfile)
389
 
    _show_repository_stats(repository, stats, outfile)
390
 
 
391
 
 
392
 
def describe_layout(repository=None, branch=None, tree=None):
 
431
    if repository is not None:
 
432
        _show_repository_stats(repository, stats, outfile)
 
433
 
 
434
 
 
435
def describe_layout(repository=None, branch=None, tree=None, control=None):
393
436
    """Convert a control directory layout into a user-understandable term
394
437
 
395
438
    Common outputs include "Standalone tree", "Repository branch" and
396
439
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
397
440
    and "Empty control directory"
398
441
    """
 
442
    if branch is None and control is not None:
 
443
        try:
 
444
            branch_reference = control.get_branch_reference()
 
445
        except NotBranchError:
 
446
            pass
 
447
        else:
 
448
            if branch_reference is not None:
 
449
                return "Dangling branch reference"
399
450
    if repository is None:
400
451
        return 'Empty control directory'
401
452
    if branch is None and tree is None:
403
454
            phrase = 'Shared repository'
404
455
        else:
405
456
            phrase = 'Unshared repository'
 
457
        extra = []
406
458
        if repository.make_working_trees():
407
 
            phrase += ' with trees'
 
459
            extra.append('trees')
 
460
        if len(control.branch_names()) > 0:
 
461
            extra.append('colocated branches')
 
462
        if extra:
 
463
            phrase += ' with ' + " and ".join(extra)
408
464
        return phrase
409
465
    else:
410
466
        if repository.is_shared():
418
474
        if branch is None and tree is not None:
419
475
            phrase = "branchless tree"
420
476
        else:
421
 
            if (tree is not None and tree.user_url !=
422
 
                branch.user_url):
 
477
            if (tree is not None and tree.controldir.control_url !=
 
478
                    branch.controldir.control_url):
423
479
                independence = ''
424
480
                phrase = "Lightweight checkout"
425
481
            elif branch.get_bound_location() is not None:
442
498
 
443
499
    If no matching candidate is found, "unnamed" is returned.
444
500
    """
445
 
    candidates  = []
 
501
    candidates = []
446
502
    if (branch is not None and tree is not None and
447
 
        branch.user_url != tree.user_url):
 
503
            branch.user_url != tree.user_url):
448
504
        branch = None
449
505
        repository = None
450
 
    non_aliases = set(bzrdir.format_registry.keys())
451
 
    non_aliases.difference_update(bzrdir.format_registry.aliases())
 
506
    non_aliases = set(controldir.format_registry.keys())
 
507
    non_aliases.difference_update(controldir.format_registry.aliases())
452
508
    for key in non_aliases:
453
 
        format = bzrdir.format_registry.make_bzrdir(key)
 
509
        format = controldir.format_registry.make_controldir(key)
454
510
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
455
511
            if (tree and format.workingtree_format !=
456
 
                tree._format):
 
512
                    tree._format):
457
513
                continue
458
514
            if (branch and format.get_branch_format() !=
459
 
                branch._format):
 
515
                    branch._format):
460
516
                continue
461
517
            if (repository and format.repository_format !=
462
 
                repository._format):
 
518
                    repository._format):
463
519
                continue
464
520
        if format.__class__ is not control._format.__class__:
465
521
            continue
468
524
        return 'unnamed'
469
525
    candidates.sort()
470
526
    new_candidates = [c for c in candidates if not
471
 
        bzrdir.format_registry.get_info(c).hidden]
 
527
                      controldir.format_registry.get_info(c).hidden]
472
528
    if len(new_candidates) > 0:
473
529
        # If there are any non-hidden formats that match, only return those to
474
530
        # avoid listing hidden formats except when only a hidden format will
481
537
    """Hooks for the info command."""
482
538
 
483
539
    def __init__(self):
484
 
        super(InfoHooks, self).__init__()
485
 
        self.create_hook(_mod_hooks.HookPoint('repository',
 
540
        super(InfoHooks, self).__init__("breezy.info", "hooks")
 
541
        self.add_hook(
 
542
            'repository',
486
543
            "Invoked when displaying the statistics for a repository. "
487
544
            "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))
 
545
            "by the repository and a file-like object to write to.", (1, 15))
490
546
 
491
547
 
492
548
hooks = InfoHooks()