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

  • Committer: Martin von Gagern
  • Date: 2010-04-20 08:47:38 UTC
  • mfrom: (5167 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5195.
  • Revision ID: martin.vgagern@gmx.net-20100420084738-ygymnqmdllzrhpfn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import sys
18
18
 
24
24
    tsort,
25
25
    revision as _mod_revision,
26
26
    )
27
 
from bzrlib.diff import _raise_if_nonexistent
28
27
import bzrlib.errors as errors
29
28
from bzrlib.osutils import is_inside_any
30
29
from bzrlib.symbol_versioning import (deprecated_function,
31
30
        )
32
 
from bzrlib.trace import warning
 
31
from bzrlib.trace import mutter, warning
33
32
 
34
33
# TODO: when showing single-line logs, truncate to the width of the terminal
35
34
# if known, but only if really going to the terminal (not into a file)
36
35
 
37
36
 
 
37
def report_changes(to_file, old, new, specific_files, 
 
38
                   show_short_reporter, show_long_callback, 
 
39
                   short=False, want_unchanged=False, 
 
40
                   want_unversioned=False, show_ids=False):
 
41
    """Display summary of changes.
 
42
 
 
43
    This compares two trees with regards to a list of files, and delegates 
 
44
    the display to underlying elements.
 
45
 
 
46
    For short output, it creates an iterator on all changes, and lets a given
 
47
    reporter display these changes.
 
48
 
 
49
    For stantard output, it creates a delta of the changes, and forwards it
 
50
    to a callback
 
51
 
 
52
    :param to_file: If set, write to this file (default stdout.)
 
53
    :param old: Start tree for the comparison
 
54
    :param end: End tree for the comparison
 
55
    :param specific_files: If set, a list of filenames whose status should be
 
56
        shown.  It is an error to give a filename that is not in the working
 
57
        tree, or in the working inventory or in the basis inventory.
 
58
    :param show_short_reporter: Reporter in charge of display for short output
 
59
    :param show_long_callback: Callback in charge of display for normal output
 
60
    :param short: If True, gives short SVN-style status lines.
 
61
    :param want_unchanged: Deprecated parameter. If set, includes unchanged
 
62
        files.
 
63
    :param show_ids: If set, includes each file's id.
 
64
    :param want_unversioned: If False, only shows versioned files.
 
65
    """
 
66
 
 
67
    if short:
 
68
        changes = new.iter_changes(old, want_unchanged, specific_files,
 
69
            require_versioned=False, want_unversioned=want_unversioned)
 
70
        _mod_delta.report_changes(changes, show_short_reporter)
 
71
        
 
72
    else:
 
73
        delta = new.changes_from(old, want_unchanged=want_unchanged,
 
74
                              specific_files=specific_files,
 
75
                              want_unversioned=want_unversioned)
 
76
        # filter out unknown files. We may want a tree method for
 
77
        # this
 
78
        delta.unversioned = [unversioned for unversioned in
 
79
            delta.unversioned if not new.is_ignored(unversioned[0])]
 
80
        show_long_callback(to_file, delta, 
 
81
                           show_ids=show_ids,
 
82
                           show_unchanged=want_unchanged)
 
83
 
 
84
 
38
85
def show_tree_status(wt, show_unchanged=None,
39
86
                     specific_files=None,
40
87
                     show_ids=False,
42
89
                     show_pending=True,
43
90
                     revision=None,
44
91
                     short=False,
45
 
                     versioned=False):
 
92
                     verbose=False,
 
93
                     versioned=False,
 
94
                     show_long_callback=_mod_delta.report_delta):
46
95
    """Display summary of changes.
47
96
 
48
 
    By default this compares the working tree to a previous revision. 
49
 
    If the revision argument is given, summarizes changes between the 
 
97
    By default this compares the working tree to a previous revision.
 
98
    If the revision argument is given, summarizes changes between the
50
99
    working tree and another, or between two revisions.
51
100
 
52
 
    The result is written out as Unicode and to_file should be able 
 
101
    The result is written out as Unicode and to_file should be able
53
102
    to encode that.
54
103
 
55
104
    If showing the status of a working tree, extra information is included
56
105
    about unknown files, conflicts, and pending merges.
57
106
 
58
 
    :param show_unchanged: Deprecated parameter. If set, includes unchanged 
 
107
    :param show_unchanged: Deprecated parameter. If set, includes unchanged
59
108
        files.
60
109
    :param specific_files: If set, a list of filenames whose status should be
61
 
        shown.  It is an error to give a filename that is not in the working 
 
110
        shown.  It is an error to give a filename that is not in the working
62
111
        tree, or in the working inventory or in the basis inventory.
63
112
    :param show_ids: If set, includes each file's id.
64
113
    :param to_file: If set, write to this file (default stdout.)
68
117
        If one revision, compare with working tree.
69
118
        If two revisions, show status between first and second.
70
119
    :param short: If True, gives short SVN-style status lines.
 
120
    :param verbose: If True, show all merged revisions, not just
 
121
        the merge tips
71
122
    :param versioned: If True, only shows versioned files.
 
123
    :param show_long_callback: A callback: message = show_long_callback(to_file, delta, 
 
124
        show_ids, show_unchanged, indent, filter), only used with the long output
72
125
    """
73
126
    if show_unchanged is not None:
74
127
        warn("show_tree_status with show_unchanged has been deprecated "
76
129
 
77
130
    if to_file is None:
78
131
        to_file = sys.stdout
79
 
    
 
132
 
80
133
    wt.lock_read()
81
134
    try:
82
135
        new_is_working_tree = True
101
154
        old.lock_read()
102
155
        new.lock_read()
103
156
        try:
104
 
            _raise_if_nonexistent(specific_files, old, new)
 
157
            specific_files, nonexistents \
 
158
                = _filter_nonexistent(specific_files, old, new)
105
159
            want_unversioned = not versioned
106
 
            if short:
107
 
                changes = new.iter_changes(old, show_unchanged, specific_files,
108
 
                    require_versioned=False, want_unversioned=want_unversioned)
109
 
                reporter = _mod_delta._ChangeReporter(output_file=to_file,
110
 
                    unversioned_filter=new.is_ignored)
111
 
                _mod_delta.report_changes(changes, reporter)
112
 
            else:
113
 
                delta = new.changes_from(old, want_unchanged=show_unchanged,
114
 
                                      specific_files=specific_files,
115
 
                                      want_unversioned=want_unversioned)
116
 
                # filter out unknown files. We may want a tree method for
117
 
                # this
118
 
                delta.unversioned = [unversioned for unversioned in
119
 
                    delta.unversioned if not new.is_ignored(unversioned[0])]
120
 
                delta.show(to_file,
121
 
                           show_ids=show_ids,
122
 
                           show_unchanged=show_unchanged,
123
 
                           short_status=False)
 
160
 
 
161
            # Reporter used for short outputs
 
162
            reporter = _mod_delta._ChangeReporter(output_file=to_file,
 
163
                unversioned_filter=new.is_ignored)
 
164
            report_changes(to_file, old, new, specific_files, 
 
165
                           reporter, show_long_callback, 
 
166
                           short=short, want_unchanged=show_unchanged, 
 
167
                           want_unversioned=want_unversioned, show_ids=show_ids)
 
168
 
 
169
            # show the ignored files among specific files (i.e. show the files
 
170
            # identified from input that we choose to ignore). 
 
171
            if specific_files is not None:
 
172
                # Ignored files is sorted because specific_files is already sorted
 
173
                ignored_files = [specific for specific in
 
174
                    specific_files if new.is_ignored(specific)]
 
175
                if len(ignored_files) > 0 and not short:
 
176
                    to_file.write("ignored:\n")
 
177
                    prefix = ' '
 
178
                else:
 
179
                    prefix = 'I  '
 
180
                for ignored_file in ignored_files:
 
181
                    to_file.write("%s %s\n" % (prefix, ignored_file))
 
182
 
124
183
            # show the new conflicts only for now. XXX: get them from the
125
184
            # delta.
126
185
            conflicts = new.conflicts()
135
194
                else:
136
195
                    prefix = ' '
137
196
                to_file.write("%s %s\n" % (prefix, conflict))
 
197
            # Show files that were requested but don't exist (and are
 
198
            # not versioned).  We don't involve delta in this; these
 
199
            # paths are really the province of just the status
 
200
            # command, since they have more to do with how it was
 
201
            # invoked than with the tree it's operating on.
 
202
            if nonexistents and not short:
 
203
                to_file.write("nonexistent:\n")
 
204
            for nonexistent in nonexistents:
 
205
                # We could calculate prefix outside the loop but, given
 
206
                # how rarely this ought to happen, it's OK and arguably
 
207
                # slightly faster to do it here (ala conflicts above)
 
208
                if short:
 
209
                    prefix = 'X  '
 
210
                else:
 
211
                    prefix = ' '
 
212
                to_file.write("%s %s\n" % (prefix, nonexistent))
138
213
            if (new_is_working_tree and show_pending):
139
 
                show_pending_merges(new, to_file, short)
 
214
                show_pending_merges(new, to_file, short, verbose=verbose)
 
215
            if nonexistents:
 
216
                raise errors.PathsDoNotExist(nonexistents)
140
217
        finally:
141
218
            old.unlock()
142
219
            new.unlock()
170
247
    return sorter.iter_topo_order()
171
248
 
172
249
 
173
 
def show_pending_merges(new, to_file, short=False):
 
250
def show_pending_merges(new, to_file, short=False, verbose=False):
174
251
    """Write out a display of pending merges in a working tree."""
175
252
    parents = new.get_parent_ids()
176
253
    if len(parents) < 2:
177
254
        return
178
255
 
179
 
    # we need one extra space for terminals that wrap on last char
180
 
    term_width = osutils.terminal_width() - 1
 
256
    term_width = osutils.terminal_width()
 
257
    if term_width is not None:
 
258
        # we need one extra space for terminals that wrap on last char
 
259
        term_width = term_width - 1
181
260
    if short:
182
261
        first_prefix = 'P   '
183
262
        sub_prefix = 'P.   '
185
264
        first_prefix = '  '
186
265
        sub_prefix = '    '
187
266
 
 
267
    def show_log_message(rev, prefix):
 
268
        if term_width is None:
 
269
            width = term_width
 
270
        else:
 
271
            width = term_width - len(prefix)
 
272
        log_message = log_formatter.log_string(None, rev, width, prefix=prefix)
 
273
        to_file.write(log_message + '\n')
 
274
 
188
275
    pending = parents[1:]
189
276
    branch = new.branch
190
277
    last_revision = parents[0]
191
278
    if not short:
192
 
        to_file.write('pending merges:\n')
 
279
        if verbose:
 
280
            to_file.write('pending merges:\n')
 
281
        else:
 
282
            to_file.write('pending merge tips:'
 
283
                          ' (use -v to see all merge revisions)\n')
193
284
    graph = branch.repository.get_graph()
194
285
    other_revisions = [last_revision]
195
286
    log_formatter = log.LineLogFormatter(to_file)
203
294
            continue
204
295
 
205
296
        # Log the merge, as it gets a slightly different formatting
206
 
        log_message = log_formatter.log_string(None, rev,
207
 
                        term_width - len(first_prefix))
208
 
        to_file.write(first_prefix + log_message + '\n')
 
297
        show_log_message(rev, first_prefix)
 
298
        if not verbose:
 
299
            continue
 
300
 
209
301
        # Find all of the revisions in the merge source, which are not in the
210
302
        # last committed revision.
211
303
        merge_extra = graph.find_unique_ancestors(merge, other_revisions)
240
332
            if rev is None:
241
333
                to_file.write(sub_prefix + '(ghost) ' + sub_merge + '\n')
242
334
                continue
243
 
            log_message = log_formatter.log_string(None,
244
 
                            revisions[sub_merge],
245
 
                            term_width - len(sub_prefix))
246
 
            to_file.write(sub_prefix + log_message + '\n')
 
335
            show_log_message(revisions[sub_merge], sub_prefix)
 
336
 
 
337
 
 
338
def _filter_nonexistent(orig_paths, old_tree, new_tree):
 
339
    """Convert orig_paths to two sorted lists and return them.
 
340
 
 
341
    The first is orig_paths paths minus the items in the second list,
 
342
    and the second list is paths that are not in either inventory or
 
343
    tree (they don't qualify if they exist in the tree's inventory, or
 
344
    if they exist in the tree but are not versioned.)
 
345
 
 
346
    If either of the two lists is empty, return it as an empty list.
 
347
 
 
348
    This can be used by operations such as bzr status that can accept
 
349
    unknown or ignored files.
 
350
    """
 
351
    mutter("check paths: %r", orig_paths)
 
352
    if not orig_paths:
 
353
        return orig_paths, []
 
354
    s = old_tree.filter_unversioned_files(orig_paths)
 
355
    s = new_tree.filter_unversioned_files(s)
 
356
    nonexistent = [path for path in s if not new_tree.has_filename(path)]
 
357
    remaining   = [path for path in orig_paths if not path in nonexistent]
 
358
    # Sorting the 'remaining' list doesn't have much effect in
 
359
    # practice, since the various status output sections will sort
 
360
    # their groups individually.  But for consistency of this
 
361
    # function's API, it's better to sort both than just 'nonexistent'.
 
362
    return sorted(remaining), sorted(nonexistent)