~lifeless/bzr/index.range_map

« back to all changes in this revision

Viewing changes to bzrlib/status.py

  • Committer: Robert Collins
  • Date: 2008-06-19 01:17:19 UTC
  • mfrom: (3218.1.277 +trunk)
  • Revision ID: robertc@robertcollins.net-20080619011719-1c4g4uxzzhdls2wf
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
from bzrlib import (
20
20
    delta as _mod_delta,
 
21
    log,
 
22
    osutils,
21
23
    tree,
 
24
    tsort,
 
25
    revision as _mod_revision,
22
26
    )
23
27
from bzrlib.diff import _raise_if_nonexistent
24
28
import bzrlib.errors as errors
25
 
from bzrlib.log import line_log
26
29
from bzrlib.osutils import is_inside_any
27
30
from bzrlib.symbol_versioning import (deprecated_function,
28
31
        )
60
63
    :param show_ids: If set, includes each file's id.
61
64
    :param to_file: If set, write to this file (default stdout.)
62
65
    :param show_pending: If set, write pending merges.
63
 
    :param revision: If None the compare latest revision with working tree
64
 
        If not None it must be a RevisionSpec list.
65
 
        If one revision show compared it with working tree.
66
 
        If two revisions show status between first and second.
 
66
    :param revision: If None, compare latest revision with working tree
 
67
        If not None, it must be a RevisionSpec list.
 
68
        If one revision, compare with working tree.
 
69
        If two revisions, show status between first and second.
67
70
    :param short: If True, gives short SVN-style status lines.
68
71
    :param versioned: If True, only shows versioned files.
69
72
    """
70
73
    if show_unchanged is not None:
71
 
        warn("show_status_trees with show_unchanged has been deprecated "
 
74
        warn("show_tree_status with show_unchanged has been deprecated "
72
75
             "since bzrlib 0.9", DeprecationWarning, stacklevel=2)
73
76
 
74
77
    if to_file is None:
84
87
            old = new.basis_tree()
85
88
        elif len(revision) > 0:
86
89
            try:
87
 
                rev_id = revision[0].in_history(wt.branch).rev_id
 
90
                rev_id = revision[0].as_revision_id(wt.branch)
88
91
                old = wt.branch.repository.revision_tree(rev_id)
89
92
            except errors.NoSuchRevision, e:
90
93
                raise errors.BzrCommandError(str(e))
91
94
            if (len(revision) > 1) and (revision[1].spec is not None):
92
95
                try:
93
 
                    rev_id = revision[1].in_history(wt.branch).rev_id
 
96
                    rev_id = revision[1].as_revision_id(wt.branch)
94
97
                    new = wt.branch.repository.revision_tree(rev_id)
95
98
                    new_is_working_tree = False
96
99
                except errors.NoSuchRevision, e:
103
106
            _raise_if_nonexistent(specific_files, old, new)
104
107
            want_unversioned = not versioned
105
108
            if short:
106
 
                changes = new._iter_changes(old, show_unchanged, specific_files,
 
109
                changes = new.iter_changes(old, show_unchanged, specific_files,
107
110
                    require_versioned=False, want_unversioned=want_unversioned)
108
111
                reporter = _mod_delta._ChangeReporter(output_file=to_file,
109
112
                    unversioned_filter=new.is_ignored)
134
137
                else:
135
138
                    prefix = ' '
136
139
                to_file.write("%s %s\n" % (prefix, conflict))
137
 
            if new_is_working_tree and show_pending:
 
140
            if (new_is_working_tree and show_pending
 
141
                and specific_files is None):
138
142
                show_pending_merges(new, to_file, short)
139
143
        finally:
140
144
            old.unlock()
142
146
    finally:
143
147
        wt.unlock()
144
148
 
 
149
 
 
150
def _get_sorted_revisions(tip_revision, revision_ids, parent_map):
 
151
    """Get an iterator which will return the revisions in merge sorted order.
 
152
 
 
153
    This will build up a list of all nodes, such that only nodes in the list
 
154
    are referenced. It then uses MergeSorter to return them in 'merge-sorted'
 
155
    order.
 
156
 
 
157
    :param revision_ids: A set of revision_ids
 
158
    :param parent_map: The parent information for each node. Revisions which
 
159
        are considered ghosts should not be present in the map.
 
160
    :return: iterator from MergeSorter.iter_topo_order()
 
161
    """
 
162
    # MergeSorter requires that all nodes be present in the graph, so get rid
 
163
    # of any references pointing outside of this graph.
 
164
    parent_graph = {}
 
165
    for revision_id in revision_ids:
 
166
        if revision_id not in parent_map: # ghost
 
167
            parent_graph[revision_id] = []
 
168
        else:
 
169
            # Only include parents which are in this sub-graph
 
170
            parent_graph[revision_id] = [p for p in parent_map[revision_id]
 
171
                                            if p in revision_ids]
 
172
    sorter = tsort.MergeSorter(parent_graph, tip_revision)
 
173
    return sorter.iter_topo_order()
 
174
 
 
175
 
145
176
def show_pending_merges(new, to_file, short=False):
146
177
    """Write out a display of pending merges in a working tree."""
147
178
    parents = new.get_parent_ids()
148
179
    if len(parents) < 2:
149
180
        return
 
181
 
 
182
    # we need one extra space for terminals that wrap on last char
 
183
    term_width = osutils.terminal_width() - 1
 
184
    if short:
 
185
        first_prefix = 'P   '
 
186
        sub_prefix = 'P.   '
 
187
    else:
 
188
        first_prefix = '  '
 
189
        sub_prefix = '    '
 
190
 
150
191
    pending = parents[1:]
151
192
    branch = new.branch
152
193
    last_revision = parents[0]
153
194
    if not short:
154
195
        to_file.write('pending merges:\n')
155
 
    if last_revision is not None:
156
 
        try:
157
 
            ignore = set(branch.repository.get_ancestry(last_revision,
158
 
                                                        topo_sorted=False))
159
 
        except errors.NoSuchRevision:
160
 
            # the last revision is a ghost : assume everything is new 
161
 
            # except for it
162
 
            ignore = set([None, last_revision])
163
 
    else:
164
 
        ignore = set([None])
165
 
    # TODO: this could be improved using merge_sorted - we'd get the same 
166
 
    # output rather than one level of indent.
 
196
    graph = branch.repository.get_graph()
 
197
    other_revisions = [last_revision]
 
198
    log_formatter = log.LineLogFormatter(to_file)
167
199
    for merge in pending:
168
 
        ignore.add(merge)
169
 
        try:
170
 
            from bzrlib.osutils import terminal_width
171
 
            width = terminal_width() - 1    # we need one extra space to avoid
172
 
                                            # extra blank lines
173
 
            m_revision = branch.repository.get_revision(merge)
174
 
            if short:
175
 
                prefix = 'P   '
176
 
            else:
177
 
                prefix = '  '
178
 
            to_file.write(prefix)
179
 
            to_file.write(line_log(m_revision, width - len(prefix)))
180
 
            to_file.write('\n')
181
 
            inner_merges = branch.repository.get_ancestry(merge)
182
 
            assert inner_merges[0] is None
183
 
            inner_merges.pop(0)
184
 
            inner_merges.reverse()
185
 
            for mmerge in inner_merges:
186
 
                if mmerge in ignore:
187
 
                    continue
188
 
                mm_revision = branch.repository.get_revision(mmerge)
189
 
                if short:
190
 
                    prefix = 'P.   '
 
200
        try:
 
201
            rev = branch.repository.get_revisions([merge])[0]
 
202
        except errors.NoSuchRevision:
 
203
            # If we are missing a revision, just print out the revision id
 
204
            to_file.write(first_prefix + '(ghost) ' + merge + '\n')
 
205
            other_revisions.append(merge)
 
206
            continue
 
207
 
 
208
        # Log the merge, as it gets a slightly different formatting
 
209
        log_message = log_formatter.log_string(None, rev,
 
210
                        term_width - len(first_prefix))
 
211
        to_file.write(first_prefix + log_message + '\n')
 
212
        # Find all of the revisions in the merge source, which are not in the
 
213
        # last committed revision.
 
214
        merge_extra = graph.find_unique_ancestors(merge, other_revisions)
 
215
        other_revisions.append(merge)
 
216
        merge_extra.discard(_mod_revision.NULL_REVISION)
 
217
 
 
218
        # Get a handle to all of the revisions we will need
 
219
        try:
 
220
            revisions = dict((rev.revision_id, rev) for rev in
 
221
                             branch.repository.get_revisions(merge_extra))
 
222
        except errors.NoSuchRevision:
 
223
            # One of the sub nodes is a ghost, check each one
 
224
            revisions = {}
 
225
            for revision_id in merge_extra:
 
226
                try:
 
227
                    rev = branch.repository.get_revisions([revision_id])[0]
 
228
                except errors.NoSuchRevision:
 
229
                    revisions[revision_id] = None
191
230
                else:
192
 
                    prefix = '    '
193
 
                to_file.write(prefix)
194
 
                to_file.write(line_log(mm_revision, width - len(prefix)))
195
 
                to_file.write('\n')
196
 
                ignore.add(mmerge)
197
 
        except errors.NoSuchRevision:
198
 
            if short:
199
 
                prefix = 'P  '
200
 
            else:
201
 
                prefix = ' '
202
 
            to_file.write(prefix + ' ' + merge)
203
 
            to_file.write('\n')
 
231
                    revisions[revision_id] = rev
 
232
 
 
233
        # Display the revisions brought in by this merge.
 
234
        rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
 
235
                            branch.repository.get_parent_map(merge_extra))
 
236
        # Skip the first node
 
237
        num, first, depth, eom = rev_id_iterator.next()
 
238
        if first != merge:
 
239
            raise AssertionError('Somehow we misunderstood how'
 
240
                ' iter_topo_order works %s != %s' % (first, merge))
 
241
        for num, sub_merge, depth, eom in rev_id_iterator:
 
242
            rev = revisions[sub_merge]
 
243
            if rev is None:
 
244
                to_file.write(sub_prefix + '(ghost) ' + sub_merge + '\n')
 
245
                continue
 
246
            log_message = log_formatter.log_string(None,
 
247
                            revisions[sub_merge],
 
248
                            term_width - len(sub_prefix))
 
249
            to_file.write(sub_prefix + log_message + '\n')