/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 brzlib/status.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

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
import sys
18
20
 
19
 
from . import (
 
21
from brzlib import (
20
22
    delta as _mod_delta,
21
23
    hooks as _mod_hooks,
22
24
    log,
24
26
    tsort,
25
27
    revision as _mod_revision,
26
28
    )
27
 
from . import errors as errors
28
 
from .trace import mutter, warning
29
 
from .workingtree import ShelvingUnsupported
30
 
 
 
29
import brzlib.errors as errors
 
30
from brzlib.trace import mutter, warning
31
31
 
32
32
# TODO: when showing single-line logs, truncate to the width of the terminal
33
33
# if known, but only if really going to the terminal (not into a file)
34
34
 
35
35
 
36
 
def report_changes(to_file, old, new, specific_files,
37
 
                   show_short_reporter, show_long_callback,
38
 
                   short=False, want_unchanged=False,
 
36
def report_changes(to_file, old, new, specific_files, 
 
37
                   show_short_reporter, show_long_callback, 
 
38
                   short=False, want_unchanged=False, 
39
39
                   want_unversioned=False, show_ids=False, classify=True):
40
40
    """Display summary of changes.
41
41
 
42
 
    This compares two trees with regards to a list of files, and delegates
 
42
    This compares two trees with regards to a list of files, and delegates 
43
43
    the display to underlying elements.
44
44
 
45
45
    For short output, it creates an iterator on all changes, and lets a given
66
66
 
67
67
    if short:
68
68
        changes = new.iter_changes(old, want_unchanged, specific_files,
69
 
                                   require_versioned=False, want_unversioned=want_unversioned)
 
69
            require_versioned=False, want_unversioned=want_unversioned)
70
70
        _mod_delta.report_changes(changes, show_short_reporter)
 
71
        
71
72
    else:
72
73
        delta = new.changes_from(old, want_unchanged=want_unchanged,
73
 
                                 specific_files=specific_files,
74
 
                                 want_unversioned=want_unversioned)
 
74
                              specific_files=specific_files,
 
75
                              want_unversioned=want_unversioned)
75
76
        # filter out unknown files. We may want a tree method for
76
77
        # this
77
 
        delta.unversioned = [change for change in delta.unversioned
78
 
                             if not new.is_ignored(change.path[1])]
79
 
        show_long_callback(to_file, delta,
 
78
        delta.unversioned = [unversioned for unversioned in
 
79
            delta.unversioned if not new.is_ignored(unversioned[0])]
 
80
        show_long_callback(to_file, delta, 
80
81
                           show_ids=show_ids,
81
82
                           show_unchanged=want_unchanged,
82
83
                           classify=classify)
83
84
 
84
85
 
85
 
def show_tree_status(wt,
 
86
def show_tree_status(wt, show_unchanged=None,
86
87
                     specific_files=None,
87
88
                     show_ids=False,
88
89
                     to_file=None,
105
106
    If showing the status of a working tree, extra information is included
106
107
    about unknown files, conflicts, and pending merges.
107
108
 
 
109
    :param show_unchanged: Deprecated parameter. If set, includes unchanged
 
110
        files.
108
111
    :param specific_files: If set, a list of filenames whose status should be
109
112
        shown.  It is an error to give a filename that is not in the working
110
113
        tree, or in the working inventory or in the basis inventory.
120
123
        the merge tips
121
124
    :param versioned: If True, only shows versioned files.
122
125
    :param classify: Add special symbols to indicate file kind.
123
 
    :param show_long_callback: A callback: message = show_long_callback(to_file, delta,
 
126
    :param show_long_callback: A callback: message = show_long_callback(to_file, delta, 
124
127
        show_ids, show_unchanged, indent, filter), only used with the long output
125
128
    """
 
129
    if show_unchanged is not None:
 
130
        warn("show_tree_status with show_unchanged has been deprecated "
 
131
             "since brzlib 0.9", DeprecationWarning, stacklevel=2)
 
132
 
126
133
    if to_file is None:
127
134
        to_file = sys.stdout
128
135
 
129
 
    with wt.lock_read():
 
136
    wt.lock_read()
 
137
    try:
130
138
        new_is_working_tree = True
131
139
        if revision is None:
132
140
            if wt.last_revision() != wt.branch.last_revision():
133
 
                warning("working tree is out of date, run 'brz update'")
 
141
                warning("working tree is out of date, run 'bzr update'")
134
142
            new = wt
135
143
            old = new.basis_tree()
136
144
        elif len(revision) > 0:
137
145
            try:
138
146
                old = revision[0].as_tree(wt.branch)
139
 
            except errors.NoSuchRevision as e:
 
147
            except errors.NoSuchRevision, e:
140
148
                raise errors.BzrCommandError(str(e))
141
149
            if (len(revision) > 1) and (revision[1].spec is not None):
142
150
                try:
143
151
                    new = revision[1].as_tree(wt.branch)
144
152
                    new_is_working_tree = False
145
 
                except errors.NoSuchRevision as e:
 
153
                except errors.NoSuchRevision, e:
146
154
                    raise errors.BzrCommandError(str(e))
147
155
            else:
148
156
                new = wt
149
 
        with old.lock_read(), new.lock_read():
 
157
        old.lock_read()
 
158
        new.lock_read()
 
159
        try:
150
160
            for hook in hooks['pre_status']:
151
 
                hook(StatusHookParams(
152
 
                    old, new, to_file, versioned, show_ids, short, verbose,
153
 
                    specific_files=specific_files))
 
161
                hook(StatusHookParams(old, new, to_file, versioned,
 
162
                    show_ids, short, verbose, specific_files=specific_files))
154
163
 
155
164
            specific_files, nonexistents \
156
165
                = _filter_nonexistent(specific_files, old, new)
157
166
            want_unversioned = not versioned
158
167
 
159
168
            # Reporter used for short outputs
160
 
            reporter = _mod_delta._ChangeReporter(
161
 
                output_file=to_file, unversioned_filter=new.is_ignored,
162
 
                classify=classify)
163
 
            report_changes(to_file, old, new, specific_files,
164
 
                           reporter, show_long_callback,
165
 
                           short=short, want_unversioned=want_unversioned,
166
 
                           show_ids=show_ids, classify=classify)
 
169
            reporter = _mod_delta._ChangeReporter(output_file=to_file,
 
170
                unversioned_filter=new.is_ignored, classify=classify)
 
171
            report_changes(to_file, old, new, specific_files, 
 
172
                           reporter, show_long_callback, 
 
173
                           short=short, want_unchanged=show_unchanged, 
 
174
                           want_unversioned=want_unversioned, show_ids=show_ids,
 
175
                           classify=classify)
167
176
 
168
177
            # show the ignored files among specific files (i.e. show the files
169
 
            # identified from input that we choose to ignore).
 
178
            # identified from input that we choose to ignore). 
170
179
            if specific_files is not None:
171
180
                # Ignored files is sorted because specific_files is already sorted
172
181
                ignored_files = [specific for specific in
173
 
                                 specific_files if new.is_ignored(specific)]
 
182
                    specific_files if new.is_ignored(specific)]
174
183
                if len(ignored_files) > 0 and not short:
175
184
                    to_file.write("ignored:\n")
176
185
                    prefix = ' '
183
192
            # delta.
184
193
            conflicts = new.conflicts()
185
194
            if specific_files is not None:
186
 
                conflicts = conflicts.select_conflicts(
187
 
                    new, specific_files, ignore_misses=True, recurse=True)[1]
 
195
                conflicts = conflicts.select_conflicts(new, specific_files,
 
196
                    ignore_misses=True, recurse=True)[1]
188
197
            if len(conflicts) > 0 and not short:
189
198
                to_file.write("conflicts:\n")
190
199
            for conflict in conflicts:
192
201
                    prefix = 'C  '
193
202
                else:
194
203
                    prefix = ' '
195
 
                to_file.write("%s %s\n" % (prefix, conflict.describe()))
 
204
                to_file.write("%s %s\n" % (prefix, unicode(conflict)))
196
205
            # Show files that were requested but don't exist (and are
197
206
            # not versioned).  We don't involve delta in this; these
198
207
            # paths are really the province of just the status
214
223
            if nonexistents:
215
224
                raise errors.PathsDoNotExist(nonexistents)
216
225
            for hook in hooks['post_status']:
217
 
                hook(StatusHookParams(
218
 
                    old, new, to_file, versioned, show_ids, short, verbose,
219
 
                    specific_files=specific_files))
 
226
                hook(StatusHookParams(old, new, to_file, versioned,
 
227
                    show_ids, short, verbose, specific_files=specific_files))
 
228
        finally:
 
229
            old.unlock()
 
230
            new.unlock()
 
231
    finally:
 
232
        wt.unlock()
220
233
 
221
234
 
222
235
def _get_sorted_revisions(tip_revision, revision_ids, parent_map):
235
248
    # of any references pointing outside of this graph.
236
249
    parent_graph = {}
237
250
    for revision_id in revision_ids:
238
 
        if revision_id not in parent_map:  # ghost
 
251
        if revision_id not in parent_map: # ghost
239
252
            parent_graph[revision_id] = []
240
253
        else:
241
254
            # Only include parents which are in this sub-graph
242
255
            parent_graph[revision_id] = [p for p in parent_map[revision_id]
243
 
                                         if p in revision_ids]
 
256
                                            if p in revision_ids]
244
257
    sorter = tsort.MergeSorter(parent_graph, tip_revision)
245
258
    return sorter.iter_topo_order()
246
259
 
284
297
    log_formatter = log.LineLogFormatter(to_file)
285
298
    for merge in pending:
286
299
        try:
287
 
            rev = branch.repository.get_revision(merge)
 
300
            rev = branch.repository.get_revisions([merge])[0]
288
301
        except errors.NoSuchRevision:
289
302
            # If we are missing a revision, just print out the revision id
290
 
            to_file.write(first_prefix + '(ghost) ' +
291
 
                          merge.decode('utf-8') + '\n')
 
303
            to_file.write(first_prefix + '(ghost) ' + merge + '\n')
292
304
            other_revisions.append(merge)
293
305
            continue
294
306
 
304
316
        merge_extra.discard(_mod_revision.NULL_REVISION)
305
317
 
306
318
        # Get a handle to all of the revisions we will need
307
 
        revisions = dict(branch.repository.iter_revisions(merge_extra))
 
319
        try:
 
320
            revisions = dict((rev.revision_id, rev) for rev in
 
321
                             branch.repository.get_revisions(merge_extra))
 
322
        except errors.NoSuchRevision:
 
323
            # One of the sub nodes is a ghost, check each one
 
324
            revisions = {}
 
325
            for revision_id in merge_extra:
 
326
                try:
 
327
                    rev = branch.repository.get_revisions([revision_id])[0]
 
328
                except errors.NoSuchRevision:
 
329
                    revisions[revision_id] = None
 
330
                else:
 
331
                    revisions[revision_id] = rev
308
332
 
309
333
        # Display the revisions brought in by this merge.
310
334
        rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
311
 
                                                branch.repository.get_parent_map(merge_extra))
 
335
                            branch.repository.get_parent_map(merge_extra))
312
336
        # Skip the first node
313
 
        num, first, depth, eom = next(rev_id_iterator)
 
337
        num, first, depth, eom = rev_id_iterator.next()
314
338
        if first != merge:
315
339
            raise AssertionError('Somehow we misunderstood how'
316
 
                                 ' iter_topo_order works %s != %s' % (first, merge))
 
340
                ' iter_topo_order works %s != %s' % (first, merge))
317
341
        for num, sub_merge, depth, eom in rev_id_iterator:
318
342
            rev = revisions[sub_merge]
319
343
            if rev is None:
320
 
                to_file.write(sub_prefix + '(ghost) ' +
321
 
                              sub_merge.decode('utf-8') + '\n')
 
344
                to_file.write(sub_prefix + '(ghost) ' + sub_merge + '\n')
322
345
                continue
323
346
            show_log_message(revisions[sub_merge], sub_prefix)
324
347
 
333
356
 
334
357
    If either of the two lists is empty, return it as an empty list.
335
358
 
336
 
    This can be used by operations such as brz status that can accept
 
359
    This can be used by operations such as bzr status that can accept
337
360
    unknown or ignored files.
338
361
    """
339
362
    mutter("check paths: %r", orig_paths)
342
365
    s = old_tree.filter_unversioned_files(orig_paths)
343
366
    s = new_tree.filter_unversioned_files(s)
344
367
    nonexistent = [path for path in s if not new_tree.has_filename(path)]
345
 
    remaining = [path for path in orig_paths if path not in nonexistent]
 
368
    remaining   = [path for path in orig_paths if not path in nonexistent]
346
369
    # Sorting the 'remaining' list doesn't have much effect in
347
370
    # practice, since the various status output sections will sort
348
371
    # their groups individually.  But for consistency of this
363
386
        These are all empty initially, because by default nothing should get
364
387
        notified.
365
388
        """
366
 
        _mod_hooks.Hooks.__init__(self, "breezy.status", "hooks")
367
 
        self.add_hook(
368
 
            'post_status',
 
389
        _mod_hooks.Hooks.__init__(self, "brzlib.status", "hooks")
 
390
        self.add_hook('post_status',
369
391
            "Called with argument StatusHookParams after Bazaar has "
370
392
            "displayed the status. StatusHookParams has the attributes "
371
393
            "(old_tree, new_tree, to_file, versioned, show_ids, short, "
373
395
            "line options specified by the user for the status command. "
374
396
            "to_file is the output stream for writing.",
375
397
            (2, 3))
376
 
        self.add_hook(
377
 
            'pre_status',
 
398
        self.add_hook('pre_status',
378
399
            "Called with argument StatusHookParams before Bazaar "
379
400
            "displays the status. StatusHookParams has the attributes "
380
401
            "(old_tree, new_tree, to_file, versioned, show_ids, short, "
397
418
    """
398
419
 
399
420
    def __init__(self, old_tree, new_tree, to_file, versioned, show_ids,
400
 
                 short, verbose, specific_files=None):
 
421
            short, verbose, specific_files=None):
401
422
        """Create a group of post_status hook parameters.
402
423
 
403
424
        :param old_tree: Start tree (basis tree) for comparison.
408
429
        :param short: Use short status indicators.
409
430
        :param verbose: Verbose flag.
410
431
        :param specific_files: If set, a list of filenames whose status should be
411
 
            shown.  It is an error to give a filename that is not in the
412
 
            working tree, or in the working inventory or in the basis inventory.
 
432
            shown.  It is an error to give a filename that is not in the working
 
433
            tree, or in the working inventory or in the basis inventory.
413
434
        """
414
435
        self.old_tree = old_tree
415
436
        self.new_tree = new_tree
424
445
        return self.__dict__ == other.__dict__
425
446
 
426
447
    def __repr__(self):
427
 
        return "<%s(%s, %s, %s, %s, %s, %s, %s, %s)>" % (
428
 
            self.__class__.__name__, self.old_tree, self.new_tree,
429
 
            self.to_file, self.versioned, self.show_ids, self.short,
430
 
            self.verbose, self.specific_files)
 
448
        return "<%s(%s, %s, %s, %s, %s, %s, %s, %s)>" % (self.__class__.__name__,
 
449
            self.old_tree, self.new_tree, self.to_file, self.versioned,
 
450
            self.show_ids, self.short, self.verbose, self.specific_files)
431
451
 
432
452
 
433
453
def _show_shelve_summary(params):
442
462
    get_shelf_manager = getattr(params.new_tree, 'get_shelf_manager', None)
443
463
    if get_shelf_manager is None:
444
464
        return
445
 
    try:
446
 
        manager = get_shelf_manager()
447
 
    except ShelvingUnsupported:
448
 
        mutter('shelving not supported by tree, not displaying shelves.')
449
 
    else:
450
 
        shelves = manager.active_shelves()
451
 
        if shelves:
452
 
            singular = '%d shelf exists. '
453
 
            plural = '%d shelves exist. '
454
 
            if len(shelves) == 1:
455
 
                fmt = singular
456
 
            else:
457
 
                fmt = plural
458
 
            params.to_file.write(fmt % len(shelves))
459
 
            params.to_file.write('See "brz shelve --list" for details.\n')
 
465
    manager = get_shelf_manager()
 
466
    shelves = manager.active_shelves()
 
467
    if shelves:
 
468
        singular = '%d shelf exists. '
 
469
        plural = '%d shelves exist. '
 
470
        if len(shelves) == 1:
 
471
            fmt = singular
 
472
        else:
 
473
            fmt = plural
 
474
        params.to_file.write(fmt % len(shelves))
 
475
        params.to_file.write('See "bzr shelve --list" for details.\n')
460
476
 
461
477
 
462
478
hooks = StatusHooks()
463
479
 
464
480
 
465
481
hooks.install_named_hook('post_status', _show_shelve_summary,
466
 
                         'brz status')
 
482
    'bzr status')
 
483