summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/depexp.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/depexp.py')
-rw-r--r--bitbake/lib/bb/ui/depexp.py272
1 files changed, 272 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/depexp.py b/bitbake/lib/bb/ui/depexp.py
new file mode 100644
index 0000000000..cfa5b6564e
--- /dev/null
+++ b/bitbake/lib/bb/ui/depexp.py
@@ -0,0 +1,272 @@
1#
2# BitBake Graphical GTK based Dependency Explorer
3#
4# Copyright (C) 2007 Ross Burton
5# Copyright (C) 2007 - 2008 Richard Purdie
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 2 as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20import gobject
21import gtk
22import threading
23import xmlrpclib
24
25# Package Model
26(COL_PKG_NAME) = (0)
27
28# Dependency Model
29(TYPE_DEP, TYPE_RDEP) = (0, 1)
30(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2)
31
32class PackageDepView(gtk.TreeView):
33 def __init__(self, model, dep_type, label):
34 gtk.TreeView.__init__(self)
35 self.current = None
36 self.dep_type = dep_type
37 self.filter_model = model.filter_new()
38 self.filter_model.set_visible_func(self._filter)
39 self.set_model(self.filter_model)
40 #self.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
41 self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PACKAGE))
42
43 def _filter(self, model, iter):
44 (this_type, package) = model.get(iter, COL_DEP_TYPE, COL_DEP_PARENT)
45 if this_type != self.dep_type: return False
46 return package == self.current
47
48 def set_current_package(self, package):
49 self.current = package
50 self.filter_model.refilter()
51
52class PackageReverseDepView(gtk.TreeView):
53 def __init__(self, model, label):
54 gtk.TreeView.__init__(self)
55 self.current = None
56 self.filter_model = model.filter_new()
57 self.filter_model.set_visible_func(self._filter)
58 self.set_model(self.filter_model)
59 self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PARENT))
60
61 def _filter(self, model, iter):
62 package = model.get_value(iter, COL_DEP_PACKAGE)
63 return package == self.current
64
65 def set_current_package(self, package):
66 self.current = package
67 self.filter_model.refilter()
68
69class DepExplorer(gtk.Window):
70 def __init__(self):
71 gtk.Window.__init__(self)
72 self.set_title("Dependency Explorer")
73 self.set_default_size(500, 500)
74 self.connect("delete-event", gtk.main_quit)
75
76 # Create the data models
77 self.pkg_model = gtk.ListStore(gobject.TYPE_STRING)
78 self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
79
80 pane = gtk.HPaned()
81 pane.set_position(250)
82 self.add(pane)
83
84 # The master list of packages
85 scrolled = gtk.ScrolledWindow()
86 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
87 scrolled.set_shadow_type(gtk.SHADOW_IN)
88 self.pkg_treeview = gtk.TreeView(self.pkg_model)
89 self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed)
90 self.pkg_treeview.append_column(gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME))
91 pane.add1(scrolled)
92 scrolled.add(self.pkg_treeview)
93
94 box = gtk.VBox(homogeneous=True, spacing=4)
95
96 # Runtime Depends
97 scrolled = gtk.ScrolledWindow()
98 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
99 scrolled.set_shadow_type(gtk.SHADOW_IN)
100 self.rdep_treeview = PackageDepView(self.depends_model, TYPE_RDEP, "Runtime Depends")
101 self.rdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
102 scrolled.add(self.rdep_treeview)
103 box.add(scrolled)
104
105 # Build Depends
106 scrolled = gtk.ScrolledWindow()
107 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
108 scrolled.set_shadow_type(gtk.SHADOW_IN)
109 self.dep_treeview = PackageDepView(self.depends_model, TYPE_DEP, "Build Depends")
110 self.dep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
111 scrolled.add(self.dep_treeview)
112 box.add(scrolled)
113 pane.add2(box)
114
115 # Reverse Depends
116 scrolled = gtk.ScrolledWindow()
117 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
118 scrolled.set_shadow_type(gtk.SHADOW_IN)
119 self.revdep_treeview = PackageReverseDepView(self.depends_model, "Reverse Depends")
120 self.revdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PARENT)
121 scrolled.add(self.revdep_treeview)
122 box.add(scrolled)
123 pane.add2(box)
124
125 self.show_all()
126
127 def on_package_activated(self, treeview, path, column, data_col):
128 model = treeview.get_model()
129 package = model.get_value(model.get_iter(path), data_col)
130
131 pkg_path = []
132 def finder(model, path, iter, needle):
133 package = model.get_value(iter, COL_PKG_NAME)
134 if package == needle:
135 pkg_path.append(path)
136 return True
137 else:
138 return False
139 self.pkg_model.foreach(finder, package)
140 if pkg_path:
141 self.pkg_treeview.get_selection().select_path(pkg_path[0])
142 self.pkg_treeview.scroll_to_cell(pkg_path[0])
143
144 def on_cursor_changed(self, selection):
145 (model, it) = selection.get_selected()
146 if iter is None:
147 current_package = None
148 else:
149 current_package = model.get_value(it, COL_PKG_NAME)
150 self.rdep_treeview.set_current_package(current_package)
151 self.dep_treeview.set_current_package(current_package)
152 self.revdep_treeview.set_current_package(current_package)
153
154
155def parse(depgraph, pkg_model, depends_model):
156
157 for package in depgraph["pn"]:
158 pkg_model.set(pkg_model.append(), COL_PKG_NAME, package)
159
160 for package in depgraph["depends"]:
161 for depend in depgraph["depends"][package]:
162 depends_model.set (depends_model.append(),
163 COL_DEP_TYPE, TYPE_DEP,
164 COL_DEP_PARENT, package,
165 COL_DEP_PACKAGE, depend)
166
167 for package in depgraph["rdepends-pn"]:
168 for rdepend in depgraph["rdepends-pn"][package]:
169 depends_model.set (depends_model.append(),
170 COL_DEP_TYPE, TYPE_RDEP,
171 COL_DEP_PARENT, package,
172 COL_DEP_PACKAGE, rdepend)
173
174class ProgressBar(gtk.Window):
175 def __init__(self):
176
177 gtk.Window.__init__(self)
178 self.set_title("Parsing .bb files, please wait...")
179 self.set_default_size(500, 0)
180 self.connect("delete-event", gtk.main_quit)
181
182 self.progress = gtk.ProgressBar()
183 self.add(self.progress)
184 self.show_all()
185
186class gtkthread(threading.Thread):
187 quit = threading.Event()
188 def __init__(self, shutdown):
189 threading.Thread.__init__(self)
190 self.setDaemon(True)
191 self.shutdown = shutdown
192
193 def run(self):
194 gobject.threads_init()
195 gtk.gdk.threads_init()
196 gtk.main()
197 gtkthread.quit.set()
198
199def init(server, eventHandler):
200
201 try:
202 cmdline = server.runCommand(["getCmdLineAction"])
203 if not cmdline or cmdline[0] != "generateDotGraph":
204 print "This UI is only compatible with the -g option"
205 return
206 ret = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
207 if ret != True:
208 print "Couldn't run command! %s" % ret
209 return
210 except xmlrpclib.Fault, x:
211 print "XMLRPC Fault getting commandline:\n %s" % x
212 return
213
214 shutdown = 0
215
216 gtkgui = gtkthread(shutdown)
217 gtkgui.start()
218
219 gtk.gdk.threads_enter()
220 pbar = ProgressBar()
221 dep = DepExplorer()
222 gtk.gdk.threads_leave()
223
224 while True:
225 try:
226 event = eventHandler.waitEvent(0.25)
227 if gtkthread.quit.isSet():
228 break
229
230 if event is None:
231 continue
232 if isinstance(event, bb.event.ParseProgress):
233 x = event.sofar
234 y = event.total
235 if x == y:
236 print("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
237 % ( event.cached, event.parsed, event.skipped, event.masked, event.errors))
238 pbar.hide()
239 gtk.gdk.threads_enter()
240 pbar.progress.set_fraction(float(x)/float(y))
241 pbar.progress.set_text("%d/%d (%2d %%)" % (x, y, x*100/y))
242 gtk.gdk.threads_leave()
243 continue
244
245 if isinstance(event, bb.event.DepTreeGenerated):
246 gtk.gdk.threads_enter()
247 parse(event._depgraph, dep.pkg_model, dep.depends_model)
248 gtk.gdk.threads_leave()
249
250 if isinstance(event, bb.command.CookerCommandCompleted):
251 continue
252 if isinstance(event, bb.command.CookerCommandFailed):
253 print "Command execution failed: %s" % event.error
254 break
255 if isinstance(event, bb.cooker.CookerExit):
256 break
257
258 continue
259
260 except KeyboardInterrupt:
261 if shutdown == 2:
262 print "\nThird Keyboard Interrupt, exit.\n"
263 break
264 if shutdown == 1:
265 print "\nSecond Keyboard Interrupt, stopping...\n"
266 server.runCommand(["stateStop"])
267 if shutdown == 0:
268 print "\nKeyboard Interrupt, closing down...\n"
269 server.runCommand(["stateShutdown"])
270 shutdown = shutdown + 1
271 pass
272