3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from __future__ import print_function
15 from cmframework.apis import cmerror
18 class TopSort(object):
20 This class implements a topological sort algorithm.
22 It expects a dependency graph as an input and returns a sorted list as an
23 output. The returned list contains lists sorted accordingly to the dependency
27 # The following graph indicates that 2 depends on 11, 9 depends on 11,8,10 and so on...
39 except cmerror.CMError as exp:
40 print('Got exception %s' % str(exp))
42 The above example will generate the following output:
49 def __init__(self, graph):
52 self.recursionlevel = 0
54 def _get_dependent_entries(self, entry):
56 for e, deps in self.graph.iteritems():
61 def _update_dependent_entries(self, entry):
62 maximumrecursion = (len(self.graph)) * (len(self.graph))
63 if (self.recursionlevel + 1) >= maximumrecursion:
64 raise cmerror.CMError('cyclic dependency detected, graph %r' % self.graph)
65 self.recursionlevel += 1
66 dependententries = self._get_dependent_entries(entry)
67 entrydepth = self.output[entry]
68 for e in dependententries:
70 if entrydepth >= self.output[e]:
71 self.output[e] = entrydepth + 1
72 self._update_dependent_entries(e)
75 for entry, deps in self.graph.iteritems():
77 if entry in self.output:
78 depth = self.output[entry]
80 # calculate new depth according to dependencies
83 if dep in self.output:
84 weight = self.output[dep]
88 if weight >= newdepth:
91 # if our depth is changed we need to update the entries depending on us
92 self.output[entry] = newdepth
93 if newdepth > depth and entry in self.output:
94 self.recursionlevel = 0
95 self._update_dependent_entries(entry)
97 return self._getsorted()
101 sortedoutput = sorted(self.output.items(), key=operator.itemgetter(1))
103 for entry in sortedoutput:
104 if entry[1] not in result:
105 result[entry[1]] = []
106 result[entry[1]].append(entry[0])
109 for entry, data in result.iteritems():
110 returned.append(data)
122 graph2 = {'playbook2.yaml': [], 'playbook1.yaml': ['playbook2.yaml']}
124 topsort1 = TopSort(graph1)
125 topsort2 = TopSort(graph2)
129 sortedlists1 = topsort1.sort()
130 for entry in sortedlists1:
134 sortedlists2 = topsort2.sort()
135 for entry in sortedlists2:
137 except cmerror.CMError as exp:
141 if __name__ == '__main__':