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.py326
1 files changed, 326 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/depexp.py b/bitbake/lib/bb/ui/depexp.py
new file mode 100644
index 0000000..4578dce
--- /dev/null
+++ b/bitbake/lib/bb/ui/depexp.py
@@ -0,0 +1,326 @@
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 Queue
23import threading
24import xmlrpclib
25import bb
26import bb.event
27from bb.ui.crumbs.progressbar import HobProgressBar
28
29# Package Model
30(COL_PKG_NAME) = (0)
31
32# Dependency Model
33(TYPE_DEP, TYPE_RDEP) = (0, 1)
34(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2)
35
36
37class PackageDepView(gtk.TreeView):
38 def __init__(self, model, dep_type, label):
39 gtk.TreeView.__init__(self)
40 self.current = None
41 self.dep_type = dep_type
42 self.filter_model = model.filter_new()
43 self.filter_model.set_visible_func(self._filter)
44 self.set_model(self.filter_model)
45 #self.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
46 self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PACKAGE))
47
48 def _filter(self, model, iter):
49 (this_type, package) = model.get(iter, COL_DEP_TYPE, COL_DEP_PARENT)
50 if this_type != self.dep_type: return False
51 return package == self.current
52
53 def set_current_package(self, package):
54 self.current = package
55 self.filter_model.refilter()
56
57
58class PackageReverseDepView(gtk.TreeView):
59 def __init__(self, model, label):
60 gtk.TreeView.__init__(self)
61 self.current = None
62 self.filter_model = model.filter_new()
63 self.filter_model.set_visible_func(self._filter)
64 self.set_model(self.filter_model)
65 self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PARENT))
66
67 def _filter(self, model, iter):
68 package = model.get_value(iter, COL_DEP_PACKAGE)
69 return package == self.current
70
71 def set_current_package(self, package):
72 self.current = package
73 self.filter_model.refilter()
74
75
76class DepExplorer(gtk.Window):
77 def __init__(self):
78 gtk.Window.__init__(self)
79 self.set_title("Dependency Explorer")
80 self.set_default_size(500, 500)
81 self.connect("delete-event", gtk.main_quit)
82
83 # Create the data models
84 self.pkg_model = gtk.ListStore(gobject.TYPE_STRING)
85 self.pkg_model.set_sort_column_id(COL_PKG_NAME, gtk.SORT_ASCENDING)
86 self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
87 self.depends_model.set_sort_column_id(COL_DEP_PACKAGE, gtk.SORT_ASCENDING)
88
89 pane = gtk.HPaned()
90 pane.set_position(250)
91 self.add(pane)
92
93 # The master list of packages
94 scrolled = gtk.ScrolledWindow()
95 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
96 scrolled.set_shadow_type(gtk.SHADOW_IN)
97
98 self.pkg_treeview = gtk.TreeView(self.pkg_model)
99 self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed)
100 column = gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME)
101 self.pkg_treeview.append_column(column)
102 pane.add1(scrolled)
103 scrolled.add(self.pkg_treeview)
104
105 box = gtk.VBox(homogeneous=True, spacing=4)
106
107 # Runtime Depends
108 scrolled = gtk.ScrolledWindow()
109 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
110 scrolled.set_shadow_type(gtk.SHADOW_IN)
111 self.rdep_treeview = PackageDepView(self.depends_model, TYPE_RDEP, "Runtime Depends")
112 self.rdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
113 scrolled.add(self.rdep_treeview)
114 box.add(scrolled)
115
116 # Build Depends
117 scrolled = gtk.ScrolledWindow()
118 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
119 scrolled.set_shadow_type(gtk.SHADOW_IN)
120 self.dep_treeview = PackageDepView(self.depends_model, TYPE_DEP, "Build Depends")
121 self.dep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
122 scrolled.add(self.dep_treeview)
123 box.add(scrolled)
124 pane.add2(box)
125
126 # Reverse Depends
127 scrolled = gtk.ScrolledWindow()
128 scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
129 scrolled.set_shadow_type(gtk.SHADOW_IN)
130 self.revdep_treeview = PackageReverseDepView(self.depends_model, "Reverse Depends")
131 self.revdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PARENT)
132 scrolled.add(self.revdep_treeview)
133 box.add(scrolled)
134 pane.add2(box)
135
136 self.show_all()
137
138 def on_package_activated(self, treeview, path, column, data_col):
139 model = treeview.get_model()
140 package = model.get_value(model.get_iter(path), data_col)
141
142 pkg_path = []
143 def finder(model, path, iter, needle):
144 package = model.get_value(iter, COL_PKG_NAME)
145 if package == needle:
146 pkg_path.append(path)
147 return True
148 else:
149 return False
150 self.pkg_model.foreach(finder, package)
151 if pkg_path:
152 self.pkg_treeview.get_selection().select_path(pkg_path[0])
153 self.pkg_treeview.scroll_to_cell(pkg_path[0])
154
155 def on_cursor_changed(self, selection):
156 (model, it) = selection.get_selected()
157 if it is None:
158 current_package = None
159 else:
160 current_package = model.get_value(it, COL_PKG_NAME)
161 self.rdep_treeview.set_current_package(current_package)
162 self.dep_treeview.set_current_package(current_package)
163 self.revdep_treeview.set_current_package(current_package)
164
165
166 def parse(self, depgraph):
167 for package in depgraph["pn"]:
168 self.pkg_model.insert(0, (package,))
169
170 for package in depgraph["depends"]:
171 for depend in depgraph["depends"][package]:
172 self.depends_model.insert (0, (TYPE_DEP, package, depend))
173
174 for package in depgraph["rdepends-pn"]:
175 for rdepend in depgraph["rdepends-pn"][package]:
176 self.depends_model.insert (0, (TYPE_RDEP, package, rdepend))
177
178
179class gtkthread(threading.Thread):
180 quit = threading.Event()
181 def __init__(self, shutdown):
182 threading.Thread.__init__(self)
183 self.setDaemon(True)
184 self.shutdown = shutdown
185
186 def run(self):
187 gobject.threads_init()
188 gtk.gdk.threads_init()
189 gtk.main()
190 gtkthread.quit.set()
191
192
193def main(server, eventHandler, params):
194 try:
195 params.updateFromServer(server)
196 cmdline = params.parseActions()
197 if not cmdline:
198 print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
199 return 1
200 if 'msg' in cmdline and cmdline['msg']:
201 logger.error(cmdline['msg'])
202 return 1
203 cmdline = cmdline['action']
204 if not cmdline or cmdline[0] != "generateDotGraph":
205 print("This UI requires the -g option")
206 return 1
207 ret, error = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
208 if error:
209 print("Error running command '%s': %s" % (cmdline, error))
210 return 1
211 elif ret != True:
212 print("Error running command '%s': returned %s" % (cmdline, ret))
213 return 1
214 except xmlrpclib.Fault as x:
215 print("XMLRPC Fault getting commandline:\n %s" % x)
216 return
217
218 shutdown = 0
219
220 gtkgui = gtkthread(shutdown)
221 gtkgui.start()
222
223 gtk.gdk.threads_enter()
224 dep = DepExplorer()
225 bardialog = gtk.Dialog(parent=dep,
226 flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
227 bardialog.set_default_size(400, 50)
228 pbar = HobProgressBar()
229 bardialog.vbox.pack_start(pbar)
230 bardialog.show_all()
231 bardialog.connect("delete-event", gtk.main_quit)
232 gtk.gdk.threads_leave()
233
234 progress_total = 0
235 while True:
236 try:
237 event = eventHandler.waitEvent(0.25)
238 if gtkthread.quit.isSet():
239 _, error = server.runCommand(["stateStop"])
240 if error:
241 print('Unable to cleanly stop: %s' % error)
242 break
243
244 if event is None:
245 continue
246
247 if isinstance(event, bb.event.CacheLoadStarted):
248 progress_total = event.total
249 gtk.gdk.threads_enter()
250 bardialog.set_title("Loading Cache")
251 pbar.update(0)
252 gtk.gdk.threads_leave()
253
254 if isinstance(event, bb.event.CacheLoadProgress):
255 x = event.current
256 gtk.gdk.threads_enter()
257 pbar.update(x * 1.0 / progress_total)
258 pbar.set_title('')
259 gtk.gdk.threads_leave()
260 continue
261
262 if isinstance(event, bb.event.CacheLoadCompleted):
263 bardialog.hide()
264 continue
265
266 if isinstance(event, bb.event.ParseStarted):
267 progress_total = event.total
268 if progress_total == 0:
269 continue
270 gtk.gdk.threads_enter()
271 pbar.update(0)
272 bardialog.set_title("Processing recipes")
273
274 gtk.gdk.threads_leave()
275
276 if isinstance(event, bb.event.ParseProgress):
277 x = event.current
278 gtk.gdk.threads_enter()
279 pbar.update(x * 1.0 / progress_total)
280 pbar.set_title('')
281 gtk.gdk.threads_leave()
282 continue
283
284 if isinstance(event, bb.event.ParseCompleted):
285 bardialog.hide()
286 continue
287
288 if isinstance(event, bb.event.DepTreeGenerated):
289 gtk.gdk.threads_enter()
290 dep.parse(event._depgraph)
291 gtk.gdk.threads_leave()
292
293 if isinstance(event, bb.command.CommandCompleted):
294 continue
295
296 if isinstance(event, bb.command.CommandFailed):
297 print("Command execution failed: %s" % event.error)
298 return event.exitcode
299
300 if isinstance(event, bb.command.CommandExit):
301 return event.exitcode
302
303 if isinstance(event, bb.cooker.CookerExit):
304 break
305
306 continue
307 except EnvironmentError as ioerror:
308 # ignore interrupted io
309 if ioerror.args[0] == 4:
310 pass
311 except KeyboardInterrupt:
312 if shutdown == 2:
313 print("\nThird Keyboard Interrupt, exit.\n")
314 break
315 if shutdown == 1:
316 print("\nSecond Keyboard Interrupt, stopping...\n")
317 _, error = server.runCommand(["stateForceShutdown"])
318 if error:
319 print('Unable to cleanly stop: %s' % error)
320 if shutdown == 0:
321 print("\nKeyboard Interrupt, closing down...\n")
322 _, error = server.runCommand(["stateShutdown"])
323 if error:
324 print('Unable to cleanly shutdown: %s' % error)
325 shutdown = shutdown + 1
326 pass