~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/info.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-01-02 08:23:44 UTC
  • mfrom: (3140.1.9 find-branches)
  • Revision ID: pqm@pqm.ubuntu.com-20080102082344-qret383z2bdk1ud4
Optimize find_branches for standalone repositories (abentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
__all__ = ['show_bzrdir_info']
18
18
 
 
19
import os
19
20
import time
20
 
 
 
21
import sys
21
22
 
22
23
from bzrlib import (
23
24
    bzrdir,
24
25
    diff,
 
26
    errors,
25
27
    osutils,
26
28
    urlutils,
27
29
    )
29
31
                           NoRepositoryPresent, NotLocalUrl)
30
32
from bzrlib.missing import find_unmerged
31
33
from bzrlib.symbol_versioning import (deprecated_function,
32
 
        zero_eight, zero_eighteen)
 
34
        zero_eighteen)
33
35
 
34
36
 
35
37
def plural(n, base='', pl=None):
41
43
        return 's'
42
44
 
43
45
 
44
 
def _repo_rel_url(repo_url, inner_url):
45
 
    """Return path with common prefix of repository path removed.
46
 
 
47
 
    If path is not part of the repository, the original path is returned.
48
 
    If path is equal to the repository, the current directory marker '.' is
49
 
    returned.
50
 
    Otherwise, a relative path is returned, with trailing '/' stripped.
51
 
    """
52
 
    inner_url = urlutils.normalize_url(inner_url)
53
 
    repo_url = urlutils.normalize_url(repo_url)
54
 
    if inner_url == repo_url:
55
 
        return '.'
56
 
    result = urlutils.relative_url(repo_url, inner_url)
57
 
    if result != inner_url:
58
 
        result = result.rstrip('/')
59
 
    return result
60
 
 
61
 
class _UrlList(object):
62
 
 
63
 
    def __init__(self):
64
 
        self.urls = []
65
 
 
66
 
    def add_url(self, label, url):
67
 
        self.add_path(label, urlutils.unescape_for_display(url, 'ascii'))
68
 
 
69
 
    def add_url(self, label, url):
70
 
        self.add_path(label, url)
 
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)
71
62
 
72
63
    def add_path(self, label, path):
73
 
        self.urls.append((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))
74
75
 
75
 
    def print_lines(self):
76
 
        max_len = max(len(l) for l, u in self.urls)
77
 
        for label, url in self.urls:
78
 
            print "  %*s: %s" % (max_len, label, url)
 
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
79
 
80
80
 
81
81
def gather_location_info(repository, branch=None, working=None):
101
101
        if working_path != master_path:
102
102
            locs['checkout of branch'] = master_path
103
103
        elif repository.is_shared():
104
 
            locs['repository branch'] = _repo_rel_url(repository_path,
105
 
                branch_path)
 
104
            locs['repository branch'] = branch_path
106
105
        elif branch_path is not None:
107
106
            # standalone
108
107
            locs['branch root'] = branch_path
111
110
        if repository.is_shared():
112
111
            # lightweight checkout of branch in shared repository
113
112
            if branch_path is not None:
114
 
                locs['repository branch'] = _repo_rel_url(repository_path,
115
 
                                                          branch_path)
 
113
                locs['repository branch'] = branch_path
116
114
        elif branch_path is not None:
117
115
            # standalone
118
116
            locs['branch root'] = branch_path
130
128
    return [(n, locs[n]) for n in order if n in locs]
131
129
 
132
130
 
133
 
def _show_location_info(locs):
 
131
def _show_location_info(locs, outfile):
134
132
    """Show known locations for working, branch and repository."""
135
 
    print 'Location:'
136
 
    path_list = _UrlList()
 
133
    outfile.write('Location:\n')
 
134
    path_list = LocationList(osutils.getcwd())
137
135
    for name, loc in locs:
138
136
        path_list.add_url(name, loc)
139
 
    path_list.print_lines()
140
 
 
141
 
 
142
 
def _show_related_info(branch):
 
137
    outfile.writelines(path_list.get_lines())
 
138
 
 
139
 
 
140
def _gather_related_branches(branch):
 
141
    locs = LocationList(osutils.getcwd())
 
142
    locs.add_url('public branch', branch.get_public_branch())
 
143
    locs.add_url('push branch', branch.get_push_location())
 
144
    locs.add_url('parent branch', branch.get_parent())
 
145
    locs.add_url('submit branch', branch.get_submit_branch())
 
146
    return locs
 
147
 
 
148
 
 
149
def _show_related_info(branch, outfile):
143
150
    """Show parent and push location of branch."""
144
 
    if branch.get_parent() or branch.get_push_location():
145
 
        print
146
 
        print 'Related branches:'
147
 
        if branch.get_parent():
148
 
            if branch.get_push_location():
149
 
                print '      parent branch: %s' % branch.get_parent()
150
 
            else:
151
 
                print '  parent branch: %s' % branch.get_parent()
152
 
        if branch.get_push_location():
153
 
            print '  publish to branch: %s' % branch.get_push_location()
154
 
 
155
 
 
156
 
def _show_format_info(control=None, repository=None, branch=None, working=None):
 
151
    locs = _gather_related_branches(branch)
 
152
    if len(locs.locs) > 0:
 
153
        outfile.write('\n')
 
154
        outfile.write('Related branches:\n')
 
155
        outfile.writelines(locs.get_lines())
 
156
 
 
157
 
 
158
def _show_format_info(control=None, repository=None, branch=None,
 
159
                      working=None, outfile=None):
157
160
    """Show known formats for control, working, branch and repository."""
158
 
    print
159
 
    print 'Format:'
 
161
    outfile.write('\n')
 
162
    outfile.write('Format:\n')
160
163
    if control:
161
 
        print '       control: %s' % control._format.get_format_description()
 
164
        outfile.write('       control: %s\n' %
 
165
            control._format.get_format_description())
162
166
    if working:
163
 
        print '  working tree: %s' % working._format.get_format_description()
 
167
        outfile.write('  working tree: %s\n' %
 
168
            working._format.get_format_description())
164
169
    if branch:
165
 
        print '        branch: %s' % branch._format.get_format_description()
 
170
        outfile.write('        branch: %s\n' %
 
171
            branch._format.get_format_description())
166
172
    if repository:
167
 
        print '    repository: %s' % repository._format.get_format_description()
168
 
 
169
 
 
170
 
def _show_locking_info(repository, branch=None, working=None):
 
173
        outfile.write('    repository: %s\n' %
 
174
            repository._format.get_format_description())
 
175
 
 
176
 
 
177
def _show_locking_info(repository, branch=None, working=None, outfile=None):
171
178
    """Show locking status of working, branch and repository."""
172
179
    if (repository.get_physical_lock_status() or
173
180
        (branch and branch.get_physical_lock_status()) or
174
181
        (working and working.get_physical_lock_status())):
175
 
        print
176
 
        print 'Lock status:'
 
182
        outfile.write('\n')
 
183
        outfile.write('Lock status:\n')
177
184
        if working:
178
185
            if working.get_physical_lock_status():
179
186
                status = 'locked'
180
187
            else:
181
188
                status = 'unlocked'
182
 
            print '  working tree: %s' % status
 
189
            outfile.write('  working tree: %s\n' % status)
183
190
        if branch:
184
191
            if branch.get_physical_lock_status():
185
192
                status = 'locked'
186
193
            else:
187
194
                status = 'unlocked'
188
 
            print '        branch: %s' % status
 
195
            outfile.write('        branch: %s\n' % status)
189
196
        if repository:
190
197
            if repository.get_physical_lock_status():
191
198
                status = 'locked'
192
199
            else:
193
200
                status = 'unlocked'
194
 
            print '    repository: %s' % status
195
 
 
196
 
 
197
 
def _show_missing_revisions_branch(branch):
 
201
            outfile.write('    repository: %s\n' % status)
 
202
 
 
203
 
 
204
def _show_missing_revisions_branch(branch, outfile):
198
205
    """Show missing master revisions in branch."""
199
206
    # Try with inaccessible branch ?
200
207
    master = branch.get_master_branch()
201
208
    if master:
202
209
        local_extra, remote_extra = find_unmerged(branch, master)
203
210
        if remote_extra:
204
 
            print
205
 
            print 'Branch is out of date: missing %d revision%s.' % (
206
 
                len(remote_extra), plural(len(remote_extra)))
207
 
 
208
 
 
209
 
def _show_missing_revisions_working(working):
 
211
            outfile.write('\n')
 
212
            outfile.write(('Branch is out of date: missing %d '
 
213
                'revision%s.\n') % (len(remote_extra),
 
214
                plural(len(remote_extra))))
 
215
 
 
216
 
 
217
def _show_missing_revisions_working(working, outfile):
210
218
    """Show missing revisions in working tree."""
211
219
    branch = working.branch
212
220
    basis = working.basis_tree()
220
228
    if branch_revno and tree_last_id != branch_last_revision:
221
229
        tree_last_revno = branch.revision_id_to_revno(tree_last_id)
222
230
        missing_count = branch_revno - tree_last_revno
223
 
        print
224
 
        print 'Working tree is out of date: missing %d revision%s.' % (
225
 
            missing_count, plural(missing_count))
226
 
 
227
 
 
228
 
def _show_working_stats(working):
 
231
        outfile.write('\n')
 
232
        outfile.write(('Working tree is out of date: missing %d '
 
233
            'revision%s.\n') % (missing_count, plural(missing_count)))
 
234
 
 
235
 
 
236
def _show_working_stats(working, outfile):
229
237
    """Show statistics about a working tree."""
230
238
    basis = working.basis_tree()
231
239
    work_inv = working.inventory
232
240
    delta = working.changes_from(basis, want_unchanged=True)
233
241
 
234
 
    print
235
 
    print 'In the working tree:'
236
 
    print '  %8s unchanged' % len(delta.unchanged)
237
 
    print '  %8d modified' % len(delta.modified)
238
 
    print '  %8d added' % len(delta.added)
239
 
    print '  %8d removed' % len(delta.removed)
240
 
    print '  %8d renamed' % len(delta.renamed)
 
242
    outfile.write('\n')
 
243
    outfile.write('In the working tree:\n')
 
244
    outfile.write('  %8s unchanged\n' % len(delta.unchanged))
 
245
    outfile.write('  %8d modified\n' % len(delta.modified))
 
246
    outfile.write('  %8d added\n' % len(delta.added))
 
247
    outfile.write('  %8d removed\n' % len(delta.removed))
 
248
    outfile.write('  %8d renamed\n' % len(delta.renamed))
241
249
 
242
250
    ignore_cnt = unknown_cnt = 0
243
251
    for path in working.extras():
245
253
            ignore_cnt += 1
246
254
        else:
247
255
            unknown_cnt += 1
248
 
    print '  %8d unknown' % unknown_cnt
249
 
    print '  %8d ignored' % ignore_cnt
 
256
    outfile.write('  %8d unknown\n' % unknown_cnt)
 
257
    outfile.write('  %8d ignored\n' % ignore_cnt)
250
258
 
251
259
    dir_cnt = 0
252
260
    for file_id in work_inv:
253
261
        if (work_inv.get_file_kind(file_id) == 'directory' and 
254
262
            not work_inv.is_root(file_id)):
255
263
            dir_cnt += 1
256
 
    print '  %8d versioned %s' \
257
 
          % (dir_cnt,
258
 
             plural(dir_cnt, 'subdirectory', 'subdirectories'))
259
 
 
260
 
 
261
 
def _show_branch_stats(branch, verbose):
 
264
    outfile.write('  %8d versioned %s\n' % (dir_cnt,
 
265
        plural(dir_cnt, 'subdirectory', 'subdirectories')))
 
266
 
 
267
 
 
268
def _show_branch_stats(branch, verbose, outfile):
262
269
    """Show statistics about a branch."""
263
270
    revno, head = branch.last_revision_info()
264
 
    print
265
 
    print 'Branch history:'
266
 
    print '  %8d revision%s' % (revno, plural(revno))
 
271
    outfile.write('\n')
 
272
    outfile.write('Branch history:\n')
 
273
    outfile.write('  %8d revision%s\n' % (revno, plural(revno)))
267
274
    stats = branch.repository.gather_stats(head, committers=verbose)
268
275
    if verbose:
269
276
        committers = stats['committers']
270
 
        print '  %8d committer%s' % (committers, plural(committers))
 
277
        outfile.write('  %8d committer%s\n' % (committers,
 
278
            plural(committers)))
271
279
    if revno:
272
280
        timestamp, timezone = stats['firstrev']
273
281
        age = int((time.time() - timestamp) / 3600 / 24)
274
 
        print '  %8d day%s old' % (age, plural(age))
275
 
        print '   first revision: %s' % osutils.format_date(timestamp,
276
 
            timezone)
 
282
        outfile.write('  %8d day%s old\n' % (age, plural(age)))
 
283
        outfile.write('   first revision: %s\n' %
 
284
            osutils.format_date(timestamp, timezone))
277
285
        timestamp, timezone = stats['latestrev']
278
 
        print '  latest revision: %s' % osutils.format_date(timestamp,
279
 
            timezone)
 
286
        outfile.write('  latest revision: %s\n' %
 
287
            osutils.format_date(timestamp, timezone))
280
288
    return stats
281
289
 
282
290
 
283
 
def _show_repository_info(repository):
 
291
def _show_repository_info(repository, outfile):
284
292
    """Show settings of a repository."""
285
293
    if repository.make_working_trees():
286
 
        print
287
 
        print 'Create working tree for new branches inside the repository.'
288
 
 
289
 
 
290
 
def _show_repository_stats(stats):
 
294
        outfile.write('\n')
 
295
        outfile.write('Create working tree for new branches inside '
 
296
            'the repository.\n')
 
297
 
 
298
 
 
299
def _show_repository_stats(stats, outfile):
291
300
    """Show statistics about a repository."""
292
301
    if 'revisions' in stats or 'size' in stats:
293
 
        print
294
 
        print 'Repository:'
 
302
        outfile.write('\n')
 
303
        outfile.write('Repository:\n')
295
304
    if 'revisions' in stats:
296
305
        revisions = stats['revisions']
297
 
        print '  %8d revision%s' % (revisions, plural(revisions))
 
306
        outfile.write('  %8d revision%s\n' % (revisions, plural(revisions)))
298
307
    if 'size' in stats:
299
 
        print '  %8d KiB' % (stats['size']/1024)
300
 
 
301
 
def show_bzrdir_info(a_bzrdir, verbose=False):
 
308
        outfile.write('  %8d KiB\n' % (stats['size']/1024))
 
309
 
 
310
 
 
311
def show_bzrdir_info(a_bzrdir, verbose=False, outfile=None):
302
312
    """Output to stdout the 'info' for a_bzrdir."""
 
313
    if outfile is None:
 
314
        outfile = sys.stdout
303
315
    try:
304
316
        tree = a_bzrdir.open_workingtree(
305
317
            recommend_upgrade=False)
327
339
 
328
340
    lockable.lock_read()
329
341
    try:
330
 
        show_component_info(a_bzrdir, repository, branch, tree, verbose)
 
342
        show_component_info(a_bzrdir, repository, branch, tree, verbose,
 
343
                            outfile)
331
344
    finally:
332
345
        lockable.unlock()
333
346
 
334
347
 
335
348
def show_component_info(control, repository, branch=None, working=None,
336
 
    verbose=1):
 
349
    verbose=1, outfile=None):
337
350
    """Write info about all bzrdir components to stdout"""
 
351
    if outfile is None:
 
352
        outfile = sys.stdout
338
353
    if verbose is False:
339
354
        verbose = 1
340
355
    if verbose is True:
341
356
        verbose = 2
342
357
    layout = describe_layout(repository, branch, working)
343
358
    format = describe_format(control, repository, branch, working)
344
 
    print "%s (format: %s)" % (layout, format)
345
 
    _show_location_info(gather_location_info(repository, branch, working))
 
359
    outfile.write("%s (format: %s)\n" % (layout, format))
 
360
    _show_location_info(gather_location_info(repository, branch, working),
 
361
                        outfile)
 
362
    if branch is not None:
 
363
        _show_related_info(branch, outfile)
346
364
    if verbose == 0:
347
365
        return
348
 
    if branch is not None:
349
 
        _show_related_info(branch)
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)
 
366
    _show_format_info(control, repository, branch, working, outfile)
 
367
    _show_locking_info(repository, branch, working, outfile)
 
368
    if branch is not None:
 
369
        _show_missing_revisions_branch(branch, outfile)
354
370
    if working is not None:
355
 
        _show_missing_revisions_working(working)
356
 
        _show_working_stats(working)
 
371
        _show_missing_revisions_working(working, outfile)
 
372
        _show_working_stats(working, outfile)
357
373
    elif branch is not None:
358
 
        _show_missing_revisions_branch(branch)
 
374
        _show_missing_revisions_branch(branch, outfile)
359
375
    if branch is not None:
360
 
        stats = _show_branch_stats(branch, verbose==2)
 
376
        stats = _show_branch_stats(branch, verbose==2, outfile)
361
377
    else:
362
378
        stats = repository.gather_stats()
363
379
    if branch is None and working is None:
364
 
        _show_repository_info(repository)
365
 
    _show_repository_stats(stats)
 
380
        _show_repository_info(repository, outfile)
 
381
    _show_repository_stats(stats, outfile)
366
382
 
367
383
 
368
384
def describe_layout(repository=None, branch=None, tree=None):
449
465
    if len(new_candidates) > 0:
450
466
        candidates = new_candidates
451
467
    return ' or '.join(candidates)
452
 
 
453
 
@deprecated_function(zero_eight)
454
 
def show_info(b):
455
 
    """Please see show_bzrdir_info."""
456
 
    return show_bzrdir_info(b.bzrdir)
457
 
 
458
 
 
459
 
@deprecated_function(zero_eighteen)
460
 
def show_tree_info(working, verbose):
461
 
    """Output to stdout the 'info' for working."""
462
 
    branch = working.branch
463
 
    repository = branch.repository
464
 
    control = working.bzrdir
465
 
    show_component_info(control, repository, branch, working, verbose)
466
 
 
467
 
 
468
 
@deprecated_function(zero_eighteen)
469
 
def show_branch_info(branch, verbose):
470
 
    """Output to stdout the 'info' for branch."""
471
 
    repository = branch.repository
472
 
    control = branch.bzrdir
473
 
    show_component_info(control, repository, branch, verbose=verbose)
474
 
 
475
 
 
476
 
@deprecated_function(zero_eighteen)
477
 
def show_repository_info(repository, verbose):
478
 
    """Output to stdout the 'info' for repository."""
479
 
    control = repository.bzrdir
480
 
    show_component_info(control, repository, verbose=verbose)