/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 bzrlib/info.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-10-17 05:59:11 UTC
  • mfrom: (2903.2.11 commit)
  • Revision ID: pqm@pqm.ubuntu.com-20071017055911-jots6fwy20740n0i
commit produces (but does not yet use) a basis delta and avoids one iter_entries (mbp)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 by Martin Pool
2
 
# Copyright (C) 2005 by Canonical Ltd
3
 
 
4
 
 
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
5
3
# This program is free software; you can redistribute it and/or modify
6
4
# it under the terms of the GNU General Public License as published by
7
5
# the Free Software Foundation; either version 2 of the License, or
8
6
# (at your option) any later version.
9
 
 
 
7
#
10
8
# This program is distributed in the hope that it will be useful,
11
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
11
# GNU General Public License for more details.
14
 
 
 
12
#
15
13
# You should have received a copy of the GNU General Public License
16
14
# along with this program; if not, write to the Free Software
17
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
16
 
19
17
__all__ = ['show_bzrdir_info']
20
18
 
 
19
import os
21
20
import time
22
 
 
23
 
 
24
 
import bzrlib.diff as diff
 
21
import sys
 
22
 
 
23
from bzrlib import (
 
24
    bzrdir,
 
25
    diff,
 
26
    errors,
 
27
    osutils,
 
28
    urlutils,
 
29
    )
25
30
from bzrlib.errors import (NoWorkingTree, NotBranchError,
26
31
                           NoRepositoryPresent, NotLocalUrl)
27
32
from bzrlib.missing import find_unmerged
28
 
from bzrlib.osutils import format_date
29
 
from bzrlib.symbol_versioning import *
30
 
 
31
 
 
32
 
def _countiter(it):
33
 
    # surely there's a builtin for this?
34
 
    i = 0
35
 
    for j in it:
36
 
        i += 1
37
 
    return i        
 
33
from bzrlib.symbol_versioning import (deprecated_function,
 
34
        zero_eighteen)
38
35
 
39
36
 
40
37
def plural(n, base='', pl=None):
41
38
    if n == 1:
42
39
        return base
43
 
    elif pl != None:
 
40
    elif pl is not None:
44
41
        return pl
45
42
    else:
46
43
        return 's'
47
44
 
48
45
 
49
 
def _show_location_info(repository=None, branch=None, working=None):
 
46
class LocationList(object):
 
47
 
 
48
    def __init__(self, base_path):
 
49
        self.locs = []
 
50
        self.base_path = base_path
 
51
 
 
52
    def add_url(self, label, url):
 
53
        """Add a URL to the list, converting it to a path if possible"""
 
54
        if url is None:
 
55
            return
 
56
        try:
 
57
            path = urlutils.local_path_from_url(url)
 
58
        except errors.InvalidURL:
 
59
            self.locs.append((label, url))
 
60
        else:
 
61
            self.add_path(label, path)
 
62
 
 
63
    def add_path(self, label, path):
 
64
        """Add a path, converting it to a relative path if possible"""
 
65
        try:
 
66
            path = osutils.relpath(self.base_path, path)
 
67
        except errors.PathNotChild:
 
68
            pass
 
69
        else:
 
70
            if path == '':
 
71
                path = '.'
 
72
        if path != '/':
 
73
            path = path.rstrip('/')
 
74
        self.locs.append((label, path))
 
75
 
 
76
    def get_lines(self):
 
77
        max_len = max(len(l) for l, u in self.locs)
 
78
        return ["  %*s: %s\n" % (max_len, l, u) for l, u in self.locs ]
 
79
 
 
80
 
 
81
def gather_location_info(repository, branch=None, working=None):
 
82
    locs = {}
 
83
    repository_path = repository.bzrdir.root_transport.base
 
84
    if branch is not None:
 
85
        branch_path = branch.bzrdir.root_transport.base
 
86
        master_path = branch.get_bound_location()
 
87
        if master_path is None:
 
88
            master_path = branch_path
 
89
    else:
 
90
        branch_path = None
 
91
        master_path = None
 
92
    if working:
 
93
        working_path = working.bzrdir.root_transport.base
 
94
        if working_path != branch_path:
 
95
            locs['light checkout root'] = working_path
 
96
        if master_path != branch_path:
 
97
            if repository.is_shared():
 
98
                locs['repository checkout root'] = branch_path
 
99
            else:
 
100
                locs['checkout root'] = branch_path
 
101
        if working_path != master_path:
 
102
            locs['checkout of branch'] = master_path
 
103
        elif repository.is_shared():
 
104
            locs['repository branch'] = branch_path
 
105
        elif branch_path is not None:
 
106
            # standalone
 
107
            locs['branch root'] = branch_path
 
108
    else:
 
109
        working_path = None
 
110
        if repository.is_shared():
 
111
            # lightweight checkout of branch in shared repository
 
112
            if branch_path is not None:
 
113
                locs['repository branch'] = branch_path
 
114
        elif branch_path is not None:
 
115
            # standalone
 
116
            locs['branch root'] = branch_path
 
117
            if master_path != branch_path:
 
118
                locs['bound to branch'] = master_path
 
119
        else:
 
120
            locs['repository'] = repository_path
 
121
    if repository.is_shared():
 
122
        # lightweight checkout of branch in shared repository
 
123
        locs['shared repository'] = repository_path
 
124
    order = ['light checkout root', 'repository checkout root',
 
125
             'checkout root', 'checkout of branch', 'shared repository',
 
126
             'repository', 'repository branch', 'branch root',
 
127
             'bound to branch']
 
128
    return [(n, locs[n]) for n in order if n in locs]
 
129
 
 
130
 
 
131
def _show_location_info(locs):
50
132
    """Show known locations for working, branch and repository."""
51
133
    print 'Location:'
52
 
    if working and branch and working.bzrdir != branch.bzrdir:
53
 
        # Lightweight checkout
54
 
        print '       checkout root: %s' % (
55
 
            working.bzrdir.root_transport.base)
56
 
        print '  checkout of branch: %s' % (
57
 
            branch.bzrdir.root_transport.base)
58
 
    elif branch:
59
 
        # Standalone or bound branch (normal checkout)
60
 
        print '         branch root: %s' % (
61
 
            branch.bzrdir.root_transport.base)
62
 
        if branch.get_bound_location():
63
 
            print '     bound to branch: %s' % branch.get_bound_location()
64
 
 
65
 
    if repository and (not branch or repository.bzrdir != branch.bzrdir):
66
 
        if repository.is_shared():
67
 
            print '   shared repository: %s' % (
68
 
                repository.bzrdir.root_transport.base)
69
 
        else:
70
 
            print '          repository: %s' % (
71
 
                repository.bzrdir.root_transport.base)
72
 
 
73
 
    if branch:
74
 
        if branch.get_parent():
75
 
            print '       parent branch: %s' % branch.get_parent()
76
 
        if branch.get_push_location():
77
 
            print '      push to branch: %s' % branch.get_push_location()
 
134
    path_list = LocationList(osutils.getcwd())
 
135
    for name, loc in locs:
 
136
        path_list.add_url(name, loc)
 
137
    sys.stdout.writelines(path_list.get_lines())
 
138
 
 
139
def _gather_related_branches(branch):
 
140
    locs = LocationList(osutils.getcwd())
 
141
    locs.add_url('public branch', branch.get_public_branch())
 
142
    locs.add_url('push branch', branch.get_push_location())
 
143
    locs.add_url('parent branch', branch.get_parent())
 
144
    locs.add_url('submit branch', branch.get_submit_branch())
 
145
    return locs
 
146
 
 
147
def _show_related_info(branch, outfile):
 
148
    """Show parent and push location of branch."""
 
149
    locs = _gather_related_branches(branch)
 
150
    if len(locs.locs) > 0:
 
151
        print >> outfile
 
152
        print >> outfile, 'Related branches:'
 
153
        outfile.writelines(locs.get_lines())
78
154
 
79
155
 
80
156
def _show_format_info(control=None, repository=None, branch=None, working=None):
91
167
        print '    repository: %s' % repository._format.get_format_description()
92
168
 
93
169
 
 
170
def _show_locking_info(repository, branch=None, working=None):
 
171
    """Show locking status of working, branch and repository."""
 
172
    if (repository.get_physical_lock_status() or
 
173
        (branch and branch.get_physical_lock_status()) or
 
174
        (working and working.get_physical_lock_status())):
 
175
        print
 
176
        print 'Lock status:'
 
177
        if working:
 
178
            if working.get_physical_lock_status():
 
179
                status = 'locked'
 
180
            else:
 
181
                status = 'unlocked'
 
182
            print '  working tree: %s' % status
 
183
        if branch:
 
184
            if branch.get_physical_lock_status():
 
185
                status = 'locked'
 
186
            else:
 
187
                status = 'unlocked'
 
188
            print '        branch: %s' % status
 
189
        if repository:
 
190
            if repository.get_physical_lock_status():
 
191
                status = 'locked'
 
192
            else:
 
193
                status = 'unlocked'
 
194
            print '    repository: %s' % status
 
195
 
 
196
 
94
197
def _show_missing_revisions_branch(branch):
95
198
    """Show missing master revisions in branch."""
96
199
    # Try with inaccessible branch ?
108
211
    branch = working.branch
109
212
    basis = working.basis_tree()
110
213
    work_inv = working.inventory
111
 
    delta = diff.compare_trees(basis, working, want_unchanged=True)
112
 
    history = branch.revision_history()
113
 
    tree_last_id = working.last_revision()
 
214
    branch_revno, branch_last_revision = branch.last_revision_info()
 
215
    try:
 
216
        tree_last_id = working.get_parent_ids()[0]
 
217
    except IndexError:
 
218
        tree_last_id = None
114
219
 
115
 
    if len(history) and tree_last_id != history[-1]:
 
220
    if branch_revno and tree_last_id != branch_last_revision:
116
221
        tree_last_revno = branch.revision_id_to_revno(tree_last_id)
117
 
        missing_count = len(history) - tree_last_revno
 
222
        missing_count = branch_revno - tree_last_revno
118
223
        print
119
224
        print 'Working tree is out of date: missing %d revision%s.' % (
120
225
            missing_count, plural(missing_count))
124
229
    """Show statistics about a working tree."""
125
230
    basis = working.basis_tree()
126
231
    work_inv = working.inventory
127
 
    delta = diff.compare_trees(basis, working, want_unchanged=True)
 
232
    delta = working.changes_from(basis, want_unchanged=True)
128
233
 
129
234
    print
130
235
    print 'In the working tree:'
145
250
 
146
251
    dir_cnt = 0
147
252
    for file_id in work_inv:
148
 
        if work_inv.get_file_kind(file_id) == 'directory':
 
253
        if (work_inv.get_file_kind(file_id) == 'directory' and 
 
254
            not work_inv.is_root(file_id)):
149
255
            dir_cnt += 1
150
256
    print '  %8d versioned %s' \
151
257
          % (dir_cnt,
154
260
 
155
261
def _show_branch_stats(branch, verbose):
156
262
    """Show statistics about a branch."""
157
 
    repository = branch.repository
158
 
    history = branch.revision_history()
159
 
 
 
263
    revno, head = branch.last_revision_info()
160
264
    print
161
265
    print 'Branch history:'
162
 
    revno = len(history)
163
266
    print '  %8d revision%s' % (revno, plural(revno))
 
267
    stats = branch.repository.gather_stats(head, committers=verbose)
164
268
    if verbose:
165
 
        committers = {}
166
 
        for rev in history:
167
 
            committers[repository.get_revision(rev).committer] = True
168
 
        print '  %8d committer%s' % (len(committers), plural(len(committers)))
169
 
    if revno > 0:
170
 
        firstrev = repository.get_revision(history[0])
171
 
        age = int((time.time() - firstrev.timestamp) / 3600 / 24)
 
269
        committers = stats['committers']
 
270
        print '  %8d committer%s' % (committers, plural(committers))
 
271
    if revno:
 
272
        timestamp, timezone = stats['firstrev']
 
273
        age = int((time.time() - timestamp) / 3600 / 24)
172
274
        print '  %8d day%s old' % (age, plural(age))
173
 
        print '   first revision: %s' % format_date(firstrev.timestamp,
174
 
                                                    firstrev.timezone)
175
 
 
176
 
        lastrev = repository.get_revision(history[-1])
177
 
        print '  latest revision: %s' % format_date(lastrev.timestamp,
178
 
                                                    lastrev.timezone)
179
 
 
180
 
#     print
181
 
#     print 'Text store:'
182
 
#     c, t = branch.text_store.total_size()
183
 
#     print '  %8d file texts' % c
184
 
#     print '  %8d KiB' % (t/1024)
185
 
 
186
 
#     print
187
 
#     print 'Inventory store:'
188
 
#     c, t = branch.inventory_store.total_size()
189
 
#     print '  %8d inventories' % c
190
 
#     print '  %8d KiB' % (t/1024)
 
275
        print '   first revision: %s' % osutils.format_date(timestamp,
 
276
            timezone)
 
277
        timestamp, timezone = stats['latestrev']
 
278
        print '  latest revision: %s' % osutils.format_date(timestamp,
 
279
            timezone)
 
280
    return stats
191
281
 
192
282
 
193
283
def _show_repository_info(repository):
197
287
        print 'Create working tree for new branches inside the repository.'
198
288
 
199
289
 
200
 
def _show_repository_stats(repository):
 
290
def _show_repository_stats(stats):
201
291
    """Show statistics about a repository."""
202
 
    if repository.bzrdir.root_transport.listable():
 
292
    if 'revisions' in stats or 'size' in stats:
203
293
        print
204
 
        print 'Revision store:'
205
 
        c, t = repository._revision_store.total_size(repository.get_transaction())
206
 
        print '  %8d revision%s' % (c, plural(c))
207
 
        print '  %8d KiB' % (t/1024)
208
 
 
209
 
 
210
 
@deprecated_function(zero_eight)
211
 
def show_info(b):
212
 
    """Please see show_bzrdir_info."""
213
 
    return show_bzrdir_info(b.bzrdir)
214
 
 
 
294
        print 'Repository:'
 
295
    if 'revisions' in stats:
 
296
        revisions = stats['revisions']
 
297
        print '  %8d revision%s' % (revisions, plural(revisions))
 
298
    if 'size' in stats:
 
299
        print '  %8d KiB' % (stats['size']/1024)
215
300
 
216
301
def show_bzrdir_info(a_bzrdir, verbose=False):
217
302
    """Output to stdout the 'info' for a_bzrdir."""
218
303
    try:
219
 
        working = a_bzrdir.open_workingtree()
220
 
        working.lock_read()
221
 
        try:
222
 
            show_tree_info(working, verbose)
223
 
        finally:
224
 
            working.unlock()
225
 
        return
 
304
        tree = a_bzrdir.open_workingtree(
 
305
            recommend_upgrade=False)
226
306
    except (NoWorkingTree, NotLocalUrl):
227
 
        pass
228
 
 
229
 
    try:
230
 
        branch = a_bzrdir.open_branch()
231
 
        branch.lock_read()
232
 
        try:
233
 
            show_branch_info(branch, verbose)
234
 
        finally:
235
 
            branch.unlock()
236
 
        return
237
 
    except NotBranchError:
238
 
        pass
239
 
 
240
 
    try:
241
 
        repository = a_bzrdir.open_repository()
242
 
        repository.lock_read()
243
 
        try:
244
 
            show_repository_info(repository, verbose)
245
 
        finally:
246
 
            repository.unlock()
247
 
        return
248
 
    except NoRepositoryPresent:
249
 
        pass
250
 
 
251
 
    # Return silently, cmd_info returns NotBranchError if no bzrdir
252
 
    # could be opened.
253
 
 
254
 
 
 
307
        tree = None
 
308
        try:
 
309
            branch = a_bzrdir.open_branch()
 
310
        except NotBranchError:
 
311
            branch = None
 
312
            try:
 
313
                repository = a_bzrdir.open_repository()
 
314
            except NoRepositoryPresent:
 
315
                # Return silently; cmd_info already returned NotBranchError
 
316
                # if no bzrdir could be opened.
 
317
                return
 
318
            else:
 
319
                lockable = repository
 
320
        else:
 
321
            repository = branch.repository
 
322
            lockable = branch
 
323
    else:
 
324
        branch = tree.branch
 
325
        repository = branch.repository
 
326
        lockable = tree
 
327
 
 
328
    lockable.lock_read()
 
329
    try:
 
330
        show_component_info(a_bzrdir, repository, branch, tree, verbose)
 
331
    finally:
 
332
        lockable.unlock()
 
333
 
 
334
 
 
335
def show_component_info(control, repository, branch=None, working=None,
 
336
    verbose=1):
 
337
    """Write info about all bzrdir components to stdout"""
 
338
    if verbose is False:
 
339
        verbose = 1
 
340
    if verbose is True:
 
341
        verbose = 2
 
342
    layout = describe_layout(repository, branch, working)
 
343
    format = describe_format(control, repository, branch, working)
 
344
    print "%s (format: %s)" % (layout, format)
 
345
    _show_location_info(gather_location_info(repository, branch, working))
 
346
    if branch is not None:
 
347
        _show_related_info(branch, sys.stdout)
 
348
    if verbose == 0:
 
349
        return
 
350
    _show_format_info(control, repository, branch, working)
 
351
    _show_locking_info(repository, branch, working)
 
352
    if branch is not None:
 
353
        _show_missing_revisions_branch(branch)
 
354
    if working is not None:
 
355
        _show_missing_revisions_working(working)
 
356
        _show_working_stats(working)
 
357
    elif branch is not None:
 
358
        _show_missing_revisions_branch(branch)
 
359
    if branch is not None:
 
360
        stats = _show_branch_stats(branch, verbose==2)
 
361
    else:
 
362
        stats = repository.gather_stats()
 
363
    if branch is None and working is None:
 
364
        _show_repository_info(repository)
 
365
    _show_repository_stats(stats)
 
366
 
 
367
 
 
368
def describe_layout(repository=None, branch=None, tree=None):
 
369
    """Convert a control directory layout into a user-understandable term
 
370
 
 
371
    Common outputs include "Standalone tree", "Repository branch" and
 
372
    "Checkout".  Uncommon outputs include "Unshared repository with trees"
 
373
    and "Empty control directory"
 
374
    """
 
375
    if repository is None:
 
376
        return 'Empty control directory'
 
377
    if branch is None and tree is None:
 
378
        if repository.is_shared():
 
379
            phrase = 'Shared repository'
 
380
        else:
 
381
            phrase = 'Unshared repository'
 
382
        if repository.make_working_trees():
 
383
            phrase += ' with trees'
 
384
        return phrase
 
385
    else:
 
386
        if repository.is_shared():
 
387
            independence = "Repository "
 
388
        else:
 
389
            independence = "Standalone "
 
390
        if tree is not None:
 
391
            phrase = "tree"
 
392
        else:
 
393
            phrase = "branch"
 
394
        if branch is None and tree is not None:
 
395
            phrase = "branchless tree"
 
396
        else:
 
397
            if (tree is not None and tree.bzrdir.root_transport.base !=
 
398
                branch.bzrdir.root_transport.base):
 
399
                independence = ''
 
400
                phrase = "Lightweight checkout"
 
401
            elif branch.get_bound_location() is not None:
 
402
                if independence == 'Standalone ':
 
403
                    independence = ''
 
404
                if tree is None:
 
405
                    phrase = "Bound branch"
 
406
                else:
 
407
                    phrase = "Checkout"
 
408
        if independence != "":
 
409
            phrase = phrase.lower()
 
410
        return "%s%s" % (independence, phrase)
 
411
 
 
412
 
 
413
def describe_format(control, repository, branch, tree):
 
414
    """Determine the format of an existing control directory
 
415
 
 
416
    Several candidates may be found.  If so, the names are returned as a
 
417
    single string, separated by ' or '.
 
418
 
 
419
    If no matching candidate is found, "unnamed" is returned.
 
420
    """
 
421
    candidates  = []
 
422
    if (branch is not None and tree is not None and
 
423
        branch.bzrdir.root_transport.base !=
 
424
        tree.bzrdir.root_transport.base):
 
425
        branch = None
 
426
        repository = None
 
427
    for key in bzrdir.format_registry.keys():
 
428
        format = bzrdir.format_registry.make_bzrdir(key)
 
429
        if isinstance(format, bzrdir.BzrDirMetaFormat1):
 
430
            if (tree and format.workingtree_format !=
 
431
                tree._format):
 
432
                continue
 
433
            if (branch and format.get_branch_format() !=
 
434
                branch._format):
 
435
                continue
 
436
            if (repository and format.repository_format !=
 
437
                repository._format):
 
438
                continue
 
439
        if format.__class__ is not control._format.__class__:
 
440
            continue
 
441
        candidates.append(key)
 
442
    if len(candidates) == 0:
 
443
        return 'unnamed'
 
444
    new_candidates = [c for c in candidates if c != 'default']
 
445
    if len(new_candidates) > 0:
 
446
        candidates = new_candidates
 
447
    new_candidates = [c for c in candidates if not
 
448
        bzrdir.format_registry.get_info(c).hidden]
 
449
    if len(new_candidates) > 0:
 
450
        candidates = new_candidates
 
451
    return ' or '.join(candidates)
 
452
 
 
453
 
 
454
@deprecated_function(zero_eighteen)
255
455
def show_tree_info(working, verbose):
256
456
    """Output to stdout the 'info' for working."""
257
457
    branch = working.branch
258
458
    repository = branch.repository
259
459
    control = working.bzrdir
260
 
 
261
 
    _show_location_info(repository, branch, working)
262
 
    _show_format_info(control, repository, branch, working)
263
 
    _show_missing_revisions_branch(branch)
264
 
    _show_missing_revisions_working(working)
265
 
    _show_working_stats(working)
266
 
    _show_branch_stats(branch, verbose)
267
 
    _show_repository_stats(repository)
268
 
 
269
 
 
 
460
    show_component_info(control, repository, branch, working, verbose)
 
461
 
 
462
 
 
463
@deprecated_function(zero_eighteen)
270
464
def show_branch_info(branch, verbose):
271
465
    """Output to stdout the 'info' for branch."""
272
466
    repository = branch.repository
273
467
    control = branch.bzrdir
274
 
 
275
 
    _show_location_info(repository, branch)
276
 
    _show_format_info(control, repository, branch)
277
 
    _show_missing_revisions_branch(branch)
278
 
    _show_branch_stats(branch, verbose)
279
 
    _show_repository_stats(repository)
280
 
 
281
 
 
 
468
    show_component_info(control, repository, branch, verbose=verbose)
 
469
 
 
470
 
 
471
@deprecated_function(zero_eighteen)
282
472
def show_repository_info(repository, verbose):
283
 
    """Output to stdout the 'info' for branch."""
 
473
    """Output to stdout the 'info' for repository."""
284
474
    control = repository.bzrdir
285
 
 
286
 
    _show_location_info(repository)
287
 
    _show_format_info(control, repository)
288
 
    _show_repository_info(repository)
289
 
    _show_repository_stats(repository)
 
475
    show_component_info(control, repository, verbose=verbose)