-
Notifications
You must be signed in to change notification settings - Fork 62
/
circledep-finder
executable file
·193 lines (143 loc) · 4.6 KB
/
circledep-finder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/python
#
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008, TUBITAK/UEKAE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#
import sys
import multiprocessing
import urllib2
import bz2
import lzma
import piksemel
import pisi
import pisi.dependency as dependency
from pisi.graph import CycleException
class SourceDB:
def __init__(self, index):
self.__source_nodes = {}
self.__pkgstosrc = {}
doc = piksemel.parseString(index)
self.__source_nodes, self.__pkgstosrc = self.__generate_sources(doc)
def __generate_sources(self, doc):
sources = {}
pkgstosrc = {}
for spec in doc.tags("SpecFile"):
src_name = spec.getTag("Source").getTagData("Name")
sources[src_name] = spec.toString()
for package in spec.tags("Package"):
pkgstosrc[package.getTagData("Name")] = src_name
return sources, pkgstosrc
def has_spec(self, name):
return self.__source_nodes.has_key(name)
def get_spec(self, name):
src = self.__source_nodes[name]
spec = pisi.specfile.SpecFile()
spec.parse(src)
return spec
def list_specs(self):
return self.__source_nodes.keys()
def pkgtosrc(self, name):
return self.__pkgstosrc[name]
def find_circle(sourcedb, A):
G_f = pisi.graph.Digraph()
def get_spec(name):
if sourcedb.has_spec(name):
return sourcedb.get_spec(name)
else:
raise Exception('Cannot find source package: %s' % name)
def get_src(name):
return get_spec(name).source
def add_src(src):
if not str(src.name) in G_f.vertices():
G_f.add_vertex(str(src.name), (src.version, src.release))
def pkgtosrc(pkg):
try:
tmp = sourcedb.pkgtosrc(pkg)
except KeyError, e:
# this is a bad hack but after we hit a problem we need to continue
tmp = "e3"
print "---> borks in ", e
return tmp
B = A
install_list = set()
while len(B) > 0:
Bp = set()
for x in B:
sf = get_spec(x)
src = sf.source
add_src(src)
# add dependencies
def process_dep(dep):
srcdep = pkgtosrc(dep.package)
if not srcdep in G_f.vertices():
Bp.add(srcdep)
add_src(get_src(srcdep))
if not src.name == srcdep: # firefox - firefox-devel thing
G_f.add_edge(src.name, srcdep)
for builddep in src.buildDependencies:
process_dep(builddep)
for pkg in sf.packages:
for rtdep in pkg.packageDependencies:
process_dep(rtdep)
B = Bp
try:
order_build = G_f.topological_sort()
order_build.reverse()
except CycleException, cycle:
return str(cycle)
return ""
def getIndex(uri):
try:
if "://" in uri:
rawdata = urllib2.urlopen(uri).read()
else:
rawdata = open(uri, "r").read()
except IOError:
print "could not fetch %s" % uri
return None
if uri.endswith("bz2"):
data = bz2.decompress(rawdata)
elif uri.endswith("xz") or uri.endswith("lzma"):
data = lzma.decompress(rawdata)
else:
data = rawdata
return data
def processPackage(pkg, sourcesLength, counter):
global sourcedb
sys.stdout.write("\r(%04d/%d) Calculating build dep of %s " % (counter, sourcesLength, pkg))
sys.stdout.flush()
return find_circle(sourcedb, [pkg])
def updateStatus(circleResult):
global cycles
cycles.add(circleResult)
if __name__ == "__main__":
if len(sys.argv) < 2:
print "Usage: circlefinder.py <source repo pisi-index.xml file>"
sys.exit(1)
rawIndex = getIndex(sys.argv[1])
sourcedb = SourceDB(rawIndex)
sources = sourcedb.list_specs()
sourcesLength = len(sources)
counter = 0
global cycles
cycles = set()
pool = multiprocessing.Pool()
for pkg in sources:
counter += 1
pool.apply_async(processPackage, (pkg, sourcesLength, counter), callback=updateStatus)
pool.close()
pool.join()
if len(cycles):
print
for cycle in cycles:
print cycle
else:
print "No circular dep found"