summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/tasklistmodel.py')
-rw-r--r--bitbake/lib/bb/ui/crumbs/tasklistmodel.py620
1 files changed, 0 insertions, 620 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/tasklistmodel.py b/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
deleted file mode 100644
index 90a7e5459c..0000000000
--- a/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
+++ /dev/null
@@ -1,620 +0,0 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk
22import gobject
23import re
24
25class BuildRep(gobject.GObject):
26
27 def __init__(self, userpkgs, allpkgs, base_image=None):
28 gobject.GObject.__init__(self)
29 self.base_image = base_image
30 self.allpkgs = allpkgs
31 self.userpkgs = userpkgs
32
33 def loadRecipe(self, pathname):
34 contents = []
35 packages = ""
36 base_image = ""
37
38 with open(pathname, 'r') as f:
39 contents = f.readlines()
40
41 pkg_pattern = "^\s*(IMAGE_INSTALL)\s*([+=.?]+)\s*(\".*?\")"
42 img_pattern = "^\s*(require)\s+(\S+.bb)"
43
44 for line in contents:
45 matchpkg = re.search(pkg_pattern, line)
46 matchimg = re.search(img_pattern, line)
47 if matchpkg:
48 packages = packages + matchpkg.group(3).strip('"')
49 if matchimg:
50 base_image = os.path.basename(matchimg.group(2)).split(".")[0]
51
52 self.base_image = base_image
53 self.userpkgs = packages
54
55 def writeRecipe(self, writepath, model):
56 template = """
57# Recipe generated by the HOB
58
59require %s
60
61IMAGE_INSTALL += "%s"
62"""
63
64 empty_template = """
65# Recipe generated by the HOB
66
67inherit core-image
68
69IMAGE_INSTALL = "%s"
70"""
71 if self.base_image and not self.base_image == "empty":
72 meta_path = model.find_image_path(self.base_image)
73 recipe = template % (meta_path, self.userpkgs)
74 else:
75 recipe = empty_template % self.allpkgs
76
77 if os.path.exists(writepath):
78 os.rename(writepath, "%s~" % writepath)
79
80 with open(writepath, 'w') as r:
81 r.write(recipe)
82
83 return writepath
84
85class TaskListModel(gtk.ListStore):
86 """
87 This class defines an gtk.ListStore subclass which will convert the output
88 of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
89 providing convenience functions to access gtk.TreeModel subclasses which
90 provide filtered views of the data.
91 """
92 (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_PATH, COL_PN) = range(11)
93
94 __gsignals__ = {
95 "tasklist-populated" : (gobject.SIGNAL_RUN_LAST,
96 gobject.TYPE_NONE,
97 ()),
98 "contents-changed" : (gobject.SIGNAL_RUN_LAST,
99 gobject.TYPE_NONE,
100 (gobject.TYPE_INT,)),
101 "image-changed" : (gobject.SIGNAL_RUN_LAST,
102 gobject.TYPE_NONE,
103 (gobject.TYPE_STRING,)),
104 }
105
106 """
107 """
108 def __init__(self):
109 self.contents = None
110 self.tasks = None
111 self.packages = None
112 self.images = None
113 self.selected_image = None
114
115 gtk.ListStore.__init__ (self,
116 gobject.TYPE_STRING,
117 gobject.TYPE_STRING,
118 gobject.TYPE_STRING,
119 gobject.TYPE_STRING,
120 gobject.TYPE_STRING,
121 gobject.TYPE_STRING,
122 gobject.TYPE_STRING,
123 gobject.TYPE_BOOLEAN,
124 gobject.TYPE_BOOLEAN,
125 gobject.TYPE_STRING,
126 gobject.TYPE_STRING)
127
128 """
129 Helper method to determine whether name is a target pn
130 """
131 def non_target_name(self, name):
132 if ('-native' in name) or ('-cross' in name) or name.startswith('virtual/'):
133 return True
134 return False
135
136 def contents_changed_cb(self, tree_model, path, it=None):
137 pkg_cnt = self.contents.iter_n_children(None)
138 self.emit("contents-changed", pkg_cnt)
139
140 def contents_model_filter(self, model, it):
141 if not model.get_value(it, self.COL_INC) or model.get_value(it, self.COL_TYPE) == 'image':
142 return False
143 name = model.get_value(it, self.COL_NAME)
144 if self.non_target_name(name):
145 return False
146 else:
147 return True
148
149 """
150 Create, if required, and return a filtered gtk.TreeModel
151 containing only the items which are to be included in the
152 image
153 """
154 def contents_model(self):
155 if not self.contents:
156 self.contents = self.filter_new()
157 self.contents.set_visible_func(self.contents_model_filter)
158 self.contents.connect("row-inserted", self.contents_changed_cb)
159 self.contents.connect("row-deleted", self.contents_changed_cb)
160 return self.contents
161
162 """
163 Helper function to determine whether an item is a task
164 """
165 def task_model_filter(self, model, it):
166 if model.get_value(it, self.COL_TYPE) == 'task':
167 return True
168 else:
169 return False
170
171 """
172 Create, if required, and return a filtered gtk.TreeModel
173 containing only the items which are tasks
174 """
175 def tasks_model(self):
176 if not self.tasks:
177 self.tasks = self.filter_new()
178 self.tasks.set_visible_func(self.task_model_filter)
179 return self.tasks
180
181 """
182 Helper function to determine whether an item is an image
183 """
184 def image_model_filter(self, model, it):
185 if model.get_value(it, self.COL_TYPE) == 'image':
186 return True
187 else:
188 return False
189
190 """
191 Create, if required, and return a filtered gtk.TreeModel
192 containing only the items which are images
193 """
194 def images_model(self):
195 if not self.images:
196 self.images = self.filter_new()
197 self.images.set_visible_func(self.image_model_filter)
198 return self.images
199
200 """
201 Helper function to determine whether an item is a package
202 """
203 def package_model_filter(self, model, it):
204 if model.get_value(it, self.COL_TYPE) != 'package':
205 return False
206 else:
207 name = model.get_value(it, self.COL_NAME)
208 if self.non_target_name(name):
209 return False
210 return True
211
212 """
213 Create, if required, and return a filtered gtk.TreeModel
214 containing only the items which are packages
215 """
216 def packages_model(self):
217 if not self.packages:
218 self.packages = self.filter_new()
219 self.packages.set_visible_func(self.package_model_filter)
220 return self.packages
221
222 """
223 The populate() function takes as input the data from a
224 bb.event.TargetsTreeGenerated event and populates the TaskList.
225 Once the population is done it emits gsignal tasklist-populated
226 to notify any listeners that the model is ready
227 """
228 def populate(self, event_model):
229 # First clear the model, in case repopulating
230 self.clear()
231 for item in event_model["pn"]:
232 atype = 'package'
233 name = item
234 summary = event_model["pn"][item]["summary"]
235 lic = event_model["pn"][item]["license"]
236 group = event_model["pn"][item]["section"]
237 filename = event_model["pn"][item]["filename"]
238 if ('task-' in name):
239 atype = 'task'
240 elif ('-image-' in name):
241 atype = 'image'
242
243 # Create a combined list of build and runtime dependencies and
244 # then remove any duplicate entries and any entries for -dev
245 # packages
246 depends = event_model["depends"].get(item, [])
247 rdepends = event_model["rdepends-pn"].get(item, [])
248 packages = {}
249 for pkg in event_model["packages"]:
250 if event_model["packages"][pkg]["pn"] == name:
251 deps = []
252 deps.extend(depends)
253 deps.extend(event_model["rdepends-pkg"].get(pkg, []))
254 deps.extend(rdepends)
255 deps = self.squish(deps)
256 # rdepends-pn includes pn-dev
257 if ("%s-dev" % item) in deps:
258 deps.remove("%s-dev" % item)
259 # rdepends-on includes pn
260 if pkg in deps:
261 deps.remove(pkg)
262 packages[pkg] = deps
263
264 for p in packages:
265 self.set(self.append(), self.COL_NAME, p, self.COL_DESC, summary,
266 self.COL_LIC, lic, self.COL_GROUP, group,
267 self.COL_DEPS, " ".join(packages[p]), self.COL_BINB, "",
268 self.COL_TYPE, atype, self.COL_INC, False,
269 self.COL_IMG, False, self.COL_PATH, filename,
270 self.COL_PN, item)
271
272 self.emit("tasklist-populated")
273
274 """
275 Load a BuildRep into the model
276 """
277 def load_image_rep(self, rep):
278 # Unset everything
279 it = self.get_iter_first()
280 while it:
281 path = self.get_path(it)
282 self[path][self.COL_INC] = False
283 self[path][self.COL_IMG] = False
284 it = self.iter_next(it)
285
286 # Iterate the images and disable them all
287 it = self.images.get_iter_first()
288 while it:
289 path = self.images.convert_path_to_child_path(self.images.get_path(it))
290 name = self[path][self.COL_NAME]
291 if name == rep.base_image:
292 self.include_item(path, image_contents=True)
293 else:
294 self[path][self.COL_INC] = False
295 it = self.images.iter_next(it)
296
297 # Mark all of the additional packages for inclusion
298 packages = rep.userpkgs.split(" ")
299 it = self.get_iter_first()
300 while it:
301 path = self.get_path(it)
302 name = self[path][self.COL_NAME]
303 if name in packages:
304 self.include_item(path, binb="User Selected")
305 packages.remove(name)
306 it = self.iter_next(it)
307
308 self.emit("image-changed", rep.base_image)
309
310 """
311 squish lst so that it doesn't contain any duplicate entries
312 """
313 def squish(self, lst):
314 seen = {}
315 for l in lst:
316 seen[l] = 1
317 return seen.keys()
318
319 """
320 Mark the item at path as not included
321 NOTE:
322 path should be a gtk.TreeModelPath into self (not a filtered model)
323 """
324 def remove_item_path(self, path):
325 self[path][self.COL_BINB] = ""
326 self[path][self.COL_INC] = False
327
328 """
329 Recursively called to mark the item at opath and any package which
330 depends on it for removal.
331 NOTE: This method dumbly removes user selected packages and since we don't
332 do significant reverse dependency tracking it's easier and simpler to save
333 the items marked as user selected and re-add them once the removal sweep is
334 complete.
335 """
336 def mark(self, opath):
337 usersel = {}
338 removed = []
339
340 it = self.get_iter_first()
341 # The name of the item we're removing, so that we can use it to find
342 # other items which either depend on it, or were brought in by it
343 marked_name = self[opath][self.COL_NAME]
344
345 # Remove the passed item
346 self.remove_item_path(opath)
347
348 # Remove all dependent packages, update binb
349 while it:
350 path = self.get_path(it)
351 it = self.iter_next(it)
352
353 inc = self[path][self.COL_INC]
354 deps = self[path][self.COL_DEPS]
355 binb = self[path][self.COL_BINB].split(', ')
356 itype = self[path][self.COL_TYPE]
357 itname = self[path][self.COL_NAME]
358
359 # We ignore anything that isn't a package
360 if not itype == "package":
361 continue
362
363 # If the user added this item and it's not the item we're removing
364 # we should keep it and its dependencies, the easiest way to do so
365 # is to save its name and re-mark it for inclusion once dependency
366 # processing is complete
367 if "User Selected" in binb:
368 usersel[itname] = self[path][self.COL_IMG]
369
370 # If the iterated item is included and depends on the removed
371 # item it should also be removed.
372 # FIXME: need to ensure partial name matching doesn't happen
373 if inc and marked_name in deps and itname not in removed:
374 # found a dependency, remove it
375 removed.append(itname)
376 self.mark(path)
377
378 # If the iterated item was brought in by the removed (passed) item
379 # try and find an alternative dependee and update the binb column
380 if inc and marked_name in binb:
381 binb.remove(marked_name)
382 self[path][self.COL_BINB] = ', '.join(binb).lstrip(', ')
383
384 # Re-add any removed user selected items
385 for u in usersel:
386 npath = self.find_path_for_item(u)
387 self.include_item(item_path=npath,
388 binb="User Selected",
389 image_contents=usersel[u])
390 """
391 Remove items from contents if the have an empty COL_BINB (brought in by)
392 caused by all packages they are a dependency of being removed.
393 If the item isn't a package we leave it included.
394 """
395 def sweep_up(self):
396 it = self.contents.get_iter_first()
397 while it:
398 binb = self.contents.get_value(it, self.COL_BINB)
399 itype = self.contents.get_value(it, self.COL_TYPE)
400 remove = False
401
402 if itype == 'package' and not binb:
403 oit = self.contents.convert_iter_to_child_iter(it)
404 opath = self.get_path(oit)
405 self.mark(opath)
406 remove = True
407
408 # When we remove a package from the contents model we alter the
409 # model, so continuing to iterate is bad. *Furthermore* it's
410 # likely that the removal has affected an already iterated item
411 # so we should start from the beginning anyway.
412 # Only when we've managed to iterate the entire contents model
413 # without removing any items do we allow the loop to exit.
414 if remove:
415 it = self.contents.get_iter_first()
416 else:
417 it = self.contents.iter_next(it)
418
419 """
420 Check whether the item at item_path is included or not
421 """
422 def contents_includes_path(self, item_path):
423 return self[item_path][self.COL_INC]
424
425 """
426 Add this item, and any of its dependencies, to the image contents
427 """
428 def include_item(self, item_path, binb="", image_contents=False):
429 item_name = self[item_path][self.COL_NAME]
430 item_deps = self[item_path][self.COL_DEPS]
431
432 self[item_path][self.COL_INC] = True
433
434 item_bin = self[item_path][self.COL_BINB].split(', ')
435 if binb and not binb in item_bin:
436 item_bin.append(binb)
437 self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ')
438
439 # We want to do some magic with things which are brought in by the
440 # base image so tag them as so
441 if image_contents:
442 self[item_path][self.COL_IMG] = True
443 if self[item_path][self.COL_TYPE] == 'image':
444 self.selected_image = item_name
445
446 if item_deps:
447 # Ensure all of the items deps are included and, where appropriate,
448 # add this item to their COL_BINB
449 for dep in item_deps.split(" "):
450 # If the contents model doesn't already contain dep, add it
451 dep_path = self.find_path_for_item(dep)
452 if not dep_path:
453 continue
454 dep_included = self.contents_includes_path(dep_path)
455
456 if dep_included and not dep in item_bin:
457 # don't set the COL_BINB to this item if the target is an
458 # item in our own COL_BINB
459 dep_bin = self[dep_path][self.COL_BINB].split(', ')
460 if not item_name in dep_bin:
461 dep_bin.append(item_name)
462 self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
463 elif not dep_included:
464 self.include_item(dep_path, binb=item_name, image_contents=image_contents)
465
466 """
467 Find the model path for the item_name
468 Returns the path in the model or None
469 """
470 def find_path_for_item(self, item_name):
471 # We don't include virtual/* or *-native items in the model so save a
472 # heavy iteration loop by exiting early for these items
473 if self.non_target_name(item_name):
474 return None
475
476 it = self.get_iter_first()
477 while it:
478 if (self.get_value(it, self.COL_NAME) == item_name):
479 return self.get_path(it)
480 else:
481 it = self.iter_next(it)
482 return None
483
484 """
485 Empty self.contents by setting the include of each entry to None
486 """
487 def reset(self):
488 # Deselect images - slightly more complex logic so that we don't
489 # have to iterate all of the contents of the main model, instead
490 # just iterate the images model.
491 if self.selected_image:
492 iit = self.images.get_iter_first()
493 while iit:
494 pit = self.images.convert_iter_to_child_iter(iit)
495 self.set(pit, self.COL_INC, False)
496 iit = self.images.iter_next(iit)
497 self.selected_image = None
498
499 it = self.contents.get_iter_first()
500 while it:
501 oit = self.contents.convert_iter_to_child_iter(it)
502 self.set(oit,
503 self.COL_INC, False,
504 self.COL_BINB, "",
505 self.COL_IMG, False)
506 # As we've just removed the first item...
507 it = self.contents.get_iter_first()
508
509 """
510 Returns two lists. One of user selected packages and the other containing
511 all selected packages
512 """
513 def get_selected_packages(self):
514 allpkgs = []
515 userpkgs = []
516
517 it = self.contents.get_iter_first()
518 while it:
519 sel = "User Selected" in self.contents.get_value(it, self.COL_BINB)
520 name = self.contents.get_value(it, self.COL_NAME)
521 allpkgs.append(name)
522 if sel:
523 userpkgs.append(name)
524 it = self.contents.iter_next(it)
525 return userpkgs, allpkgs
526
527 """
528 Return a squished (uniquified) list of the PN's of all selected items
529 """
530 def get_selected_pn(self):
531 pns = []
532
533 it = self.contents.get_iter_first()
534 while it:
535 if self.contents.get_value(it, self.COL_BINB):
536 pns.append(self.contents.get_value(it, self.COL_PN))
537 it = self.contents.iter_next(it)
538
539 return self.squish(pns)
540
541 def image_contents_removed(self):
542 it = self.get_iter_first()
543 while it:
544 sel = self.get_value(it, self.COL_INC)
545 img = self.get_value(it, self.COL_IMG)
546 if img and not sel:
547 return True
548 it = self.iter_next(it)
549 return False
550
551 def get_build_rep(self):
552 userpkgs, allpkgs = self.get_selected_packages()
553 # If base image contents have been removed start from an empty rootfs
554 if not self.selected_image or self.image_contents_removed():
555 image = "empty"
556 else:
557 image = self.selected_image
558
559 return BuildRep(" ".join(userpkgs), " ".join(allpkgs), image)
560
561 def find_reverse_depends(self, pn):
562 revdeps = []
563 it = self.contents.get_iter_first()
564
565 while it:
566 name = self.contents.get_value(it, self.COL_NAME)
567 itype = self.contents.get_value(it, self.COL_TYPE)
568 deps = self.contents.get_value(it, self.COL_DEPS)
569
570 it = self.contents.iter_next(it)
571
572 if not itype == 'package':
573 continue
574
575 if pn in deps:
576 revdeps.append(name)
577
578 if pn in revdeps:
579 revdeps.remove(pn)
580 return revdeps
581
582 def set_selected_image(self, img):
583 self.selected_image = img
584 path = self.find_path_for_item(img)
585 self.include_item(item_path=path,
586 binb="User Selected",
587 image_contents=True)
588
589 self.emit("image-changed", self.selected_image)
590
591 def set_selected_packages(self, pkglist):
592 selected = pkglist
593 it = self.get_iter_first()
594
595 while it:
596 name = self.get_value(it, self.COL_NAME)
597 if name in pkglist:
598 pkglist.remove(name)
599 path = self.get_path(it)
600 self.include_item(item_path=path,
601 binb="User Selected")
602 if len(pkglist) == 0:
603 return
604 it = self.iter_next(it)
605
606 def find_image_path(self, image):
607 it = self.images.get_iter_first()
608
609 while it:
610 image_name = self.images.get_value(it, self.COL_NAME)
611 if image_name == image:
612 path = self.images.get_value(it, self.COL_PATH)
613 meta_pattern = "(\S*)/(meta*/)(\S*)"
614 meta_match = re.search(meta_pattern, path)
615 if meta_match:
616 _, lyr, bbrel = path.partition(meta_match.group(2))
617 if bbrel:
618 path = bbrel
619 return path
620 it = self.images.iter_next(it)