Skip to contentSkip to conversation

hob enhancements and UI bug fixes

PATCH New Joshua Lock 1 participant 12 messages Aug 19, 2011 Arm STM32

lore
Share & tools
lore
#0 lore raw

cover hob enhancements and UI bug fixes

This series includes several bug fixes and improvements for UI's including:
* Hide the goggle progress bar after cache load
* Adapt to recent msg.py change and reduce messages in RunningBuildTreeView
* Change hob to track and list all packages which bring in the listed package rather than just the first, it's expected that this will increase the usability of the UI by making changes more obvious

Amongst increased usefulness of hob this series ensures goggle is reliably usable once more.

Regards,
Joshua

The following changes since commit d5abdacaf9ac604ef8d8c1bafb9b30617827cb4f:

Fixup remaining bb.msg.domain users (2011-08-15 17:31:18 +0100)

are available in the git repository at:
git://github.com/incandescant/bitbake hob
https://github.com/incandescant/bitbake/tree/hob

Joshua Lock (11):
bb/ui/crumbs/runningbuild: reduce number of messages after recent msg
change
bb/ui/crumbs/runningbuild: hide the progress bar on cache load
complete
bb/ui/crumbs/tasklistmodel: more robust checking for substrings bb/ui/crumbs/tasklistmodel: remove useless items from dependency list bb/ui/crumbs/tasklistmodel: store all binb, not just the first
hob: don't try and build if user selects Bake with no selections made bb/ui/crumbs/tasklistmodel: track the PN for each entry in the model bb/ui/hob: fix package only build bb/ui/crumbs/hobeventhandler: fix return values of
*_image_output_type
bb/ui/crumbs/hobprefs: fix setting IMAGE_FSYTPES bb/ui/hob: warn and prevent image build if no IMAGE_FSTYPE is set

 lib/bb/ui/crumbs/hobeventhandler.py |    8 +-
 lib/bb/ui/crumbs/hobprefs.py        |    2 +-
 lib/bb/ui/crumbs/runningbuild.py    |    5 +-
 lib/bb/ui/crumbs/tasklistmodel.py   |  106 ++++++++++++++++++++---------------
 lib/bb/ui/hob.py                    |   34 ++++++++++-
 5 files changed, 100 insertions(+), 55 deletions(-)
Signature · 1 line
1.7.6
#1 lore raw

PATCH 1/11 bb/ui/crumbs/runningbuild: reduce number of messages after recent msg change

The recent change to the message module to remove custom logging domains resulted in an increased number of messages being displayed in the running build view, ignore all messages lower than log level INFO.

---
 lib/bb/ui/crumbs/runningbuild.py |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
lib/bb/ui/crumbs/runningbuild.py +2 -1
index bf72e2a..f78969c 100644
@@ -91,7 +91,8 @@ class RunningBuild (gobject.GObject):
             parent = self.tasks_to_iter[(package, task)]
 
         if(isinstance(event, logging.LogRecord)):
-            if (event.msg.startswith ("Running task")):
+            if (event.levelno < logging.INFO or
+                event.msg.startswith("Running task")):
                 return # don't add these to the list
 
             if event.levelno >= logging.ERROR:
Signature · 1 line
1.7.6
#2 lore raw

PATCH 2/11 bb/ui/crumbs/runningbuild: hide the progress bar on cache load complete

In reply to Joshua Lock

When we receive the CacheLoadComplete command we need to ensure the progress bar is hidden as we can't expect the ParseComplete event, where this would usually be done.

This patch makes the Goggle UI usable again.

---
 lib/bb/ui/crumbs/runningbuild.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
lib/bb/ui/crumbs/runningbuild.py +1 -1
index f78969c..d9e9f26 100644
@@ -254,7 +254,7 @@ class RunningBuild (gobject.GObject):
             pbar.update(event.current, self.progress_total)
         elif isinstance(event, bb.event.CacheLoadCompleted) and pbar:
             pbar.update(self.progress_total, self.progress_total)
-
+            pbar.hide()
         elif isinstance(event, bb.event.ParseStarted) and pbar:
             if event.total == 0:
                 return
Signature · 1 line
1.7.6
#3 lore raw

PATCH 3/11 bb/ui/crumbs/tasklistmodel: more robust checking for substrings

In reply to Joshua Lock

Relying on the count() method of Str to determine whether the string contains a substring is error prone purely because the return value doesn't strictly convert to a Boolean value.
To that end take the more pythonic approach of using the in operator (foo in bar) to check for the substring.
Further, add a helper method for the common case of testing whether a pn is -native, -cross or virtual/

---
 lib/bb/ui/crumbs/tasklistmodel.py |   26 +++++++++++++++++---------
 1 files changed, 17 insertions(+), 9 deletions(-)
lib/bb/ui/crumbs/tasklistmodel.py +17 -9
index 203b628..fa16609 100644
@@ -124,6 +124,14 @@ class TaskListModel(gtk.ListStore):
                                 gobject.TYPE_BOOLEAN,
                                 gobject.TYPE_STRING)
 
+    """
+    Helper method to determine whether name is a target pn
+    """
+    def non_target_name(self, name):
+        if ('-native' in name) or ('-cross' in name) or name.startswith('virtual/'):
+            return True
+        return False
+
     def contents_changed_cb(self, tree_model, path, it=None):
         pkg_cnt = self.contents.iter_n_children(None)
         self.emit("contents-changed", pkg_cnt)
@@ -132,7 +140,7 @@ class TaskListModel(gtk.ListStore):
         if not model.get_value(it, self.COL_INC) or model.get_value(it, self.COL_TYPE) == 'image':
             return False
         name = model.get_value(it, self.COL_NAME)
-        if name.count('-native') or name.count('-cross'):
+        if self.non_target_name(name):
             return False
         else:
             return True
@@ -196,7 +204,7 @@ class TaskListModel(gtk.ListStore):
             return False
         else:
             name = model.get_value(it, self.COL_NAME)
-            if name.count('-native') or name.count('-cross'):
+            if self.non_target_name(name):
                 return False
             return True
 
@@ -226,9 +234,9 @@ class TaskListModel(gtk.ListStore):
             lic = event_model["pn"][item]["license"]
             group = event_model["pn"][item]["section"]
             filename = event_model["pn"][item]["filename"]
-            if name.count('task-') > 0:
+            if ('task-' in name):
                 atype = 'task'
-            elif name.count('-image-') > 0:
+            elif ('-image-' in name):
                 atype = 'image'
 
             depends = event_model["depends"].get(item, [])
@@ -352,14 +360,14 @@ class TaskListModel(gtk.ListStore):
             # If the iterated item is included and depends on the removed
             # item it should also be removed.
             # FIXME: need to ensure partial name matching doesn't happen
-            if inc and deps.count(marked_name) and itname not in removed:
+            if inc and marked_name in deps and itname not in removed:
                 # found a dependency, remove it
                 removed.append(itname)
                 self.mark(path)
 
             # If the iterated item was brought in by the removed (passed) item
             # try and find an alternative dependee and update the binb column
-            if inc and binb.count(marked_name):
+            if inc and marked_name in binb:
                 bib = self.find_alt_dependency(itname)
                 self[path][self.COL_BINB] = bib
 
@@ -411,7 +419,7 @@ class TaskListModel(gtk.ListStore):
             deps = self.contents[path][self.COL_DEPS]
             itname = self.contents[path][self.COL_NAME]
             inc = self.contents[path][self.COL_INC]
-            if itname != name and inc and deps.count(name) > 0:
+            if itname != name and inc and name in deps:
 		# if this item depends on the item, return this items name
 	        return itname
 	    it = self.contents.iter_next(it)
@@ -471,7 +479,7 @@ class TaskListModel(gtk.ListStore):
     def find_path_for_item(self, item_name):
         # We don't include virtual/* or *-native items in the model so save a
         # heavy iteration loop by exiting early for these items
-        if item_name.startswith("virtual/") or item_name.count('-native') or item_name.count('-cross'):
+        if self.non_target_name(item_name):
             return None
 
         it = self.get_iter_first()
@@ -561,7 +569,7 @@ class TaskListModel(gtk.ListStore):
             if not itype == 'package':
                 continue
 
-            if deps.count(pn) != 0:
+            if pn not in deps:
                 revdeps.append(name)
 
         if pn in revdeps:
Signature · 1 line
1.7.6
#4 lore raw

PATCH 4/11 bb/ui/crumbs/tasklistmodel: remove useless items from dependency list

In reply to Joshua Lock

Ensure the dependency list is uniquified, doesn't include self references and further doesn't include -dev references.

---
 lib/bb/ui/crumbs/tasklistmodel.py |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)
lib/bb/ui/crumbs/tasklistmodel.py +10 -2
index fa16609..b0f5d7a 100644
@@ -239,10 +239,11 @@ class TaskListModel(gtk.ListStore):
             elif ('-image-' in name):
                 atype = 'image'
 
+            # Create a combined list of build and runtime dependencies and
+            # then remove any duplicate entries and any entries for -dev
+            # packages
             depends = event_model["depends"].get(item, [])
             rdepends = event_model["rdepends-pn"].get(item, [])
-            if ("%s-dev" % item) in rdepends:
-                rdepends.remove("%s-dev" % item)
             packages = {}
             for pkg in event_model["packages"]:
                 if event_model["packages"][pkg]["pn"] == name:
@@ -250,6 +251,13 @@ class TaskListModel(gtk.ListStore):
                     deps.extend(depends)
                     deps.extend(event_model["rdepends-pkg"].get(pkg, []))
                     deps.extend(rdepends)
+                    deps = self.squish(deps)
+                    # rdepends-pn includes pn-dev
+                    if ("%s-dev" % item) in deps:
+                        deps.remove("%s-dev" % item)
+                    # rdepends-on includes pn
+                    if pkg in deps:
+                        deps.remove(pkg)
                     packages[pkg] = deps
 
             for p in packages:
Signature · 1 line
1.7.6
#5 lore raw

PATCH 5/11 bb/ui/crumbs/tasklistmodel: store all binb, not just the first

In reply to Joshua Lock

This makes it easier for the user to determine what the effects of a removal may be, further it means we no longer need the find_alt_dependency method which could be a fairly time-consuming method depending on the size of the contents table.

Partially addresses [YOCTO #1365]

---
 lib/bb/ui/crumbs/tasklistmodel.py |   50 ++++++++++++------------------------
 1 files changed, 17 insertions(+), 33 deletions(-)
lib/bb/ui/crumbs/tasklistmodel.py +17 -33
index b0f5d7a..d2f49d1 100644
@@ -350,7 +350,7 @@ class TaskListModel(gtk.ListStore):
 
             inc = self[path][self.COL_INC]
             deps = self[path][self.COL_DEPS]
-            binb = self[path][self.COL_BINB]
+            binb = self[path][self.COL_BINB].split(', ')
             itype = self[path][self.COL_TYPE]
             itname = self[path][self.COL_NAME]
 
@@ -362,7 +362,7 @@ class TaskListModel(gtk.ListStore):
             # we should keep it and its dependencies, the easiest way to do so
             # is to save its name and re-mark it for inclusion once dependency
             # processing is complete
-            if binb == "User Selected":
+            if "User Selected" in binb:
                 usersel[itname] = self[path][self.COL_IMG]
 
             # If the iterated item is included and depends on the removed
@@ -376,8 +376,8 @@ class TaskListModel(gtk.ListStore):
             # If the iterated item was brought in by the removed (passed) item
             # try and find an alternative dependee and update the binb column
             if inc and marked_name in binb:
-                bib = self.find_alt_dependency(itname)
-                self[path][self.COL_BINB] = bib
+                binb.remove(marked_name)
+                self[path][self.COL_BINB] = ', '.join(binb).lstrip(', ')
 
         # Re-add any removed user selected items
         for u in usersel:
@@ -415,25 +415,6 @@ class TaskListModel(gtk.ListStore):
                 it = self.contents.iter_next(it)
 
     """
-    Find the name of an item in the image contents which depends on the item
-    name.
-    Returns either an item name (str) or None
-    """
-    def find_alt_dependency(self, name):
-        it = self.contents.get_iter_first()
-        while it:
-            # iterate all items in the contents model
-            path = self.contents.get_path(it)
-            deps = self.contents[path][self.COL_DEPS]
-            itname = self.contents[path][self.COL_NAME]
-            inc = self.contents[path][self.COL_INC]
-            if itname != name and inc and name in deps:
-		# if this item depends on the item, return this items name
-	        return itname
-	    it = self.contents.iter_next(it)
-	return ""
-
-    """
     Check the self.contents gtk.TreeModel for an item
     where COL_NAME matches item_name
     Returns True if a match is found, False otherwise
@@ -456,7 +437,10 @@ class TaskListModel(gtk.ListStore):
         cur_inc = self[item_path][self.COL_INC]
         if not cur_inc:
             self[item_path][self.COL_INC] = True
-            self[item_path][self.COL_BINB] = binb
+
+        bin = self[item_path][self.COL_BINB].split(', ')
+        bin.append(binb)
+        self[item_path][self.COL_BINB] = ', '.join(bin).lstrip(', ')
 
         # We want to do some magic with things which are brought in by the
         # base image so tag them as so
@@ -469,16 +453,16 @@ class TaskListModel(gtk.ListStore):
             # add all of the deps and set their binb to this item
             for dep in deps.split(" "):
                 # If the contents model doesn't already contain dep, add it
-                # We only care to show things which will end up in the
-                # resultant image, so filter cross and native recipes
                 dep_included = self.contents_includes_name(dep)
                 path = self.find_path_for_item(dep)
-                if not dep_included and path:
-                    self.include_item(path, name, image_contents)
-                # Set brought in by for any no longer orphan packages
-                elif dep_included and path:
-                    if not self[path][self.COL_BINB]:
-                        self[path][self.COL_BINB] = name
+                if not path:
+                    continue
+                if dep_included:
+                    bin = self[path][self.COL_BINB].split(', ')
+                    bin.append(name)
+                    self[path][self.COL_BINB] = ', '.join(bin).lstrip(', ')
+                else:
+                    self.include_item(path, binb=name, image_contents=image_contents)
 
     """
     Find the model path for the item_name
@@ -535,7 +519,7 @@ class TaskListModel(gtk.ListStore):
 
         it = self.contents.get_iter_first()
         while it:
-            sel = self.contents.get_value(it, self.COL_BINB) == "User Selected"
+            sel = "User Selected" in self.contents.get_value(it, self.COL_BINB)
             name = self.contents.get_value(it, self.COL_NAME)
             allpkgs.append(name)
             if sel:
Signature · 1 line
1.7.6
#6 lore raw

PATCH 6/11 hob: don't try and build if user selects Bake with no selections made

In reply to Joshua Lock

If the user hasn't made any selections inform them that they need to do so before clicking Bake.

Fixes [YOCTO #1384]

---
 lib/bb/ui/hob.py |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
lib/bb/ui/hob.py +13 -1
index b0a98cb..0230dda 100644
@@ -405,7 +405,19 @@ class MainWindow (gtk.Window):
         build_image = True
 
         rep = self.model.get_build_rep()
-        if not rep.base_image:
+
+        # If no base image and no user selected packages don't build anything
+        if not self.selected_image and not len(rep.userpkgs):
+            lbl = "<b>No selections made</b>\nYou have not made any selections"
+            lbl = lbl + " so there isn't anything to bake at this time."
+            dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
+            dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+            dialog.run()
+            dialog.destroy()
+            return
+        # Else if no base image, ask whether to just build packages or whether
+        # to build a rootfs with the selected packages in
+        elif not self.selected_image:
             lbl = "<b>Build empty image or only packages?</b>\nA base image"
             lbl = lbl + " has not been selected.\n\'Empty image' will build"
             lbl = lbl + " an image with only the selected packages as its"
Signature · 1 line
1.7.6
#7 lore raw

PATCH 7/11 bb/ui/crumbs/tasklistmodel: track the PN for each entry in the model

In reply to Joshua Lock

Now that we've switched to packages in the model, rather than PN, it makes sense to add an extra field to store the PN of the package.

This patch includes a convenience method to retrieve a list of selected PN's.

---
 lib/bb/ui/crumbs/tasklistmodel.py |   20 ++++++++++++++++++--
 1 files changed, 18 insertions(+), 2 deletions(-)
lib/bb/ui/crumbs/tasklistmodel.py +18 -2
index d2f49d1..3921581 100644
@@ -89,7 +89,7 @@ class TaskListModel(gtk.ListStore):
     providing convenience functions to access gtk.TreeModel subclasses which
     provide filtered views of the data.
     """
-    (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_PATH) = range(10)
+    (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_PATH, COL_PN) = range(11)
 
     __gsignals__ = {
         "tasklist-populated" : (gobject.SIGNAL_RUN_LAST,
@@ -122,6 +122,7 @@ class TaskListModel(gtk.ListStore):
                                 gobject.TYPE_STRING,
                                 gobject.TYPE_BOOLEAN,
                                 gobject.TYPE_BOOLEAN,
+                                gobject.TYPE_STRING,
                                 gobject.TYPE_STRING)
 
     """
@@ -265,7 +266,8 @@ class TaskListModel(gtk.ListStore):
                          self.COL_LIC, lic, self.COL_GROUP, group,
                          self.COL_DEPS, " ".join(packages[p]), self.COL_BINB, "",
                          self.COL_TYPE, atype, self.COL_INC, False,
-                         self.COL_IMG, False, self.COL_PATH, filename)
+                         self.COL_IMG, False, self.COL_PATH, filename,
+                         self.COL_PN, item)
 
 	self.emit("tasklist-populated")
 
@@ -527,6 +529,20 @@ class TaskListModel(gtk.ListStore):
             it = self.contents.iter_next(it)
         return userpkgs, allpkgs
 
+    """
+    Return a squished (uniquified) list of the PN's of all selected items
+    """
+    def get_selected_pn(self):
+        pns = []
+
+        it = self.contents.get_iter_first()
+        while it:
+            if self.contents.get_value(it, self.COL_BINB):
+                pns.append(self.contents.get_value(it, self.COL_PN))
+            it = self.contents.iter_next(it)
+
+        return self.squish(pns)
+
     def image_contents_removed(self):
         it = self.get_iter_first()
         while it:
Signature · 1 line
1.7.6
#8 lore raw

PATCH 8/11 bb/ui/hob: fix package only build

In reply to Joshua Lock

Use the models new get_selected_pn method to return a list of PN's for the selected items and pass that for a package only build, rather than passing a list of package names (which buildTargets can't handle).

Fixes [YOCTO #1385]

---
 lib/bb/ui/hob.py |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
lib/bb/ui/hob.py +2 -1
index 0230dda..e02f48c 100644
@@ -174,6 +174,7 @@ class MainWindow (gtk.Window):
             self.toggle_package(path, model, image=True)
             if len(userp):
                 self.model.set_selected_packages(userp)
+            self.selected_image = model[path][self.model.COL_NAME]
 
     def reload_triggered_cb(self, handler, image, packages):
         if image:
@@ -451,7 +452,7 @@ class MainWindow (gtk.Window):
 
             self.handler.build_image(image_name, self.configurator)
         else:
-            self.handler.build_packages(rep.allpkgs.split(" "))
+            self.handler.build_packages(self.model.get_selected_pn())
 
         self.nb.set_current_page(1)
 
Signature · 1 line
1.7.6
#9 lore raw

PATCH 9/11 bb/ui/crumbs/hobeventhandler: fix return values of *_image_output_type

In reply to Joshua Lock

These methods are expected to return lists.

---
 lib/bb/ui/crumbs/hobeventhandler.py |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
lib/bb/ui/crumbs/hobeventhandler.py +4 -4
index 1a4c7b5..fca4401 100644
@@ -310,17 +310,17 @@ class HobHandler(gobject.GObject):
     def add_image_output_type(self, output_type):
         if output_type not in self.image_output_types:
             self.image_output_types.append(output_type)
-            fstypes = " ".join(self.image_output_types)
+            fstypes = " ".join(self.image_output_types).lstrip(" ")
             self.set_fstypes(fstypes)
-        return fstypes
+        return self.image_output_types
 
     def remove_image_output_type(self, output_type):
         if output_type in self.image_output_types:
             ind = self.image_output_types.index(output_type)
             self.image_output_types.pop(ind)
-            fstypes = " ".join(self.image_output_types)
+            fstypes = " ".join(self.image_output_types).lstrip(" ")
             self.set_fstypes(fstypes)
-        return fstypes
+        return self.image_output_types
 
     def get_image_deploy_dir(self):
         return self.server.runCommand(["getVariable", "DEPLOY_DIR_IMAGE"])
Signature · 1 line
1.7.6
#10 lore raw

PATCH 10/11 bb/ui/crumbs/hobprefs: fix setting IMAGE_FSYTPES

In reply to Joshua Lock

We were setting the value as a list when a string is expected

---
 lib/bb/ui/crumbs/hobprefs.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
lib/bb/ui/crumbs/hobprefs.py +1 -1
index 014087b..ee42e58 100644
@@ -38,7 +38,7 @@ class HobPrefs(gtk.Dialog):
         else:
             self.selected_image_types = handler.remove_image_output_type(ot)
 
-        self.configurator.setLocalConfVar('IMAGE_FSTYPES', "%s" % self.selected_image_types)
+        self.configurator.setLocalConfVar('IMAGE_FSTYPES', "%s" % " ".join(self.selected_image_types).lstrip(" "))
 
     def sdk_machine_combo_changed_cb(self, combo, handler):
         sdk_mach = combo.get_active_text()
Signature · 1 line
1.7.6
#11 lore raw

PATCH 11/11 bb/ui/hob: warn and prevent image build if no IMAGE_FSTYPE is set

In reply to Joshua Lock

If IMAGE_FSTYPE is empty and the user has opted to build an image warn them and prevent the build.

Fixes [YOCTO #1267]

---
 lib/bb/ui/hob.py |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)
lib/bb/ui/hob.py +16 -1
index e02f48c..105b0ef 100644
@@ -437,7 +437,22 @@ class MainWindow (gtk.Window):
             elif response == gtk.RESPONSE_OK:
                 rep.base_image = "empty"
 
-        if build_image:
+        # Ensure at least one value is set in IMAGE_FSTYPES.
+        have_selected_fstype = False
+        if (len(self.prefs.selected_image_types) and
+            len(self.prefs.selected_image_types[0])):
+            have_selected_fstype = True
+
+        if build_image and not have_selected_fstype:
+            lbl = "<b>No image output type selected</b>\nThere is no image output"
+            lbl = lbl + " selected for the build. Please set an output image type"
+            lbl = lbl + " in the preferences (Edit -> Preferences)."
+            dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
+            dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+            dialog.run()
+            dialog.destroy()
+            return
+        elif build_image:
             self.handler.make_temp_dir()
             recipepath =  self.handler.get_temp_recipe_path(rep.base_image)
             image_name = recipepath.rstrip(".bb")
Signature · 1 line
1.7.6