1
# Copyright (C) 2005, 2006 Canonical Ltd
 
 
3
# This program is free software; you can redistribute it and/or modify
 
 
4
# it under the terms of the GNU General Public License as published by
 
 
5
# the Free Software Foundation; either version 2 of the License, or
 
 
6
# (at your option) any later version.
 
 
8
# This program is distributed in the hope that it will be useful,
 
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
11
# GNU General Public License for more details.
 
 
13
# You should have received a copy of the GNU General Public License
 
 
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
 
 
17
"""Display what revisions are missing in 'other' from 'this' and vice versa."""
 
 
19
from bzrlib.log import (
 
 
24
def iter_log_revisions(revisions, revision_source, verbose):
 
 
25
    last_tree = revision_source.revision_tree(None)
 
 
27
    for revno, rev_id in revisions:
 
 
28
        rev = revision_source.get_revision(rev_id)
 
 
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
 
 
35
                parent_tree = revision_source.revision_tree(parent_rev_id)
 
 
36
            revision_tree = revision_source.revision_tree(rev_id)
 
 
38
            last_tree = revision_tree
 
 
39
            delta = revision_tree.changes_from(parent_tree)
 
 
42
        yield LogRevision(rev, revno, delta=delta)
 
 
45
def find_unmerged(local_branch, remote_branch, restrict='all'):
 
 
46
    """Find revisions from each side that have not been merged.
 
 
48
    :param local_branch: Compare the history of local_branch
 
 
49
    :param remote_branch: versus the history of remote_branch, and determine
 
 
50
        mainline revisions which have not been merged.
 
 
51
    :param restrict: ('all', 'local', 'remote') If 'all', we will return the
 
 
52
        unique revisions from both sides. If 'local', we will return None
 
 
53
        for the remote revisions, similarly if 'remote' we will return None for
 
 
56
    :return: A list of [(revno, revision_id)] for the mainline revisions on
 
 
59
    local_branch.lock_read()
 
 
61
        remote_branch.lock_read()
 
 
63
            return _find_unmerged(local_branch,
 
 
64
                remote_branch, restrict=restrict)
 
 
66
            remote_branch.unlock()
 
 
71
def _enumerate_mainline(ancestry, graph, tip_revno, tip):
 
 
72
    """Enumerate the mainline revisions for these revisions.
 
 
74
    :param ancestry: A set of revisions that we care about
 
 
75
    :param graph: A Graph which lets us find the parents for a revision
 
 
76
    :param tip_revno: The revision number for the tip revision
 
 
77
    :param tip: The tip of mainline
 
 
78
    :return: [(revno, revision_id)] for all revisions in ancestry that
 
 
79
        are left-hand parents from tip, or None if ancestry is None.
 
 
83
    if not ancestry: #Empty ancestry, no need to do any work
 
 
86
    # Optionally, we could make 1 call to graph.get_parent_map with all
 
 
87
    # ancestors. However that will often check many more parents than we
 
 
88
    # actually need, and the Graph is likely to already have the parents cached
 
 
93
    while cur in ancestry:
 
 
94
        parent_map = graph.get_parent_map([cur])
 
 
95
        parents = parent_map.get(cur)
 
 
97
            break # Ghost, we are done
 
 
98
        mainline.append((cur_revno, cur))
 
 
105
def _find_unmerged(local_branch, remote_branch, restrict):
 
 
106
    """See find_unmerged.
 
 
108
    The branches should already be locked before entering.
 
 
110
    local_revno, local_revision_id = local_branch.last_revision_info()
 
 
111
    remote_revno, remote_revision_id = remote_branch.last_revision_info()
 
 
112
    if local_revno == remote_revno and local_revision_id == remote_revision_id:
 
 
113
        # A simple shortcut when the tips are at the same point
 
 
115
    graph = local_branch.repository.get_graph(
 
 
116
                remote_branch.repository)
 
 
117
    if restrict == 'remote':
 
 
119
        remote_extra = graph.find_unique_ancestors(
 
 
120
            remote_revision_id, [local_revision_id])
 
 
121
    elif restrict == 'local':
 
 
123
        local_extra = graph.find_unique_ancestors(
 
 
124
            local_revision_id, [remote_revision_id])
 
 
126
        if restrict != 'all':
 
 
127
            raise ValueError('param restrict not one of "all", "local",'
 
 
128
                             ' "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,
 
 
135
    remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
 
 
137
    return local_mainline, remote_mainline
 
 
140
def sorted_revisions(revisions, history_map):
 
 
141
    revisions = [(history_map[r],r) for r in revisions]