~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/missing.py

  • Committer: Vincent Ladeuil
  • Date: 2009-06-22 12:52:39 UTC
  • mto: (4471.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4472.
  • Revision ID: v.ladeuil+lp@free.fr-20090622125239-kabo9smxt9c3vnir
Use a consistent scheme for naming pyrex source files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
"""Display what revisions are missing in 'other' from 'this' and vice versa."""
18
18
 
19
 
from bzrlib.log import (
20
 
    LogRevision,
 
19
from bzrlib import (
 
20
    log,
 
21
    repository as _mod_repository,
 
22
    tsort,
21
23
    )
 
24
import bzrlib.revision as _mod_revision
22
25
 
23
26
 
24
27
def iter_log_revisions(revisions, revision_source, verbose):
25
 
    last_tree = revision_source.revision_tree(None)
 
28
    last_tree = revision_source.revision_tree(_mod_revision.NULL_REVISION)
26
29
    last_rev_id = None
27
 
    for revno, rev_id in revisions:
 
30
    for rev in revisions:
 
31
        # We need the following for backward compatibilty (hopefully
 
32
        # this will be deprecated soon :-/) -- vila 080911
 
33
        if len(rev) == 2:
 
34
            revno, rev_id = rev
 
35
            merge_depth = 0
 
36
        else:
 
37
            revno, rev_id, merge_depth = rev
28
38
        rev = revision_source.get_revision(rev_id)
29
39
        if verbose:
30
 
            remote_tree = revision_source.revision_tree(rev_id)
31
 
            parent_rev_id = rev.parent_ids[0]
32
 
            if last_rev_id == parent_rev_id:
33
 
                parent_tree = last_tree
34
 
            else:
35
 
                parent_tree = revision_source.revision_tree(parent_rev_id)
36
 
            revision_tree = revision_source.revision_tree(rev_id)
37
 
            last_rev_id = rev_id
38
 
            last_tree = revision_tree
39
 
            delta = revision_tree.changes_from(parent_tree)
 
40
            delta = revision_source.get_revision_delta(rev_id)
40
41
        else:
41
42
            delta = None
42
 
        yield LogRevision(rev, revno, delta=delta)
43
 
 
44
 
 
45
 
def find_unmerged(local_branch, remote_branch, restrict='all'):
 
43
        yield log.LogRevision(rev, revno, merge_depth, delta=delta)
 
44
 
 
45
 
 
46
def find_unmerged(local_branch, remote_branch, restrict='all',
 
47
                  include_merges=False, backward=False,
 
48
                  local_revid_range=None, remote_revid_range=None):
46
49
    """Find revisions from each side that have not been merged.
47
50
 
48
51
    :param local_branch: Compare the history of local_branch
52
55
        unique revisions from both sides. If 'local', we will return None
53
56
        for the remote revisions, similarly if 'remote' we will return None for
54
57
        the local revisions.
 
58
    :param include_merges: Show mainline revisions only if False,
 
59
        all revisions otherwise.
 
60
    :param backward: Show oldest versions first when True, newest versions
 
61
        first when False.
 
62
    :param local_revid_range: Revision-id range for filtering local_branch
 
63
        revisions (lower bound, upper bound)
 
64
    :param remote_revid_range: Revision-id range for filtering remote_branch
 
65
        revisions (lower bound, upper bound)
55
66
 
56
67
    :return: A list of [(revno, revision_id)] for the mainline revisions on
57
68
        each side.
60
71
    try:
61
72
        remote_branch.lock_read()
62
73
        try:
63
 
            return _find_unmerged(local_branch,
64
 
                remote_branch, restrict=restrict)
 
74
            return _find_unmerged(
 
75
                local_branch, remote_branch, restrict=restrict,
 
76
                include_merges=include_merges, backward=backward,
 
77
                local_revid_range=local_revid_range,
 
78
                remote_revid_range=remote_revid_range)
65
79
        finally:
66
80
            remote_branch.unlock()
67
81
    finally:
68
82
        local_branch.unlock()
69
83
 
70
84
 
71
 
def _enumerate_mainline(ancestry, graph, tip_revno, tip):
 
85
def _enumerate_mainline(ancestry, graph, tip_revno, tip, backward=True):
72
86
    """Enumerate the mainline revisions for these revisions.
73
87
 
74
88
    :param ancestry: A set of revisions that we care about
75
89
    :param graph: A Graph which lets us find the parents for a revision
76
90
    :param tip_revno: The revision number for the tip revision
77
91
    :param tip: The tip of mainline
 
92
    :param backward: Show oldest versions first when True, newest versions
 
93
        first when False.
78
94
    :return: [(revno, revision_id)] for all revisions in ancestry that
79
95
        are left-hand parents from tip, or None if ancestry is None.
80
96
    """
95
111
        parents = parent_map.get(cur)
96
112
        if not parents:
97
113
            break # Ghost, we are done
98
 
        mainline.append((cur_revno, cur))
 
114
        mainline.append((str(cur_revno), cur))
99
115
        cur = parents[0]
100
116
        cur_revno -= 1
101
 
    mainline.reverse()
 
117
    if not backward:
 
118
        mainline.reverse()
102
119
    return mainline
103
120
 
104
121
 
105
 
def _find_unmerged(local_branch, remote_branch, restrict):
 
122
def _enumerate_with_merges(branch, ancestry, graph, tip_revno, tip,
 
123
                           backward=True):
 
124
    """Enumerate the revisions for the ancestry.
 
125
 
 
126
    :param branch: The branch we care about
 
127
    :param ancestry: A set of revisions that we care about
 
128
    :param graph: A Graph which lets us find the parents for a revision
 
129
    :param tip_revno: The revision number for the tip revision
 
130
    :param tip: The tip of the ancsetry
 
131
    :param backward: Show oldest versions first when True, newest versions
 
132
        first when False.
 
133
    :return: [(revno, revision_id)] for all revisions in ancestry that
 
134
        are parents from tip, or None if ancestry is None.
 
135
    """
 
136
    if ancestry is None:
 
137
        return None
 
138
    if not ancestry: #Empty ancestry, no need to do any work
 
139
        return []
 
140
 
 
141
    mainline_revs, rev_nos, start_rev_id, end_rev_id = log._get_mainline_revs(
 
142
        branch, None, tip_revno)
 
143
    if not mainline_revs:
 
144
        return []
 
145
 
 
146
    # This asks for all mainline revisions, which is size-of-history and
 
147
    # should be addressed (but currently the only way to get correct
 
148
    # revnos).
 
149
 
 
150
    # mainline_revisions always includes an extra revision at the
 
151
    # beginning, so don't request it.
 
152
    parent_map = dict(((key, value) for key, value
 
153
                       in graph.iter_ancestry(mainline_revs[1:])
 
154
                       if value is not None))
 
155
    # filter out ghosts; merge_sort errors on ghosts.
 
156
    # XXX: is this needed here ? -- vila080910
 
157
    rev_graph = _mod_repository._strip_NULL_ghosts(parent_map)
 
158
    # XXX: what if rev_graph is empty now ? -- vila080910
 
159
    merge_sorted_revisions = tsort.merge_sort(rev_graph, tip,
 
160
                                              mainline_revs,
 
161
                                              generate_revno=True)
 
162
    # Now that we got the correct revnos, keep only the relevant
 
163
    # revisions.
 
164
    merge_sorted_revisions = [
 
165
        (s, revid, n, d, e) for s, revid, n, d, e in merge_sorted_revisions
 
166
        if revid in ancestry]
 
167
    if not backward:
 
168
        merge_sorted_revisions = log.reverse_by_depth(merge_sorted_revisions)
 
169
    revline = []
 
170
    for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
 
171
        revline.append(('.'.join(map(str, revno)), rev_id, merge_depth))
 
172
    return revline
 
173
 
 
174
 
 
175
def _filter_revs(graph, revs, revid_range):
 
176
    if revid_range is None or revs is None:
 
177
        return revs
 
178
    return [rev for rev in revs
 
179
        if graph.is_between(rev[1], revid_range[0], revid_range[1])]
 
180
 
 
181
 
 
182
def _find_unmerged(local_branch, remote_branch, restrict,
 
183
                   include_merges, backward,
 
184
                   local_revid_range=None, remote_revid_range=None):
106
185
    """See find_unmerged.
107
186
 
108
187
    The branches should already be locked before entering.
112
191
    if local_revno == remote_revno and local_revision_id == remote_revision_id:
113
192
        # A simple shortcut when the tips are at the same point
114
193
        return [], []
115
 
    graph = local_branch.repository.get_graph(
116
 
                remote_branch.repository)
 
194
    graph = local_branch.repository.get_graph(remote_branch.repository)
117
195
    if restrict == 'remote':
118
196
        local_extra = None
119
 
        remote_extra = graph.find_unique_ancestors(
120
 
            remote_revision_id, [local_revision_id])
 
197
        remote_extra = graph.find_unique_ancestors(remote_revision_id,
 
198
                                                   [local_revision_id])
121
199
    elif restrict == 'local':
122
200
        remote_extra = None
123
 
        local_extra = graph.find_unique_ancestors(
124
 
            local_revision_id, [remote_revision_id])
 
201
        local_extra = graph.find_unique_ancestors(local_revision_id,
 
202
                                                  [remote_revision_id])
125
203
    else:
126
204
        if restrict != 'all':
127
205
            raise ValueError('param restrict not one of "all", "local",'
128
206
                             ' "remote": %r' % (restrict,))
129
 
        local_extra, remote_extra = graph.find_difference(
130
 
            local_revision_id, remote_revision_id)
131
 
    # Now that we have unique ancestors, compute just the mainline, and
132
 
    # generate revnos for them.
133
 
    local_mainline = _enumerate_mainline(local_extra, graph, local_revno,
134
 
                                         local_revision_id)
135
 
    remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
136
 
                                          remote_revision_id)
137
 
    return local_mainline, remote_mainline
 
207
        local_extra, remote_extra = graph.find_difference(local_revision_id,
 
208
                                                          remote_revision_id)
 
209
    if include_merges:
 
210
        locals = _enumerate_with_merges(local_branch, local_extra,
 
211
                                        graph, local_revno,
 
212
                                        local_revision_id, backward)
 
213
        remotes = _enumerate_with_merges(remote_branch, remote_extra,
 
214
                                         graph, remote_revno,
 
215
                                         remote_revision_id, backward)
 
216
    else:
 
217
        # Now that we have unique ancestors, compute just the mainline, and
 
218
        # generate revnos for them.
 
219
        locals = _enumerate_mainline(local_extra, graph, local_revno,
 
220
                                     local_revision_id, backward)
 
221
        remotes = _enumerate_mainline(remote_extra, graph, remote_revno,
 
222
                                      remote_revision_id, backward)
 
223
    return _filter_revs(graph, locals, local_revid_range), _filter_revs(graph,
 
224
        remotes, remote_revid_range)
138
225
 
139
226
 
140
227
def sorted_revisions(revisions, history_map):