~bzr-pqm/bzr/bzr.dev

974.1.68 by Aaron Bentley
Added GPL notice
1
# (C) 2005 Canonical
2
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.
7
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.
12
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
16
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
17
def max_distance(node, ancestors, distances):
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
18
    """Calculate the max distance to an ancestor.  
19
    Return None if not all possible ancestors have known distances"""
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
20
    best = None
21
    if node in distances:
22
        best = distances[node]
23
    for ancestor in ancestors[node]:
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
24
        # An ancestor which is not listed in ancestors will never be in
25
        # distances, so we pretend it never existed.
974.1.64 by Aaron Bentley
Handled ancestors that are missing when finding a base
26
        if ancestor not in ancestors:
27
            continue
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
28
        if ancestor not in distances:
29
            return None
30
        if best is None or distances[ancestor] > best:
31
            best = distances[ancestor] + 1
32
    return best
33
34
    
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
35
def farthest_nodes(graph, ancestors, start):
36
    """Produce a list of nodes, sorted by distance from a start node.
37
    This is an algorithm devised by Aaron Bentley, because applying Dijkstra
38
    backwards seemed too complicated.
39
40
    For each node, we walk its descendants.  If all the descendant's ancestors
41
    have a max-distance-to-start, (excluding ones that can never reach start),
42
    we calculate their max-distance-to-start, and schedule their descendants.
43
44
    So when a node's last parent acquires a distance, it will acquire a
45
    distance on the next iteration.
46
47
    Once we know the max distances for all nodes, we can return a list sorted
48
    by distance, farthest first.
49
    """
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
50
    distances = {start: 0}
974.1.60 by aaron.bentley at utoronto
Initial import of common-ancestor detection
51
    lines = set([start])
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
52
    while len(lines) > 0:
53
        new_lines = set()
54
        for line in lines:
974.1.62 by Aaron Bentley
Added farthest_node sanity checks
55
            assert line not in graph[line], "%s refers to itself" % line
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
56
            for descendant in graph[line]:
57
                distance = max_distance(descendant, ancestors, distances)
58
                if distance is None:
59
                    continue
60
                distances[descendant] = distance
61
                new_lines.add(descendant)
62
        lines = new_lines
63
64
    def by_distance(n):
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
65
        return distances[n],n
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
66
    node_list = distances.keys()
67
    node_list.sort(key=by_distance, reverse=True)
68
    return node_list