* [RFC] [PATCH 00/13] Prototype GUI Image Creator
@ 2011-02-04 8:53 Joshua Lock
2011-02-04 8:53 ` [PATCH 01/13] bitbake/cache: store a list of inherited files in the cache Joshua Lock
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
This patch series introduces a very basic image creator for BitBake. It is far from complete and not very usable but begins to explore the possibilities of graphical tooling built on top of BitBake.
Note: this does *not* work with the default None server in Poky, you need to use the XML-RPC server (uncomment the two xmlrpc lines in bitbake/bin/bitbake and comment out the none lines).
The code is pretty ugly in places, though I hope it's not too Poky specific.
Currently it will just set the targets of the build command to all of the selected packages, this needs refinement - ideally it will 'squash' the list of packages to only include packages not brough in by a selected image (this will also be useful to provide a summary/confirmation dialog before the build)but I want to implement this in a generic way (i.e. not relying on Poky metadata conventions).
There are also various NOTE/FIXME/TODO comments - these all need adressing.
Several UI enhancements are planned, such as an 'Advanced' section of the GUI which will enable the tweaking of variables such as DISTRO, PACKAGE_CLASSES, BB_NUMBER_THREADS and others. There are also various usability niggles that need work such as: the treeview columns being sized better and the fact that
the sort column in the 'Packages (by Group)' column needs a custom sort function otherwise sort order changes when packages are toggled for inclusion.
I'm hoping for feedback on the approach and code review.
Thanks,
Joshua
Pull URL: git://git.pokylinux.org/poky-contrib.git
Branch: josh/gui
Browse: http://git.pokylinux.org/cgit.cgi/poky-contrib/log/?h=josh/gui
Thanks,
Joshua Lock <josh@linux.intel.com>
---
Joshua Lock (13):
bitbake/cache: store a list of inherited files in the cache
bitbake: implement command to get all possible targets and their
dependencies
bitbake: implement command to find configuration files for a config
variable
bitbake/cooker: add generateTargetsTree method
bitbake/cooker: reduce code duplication
bitbake/[cooker|cache]: cache summary, license and group. Add to
targets tree
bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass
bitbake/event: fix some whitespace issues
bitbake/crumbs: update documentation header
bitbake/progress: add method to pulse the progress bar
bitbake/cooker: don't drop possible_world ref count
bitbake: Add new UI hob, a prototype Gtk+ GUI for creating images
bitbake/progress: make progress dialog modal for parent window
bitbake/lib/bb/cache.py | 17 +
bitbake/lib/bb/command.py | 21 +
bitbake/lib/bb/cooker.py | 111 +++++-
bitbake/lib/bb/event.py | 17 +
bitbake/lib/bb/ui/crumbs/__init__.py | 2 +-
bitbake/lib/bb/ui/crumbs/hobeventhandler.py | 138 ++++++
bitbake/lib/bb/ui/crumbs/progress.py | 7 +-
bitbake/lib/bb/ui/crumbs/tasklistmodel.py | 346 ++++++++++++++++
bitbake/lib/bb/ui/hob.py | 596 +++++++++++++++++++++++++++
9 files changed, 1245 insertions(+), 10 deletions(-)
create mode 100644 bitbake/lib/bb/ui/crumbs/hobeventhandler.py
create mode 100644 bitbake/lib/bb/ui/crumbs/tasklistmodel.py
create mode 100644 bitbake/lib/bb/ui/hob.py
--
1.7.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/13] bitbake/cache: store a list of inherited files in the cache
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:53 ` [PATCH 02/13] bitbake: implement command to get all possible targets and their dependencies Joshua Lock
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/cache.py | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py
index ff42a37..8480f89 100644
--- a/bitbake/lib/bb/cache.py
+++ b/bitbake/lib/bb/cache.py
@@ -74,6 +74,7 @@ recipe_fields = (
'tasks',
'basetaskhashes',
'hashfilename',
+ 'inherits',
)
@@ -164,6 +165,7 @@ class RecipeInfo(namedtuple('RecipeInfo', recipe_fields)):
rprovides_pkg = cls.pkgvar('RPROVIDES', packages, metadata),
rdepends_pkg = cls.pkgvar('RDEPENDS', packages, metadata),
rrecommends_pkg = cls.pkgvar('RRECOMMENDS', packages, metadata),
+ inherits = cls.getvar('__inherit_cache', metadata),
)
@@ -574,6 +576,7 @@ class CacheData(object):
self.tasks = {}
self.basetaskhash = {}
self.hashfn = {}
+ self.inherits = {}
"""
Indirect Cache variables
@@ -635,3 +638,5 @@ class CacheData(object):
for task, taskhash in info.basetaskhashes.iteritems():
identifier = '%s.%s' % (fn, task)
self.basetaskhash[identifier] = taskhash
+
+ self.inherits[fn] = info.inherits
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/13] bitbake: implement command to get all possible targets and their dependencies
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
2011-02-04 8:53 ` [PATCH 01/13] bitbake/cache: store a list of inherited files in the cache Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:53 ` [PATCH 03/13] bitbake: implement command to find configuration files for a config variable Joshua Lock
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Add a new command generateTargetsTree() which returns a dependency tree of
possible targets (tasks and recipes) as well as their dependency information.
Optional parameter 'klass' also ensures any recipes which inherit the
specified class path (i.e. 'classes/image.bbclass') are included in the model
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/command.py | 10 ++++++++++
bitbake/lib/bb/cooker.py | 25 +++++++++++++++++++++++++
bitbake/lib/bb/event.py | 9 +++++++++
3 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py
index b880892..42b5b06 100644
--- a/bitbake/lib/bb/command.py
+++ b/bitbake/lib/bb/command.py
@@ -222,6 +222,16 @@ class CommandsAsync:
command.finishAsyncCommand()
generateDotGraph.needcache = True
+ def generateTargetsTree(self, command, params):
+ """
+ Generate a tree of all buildable targets.
+ """
+ klass = params[0]
+
+ command.cooker.generateTargetsTree(klass)
+ command.finishAsyncCommand()
+ generateTargetsTree.needcache = True
+
def showVersions(self, command, params):
"""
Show the currently selected versions
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index e524db7..ccb67a1 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -430,6 +430,31 @@ class BBCooker:
if not regex in matched:
collectlog.warn("No bb files matched BBFILE_PATTERN_%s '%s'" % (collection, pattern))
+ def checkInheritsClass(self, klass):
+ pkg_list = []
+ for pfn in self.status.pkg_fn:
+ inherits = self.status.inherits.get(pfn, None)
+ if inherits and inherits.count(klass) > 0:
+ pkg_list.append(self.status.pkg_fn[pfn])
+
+ return pkg_list
+
+ def generateTargetsTree(self, klass):
+ """
+ Generate a dependency tree of buildable targets
+ Generate an event with the result
+ """
+ pkgs = ['world']
+ # if inherited_class passed ensure all recipes which inherit the
+ # specified class are included in pkgs
+ if klass:
+ extra_pkgs = self.checkInheritsClass(klass)
+ pkgs = pkgs + extra_pkgs
+
+ # generate a dependency tree for all our packages
+ tree = self.generateDepTreeData(pkgs, 'build')
+ bb.event.fire(bb.event.TargetsTreeGenerated(tree), self.configuration.data)
+
def buildWorldTargetList(self):
"""
Build package list for "bitbake world"
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index bd2042a..0777b42 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -352,6 +352,15 @@ class DepTreeGenerated(Event):
Event.__init__(self)
self._depgraph = depgraph
+class TargetsTreeGenerated(Event):
+ """
+ Event when a set of buildable targets has been generated
+ """
+
+ def __init__(self, model):
+ Event.__init__(self)
+ self._model = model
+
class MsgBase(Event):
"""Base class for messages"""
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/13] bitbake: implement command to find configuration files for a config variable
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
2011-02-04 8:53 ` [PATCH 01/13] bitbake/cache: store a list of inherited files in the cache Joshua Lock
2011-02-04 8:53 ` [PATCH 02/13] bitbake: implement command to get all possible targets and their dependencies Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:53 ` [PATCH 04/13] bitbake/cooker: add generateTargetsTree method Joshua Lock
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Some configuration variables (MACHINE, MACHINE-SDK and DISTRO) set which
confguration files bitbake should use.
The added command , findConfigFiles, enables a UI to query which files are
suitable values for a specified parameter.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/command.py | 11 +++++++++++
bitbake/lib/bb/cooker.py | 24 ++++++++++++++++++++++++
bitbake/lib/bb/event.py | 10 ++++++++++
3 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py
index 42b5b06..e83751a 100644
--- a/bitbake/lib/bb/command.py
+++ b/bitbake/lib/bb/command.py
@@ -232,6 +232,17 @@ class CommandsAsync:
command.finishAsyncCommand()
generateTargetsTree.needcache = True
+ def findConfigFiles(self, command, params):
+ """
+ Find config files which provide appropriate values
+ for the passed configuration variable. i.e. MACHINE
+ """
+ varname = params[0]
+
+ command.cooker.findConfigFiles(varname)
+ command.finishAsyncCommand()
+ findConfigFiles.needcache = True
+
def showVersions(self, command, params):
"""
Show the currently selected versions
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index ccb67a1..e6643ec 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -430,8 +430,32 @@ class BBCooker:
if not regex in matched:
collectlog.warn("No bb files matched BBFILE_PATTERN_%s '%s'" % (collection, pattern))
+ def findConfigFiles(self, varname):
+ """
+ Find config files which are appropriate values for varname.
+ i.e. MACHINE, DISTRO
+ """
+ possible = []
+ var = varname.lower()
+
+ data = self.configuration.data
+ # iterate configs
+ bbpaths = bb.data.getVar('BBPATH', data, True).split(':')
+ for path in bbpaths:
+ confpath = os.path.join(path, "conf", var)
+ if os.path.exists(confpath):
+ for root, dirs, files in os.walk(confpath):
+ # get all child files, these are appropriate values
+ for f in files:
+ val, sep, end = f.rpartition('.')
+ if end == 'conf':
+ possible.append(val)
+
+ bb.event.fire(bb.event.ConfigFilesFound(var, possible), self.configuration.data)
+
def checkInheritsClass(self, klass):
pkg_list = []
+
for pfn in self.status.pkg_fn:
inherits = self.status.inherits.get(pfn, None)
if inherits and inherits.count(klass) > 0:
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index 0777b42..176eeb8 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -361,6 +361,16 @@ class TargetsTreeGenerated(Event):
Event.__init__(self)
self._model = model
+class ConfigFilesFound(Event):
+ """
+ Event when a list of appropriate config files has been generated
+ """
+
+ def __init__(self, variable, values):
+ Event.__init__(self)
+ self._variable = variable
+ self._values = values
+
class MsgBase(Event):
"""Base class for messages"""
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/13] bitbake/cooker: add generateTargetsTree method
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (2 preceding siblings ...)
2011-02-04 8:53 ` [PATCH 03/13] bitbake: implement command to find configuration files for a config variable Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:53 ` [PATCH 05/13] bitbake/cooker: reduce code duplication Joshua Lock
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
The generateTargetsTree() command needs to return a model which includes more
metadata than the one generated by generateDepTree().
This patch adds a new method generateTargetsTreeData() to the cooker, based
on generateDepData(), and switches generateTargetsTree() to use it.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/cooker.py | 67 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index e6643ec..c7c8ad6 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -453,7 +453,10 @@ class BBCooker:
bb.event.fire(bb.event.ConfigFilesFound(var, possible), self.configuration.data)
- def checkInheritsClass(self, klass):
+ def findInheritsClass(self, klass):
+ """
+ Find all recipes which inherit the specified class
+ """
pkg_list = []
for pfn in self.status.pkg_fn:
@@ -463,6 +466,64 @@ class BBCooker:
return pkg_list
+ def generateTargetsTreeData(self, pkgs_to_build, task):
+ """
+ Create a tree of pkgs_to_build metadata, returning the data.
+ """
+
+ # Need files parsed
+ self.updateCache()
+
+ # If we are told to do the None task then query the default task
+ if (task == None):
+ task = self.configuration.cmd
+
+ pkgs_to_build = self.checkPackages(pkgs_to_build)
+
+ localdata = data.createCopy(self.configuration.data)
+ bb.data.update_data(localdata)
+ bb.data.expandKeys(localdata)
+ taskdata = bb.taskdata.TaskData(self.configuration.abort)
+
+ runlist = []
+ for k in pkgs_to_build:
+ taskdata.add_provider(localdata, self.status, k)
+ runlist.append([k, "do_%s" % task])
+ taskdata.add_unresolved(localdata, self.status)
+
+ rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
+ rq.rqdata.prepare()
+
+ seen_fnids = []
+ target_tree = {}
+ target_tree["depends"] = {}
+ target_tree["pn"] = {}
+ target_tree["rdepends-pn"] = {}
+
+ for task in xrange(len(rq.rqdata.runq_fnid)):
+ taskname = rq.rqdata.runq_task[task]
+ fnid = rq.rqdata.runq_fnid[task]
+ fn = taskdata.fn_index[fnid]
+ pn = self.status.pkg_fn[fn]
+ version = "%s:%s-%s" % self.status.pkg_pepvpr[fn]
+ if pn not in target_tree["pn"]:
+ target_tree["pn"][pn] = {}
+ target_tree["pn"][pn]["filename"] = fn
+ target_tree["pn"][pn]["version"] = version
+ if fnid not in seen_fnids:
+ seen_fnids.append(fnid)
+ packages = []
+
+ target_tree["depends"][pn] = []
+ for dep in taskdata.depids[fnid]:
+ target_tree["depends"][pn].append(taskdata.build_names_index[dep])
+
+ target_tree["rdepends-pn"][pn] = []
+ for rdep in taskdata.rdepids[fnid]:
+ target_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep])
+
+ return target_tree
+
def generateTargetsTree(self, klass):
"""
Generate a dependency tree of buildable targets
@@ -472,11 +533,11 @@ class BBCooker:
# if inherited_class passed ensure all recipes which inherit the
# specified class are included in pkgs
if klass:
- extra_pkgs = self.checkInheritsClass(klass)
+ extra_pkgs = self.findInheritsClass(klass)
pkgs = pkgs + extra_pkgs
# generate a dependency tree for all our packages
- tree = self.generateDepTreeData(pkgs, 'build')
+ tree = self.generateTargetsTreeData(pkgs, 'build')
bb.event.fire(bb.event.TargetsTreeGenerated(tree), self.configuration.data)
def buildWorldTargetList(self):
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/13] bitbake/cooker: reduce code duplication
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (3 preceding siblings ...)
2011-02-04 8:53 ` [PATCH 04/13] bitbake/cooker: add generateTargetsTree method Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:53 ` [PATCH 06/13] bitbake/[cooker|cache]: cache summary, license and group. Add to targets tree Joshua Lock
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Move runqueua and taskdata initialisation into a new function,
prepareTreeData(), so that generateDepTreeData() and
generateTargetsTreeData() are not duplicating the same logic.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/cooker.py | 37 +++++++++++--------------------------
1 files changed, 11 insertions(+), 26 deletions(-)
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index c7c8ad6..b3158ff 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -237,11 +237,10 @@ class BBCooker:
if data.getVarFlag( e, 'python', envdata ):
logger.plain("\npython %s () {\n%s}\n", e, data.getVar(e, envdata, 1))
- def generateDepTreeData(self, pkgs_to_build, task):
+ def prepareTreeData(self, pkgs_to_build, task):
"""
- Create a dependency tree of pkgs_to_build, returning the data.
+ Prepare a runqueue and taskdata object for iteration over pkgs_to_build
"""
-
# Need files parsed
self.updateCache()
@@ -265,6 +264,14 @@ class BBCooker:
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
rq.rqdata.prepare()
+ return taskdata, rq
+
+ def generateDepTreeData(self, pkgs_to_build, task):
+ """
+ Create a dependency tree of pkgs_to_build, returning the data.
+ """
+ taskdata, rq = self.prepareTreeData(pkgs_to_build, task)
+
seen_fnids = []
depend_tree = {}
depend_tree["depends"] = {}
@@ -470,29 +477,7 @@ class BBCooker:
"""
Create a tree of pkgs_to_build metadata, returning the data.
"""
-
- # Need files parsed
- self.updateCache()
-
- # If we are told to do the None task then query the default task
- if (task == None):
- task = self.configuration.cmd
-
- pkgs_to_build = self.checkPackages(pkgs_to_build)
-
- localdata = data.createCopy(self.configuration.data)
- bb.data.update_data(localdata)
- bb.data.expandKeys(localdata)
- taskdata = bb.taskdata.TaskData(self.configuration.abort)
-
- runlist = []
- for k in pkgs_to_build:
- taskdata.add_provider(localdata, self.status, k)
- runlist.append([k, "do_%s" % task])
- taskdata.add_unresolved(localdata, self.status)
-
- rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
- rq.rqdata.prepare()
+ taskdata, rq = self.prepareTreeData(pkgs_to_build, task)
seen_fnids = []
target_tree = {}
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/13] bitbake/[cooker|cache]: cache summary, license and group. Add to targets tree
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (4 preceding siblings ...)
2011-02-04 8:53 ` [PATCH 05/13] bitbake/cooker: reduce code duplication Joshua Lock
@ 2011-02-04 8:53 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 07/13] bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass Joshua Lock
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:53 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Add summary, license and group metadata to RecipeInfo and the cache.
Unfortunately this impacts parse speed but gives us a much richer set of
metadata to expose through UI's which can be accessed via the
generateTargetsTree command.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/cache.py | 12 ++++++++++++
bitbake/lib/bb/cooker.py | 6 ++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py
index 8480f89..0bfc5dc 100644
--- a/bitbake/lib/bb/cache.py
+++ b/bitbake/lib/bb/cache.py
@@ -75,6 +75,9 @@ recipe_fields = (
'basetaskhashes',
'hashfilename',
'inherits',
+ 'summary',
+ 'license',
+ 'section',
)
@@ -166,6 +169,9 @@ class RecipeInfo(namedtuple('RecipeInfo', recipe_fields)):
rdepends_pkg = cls.pkgvar('RDEPENDS', packages, metadata),
rrecommends_pkg = cls.pkgvar('RRECOMMENDS', packages, metadata),
inherits = cls.getvar('__inherit_cache', metadata),
+ summary = cls.getvar('SUMMARY', metadata),
+ license = cls.getvar('LICENSE', metadata),
+ section = cls.getvar('SECTION', metadata),
)
@@ -577,6 +583,9 @@ class CacheData(object):
self.basetaskhash = {}
self.hashfn = {}
self.inherits = {}
+ self.summary = {}
+ self.license = {}
+ self.section = {}
"""
Indirect Cache variables
@@ -640,3 +649,6 @@ class CacheData(object):
self.basetaskhash[identifier] = taskhash
self.inherits[fn] = info.inherits
+ self.summary[fn] = info.summary
+ self.license[fn] = info.license
+ self.section[fn] = info.section
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index b3158ff..39cf011 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -491,10 +491,16 @@ class BBCooker:
fn = taskdata.fn_index[fnid]
pn = self.status.pkg_fn[fn]
version = "%s:%s-%s" % self.status.pkg_pepvpr[fn]
+ summary = self.status.summary[fn]
+ license = self.status.license[fn]
+ section = self.status.section[fn]
if pn not in target_tree["pn"]:
target_tree["pn"][pn] = {}
target_tree["pn"][pn]["filename"] = fn
target_tree["pn"][pn]["version"] = version
+ target_tree["pn"][pn]["summary"] = summary
+ target_tree["pn"][pn]["license"] = license
+ target_tree["pn"][pn]["section"] = section
if fnid not in seen_fnids:
seen_fnids.append(fnid)
packages = []
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/13] bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (5 preceding siblings ...)
2011-02-04 8:53 ` [PATCH 06/13] bitbake/[cooker|cache]: cache summary, license and group. Add to targets tree Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 08/13] bitbake/event: fix some whitespace issues Joshua Lock
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Provide a gtk.ListStore subclass which includes a function,
populate(), which takes as input the data emitted by
bb.event.TargetsTreeGenerated and fills the ListStore model
appropriately.
Furthermore convenience functions are provided by which the caller can
get gtk.TreeModel subclasses which provide filtered views of the data.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/ui/crumbs/tasklistmodel.py | 346 +++++++++++++++++++++++++++++
1 files changed, 346 insertions(+), 0 deletions(-)
create mode 100644 bitbake/lib/bb/ui/crumbs/tasklistmodel.py
diff --git a/bitbake/lib/bb/ui/crumbs/tasklistmodel.py b/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
new file mode 100644
index 0000000..a83a176
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
@@ -0,0 +1,346 @@
+#
+# BitBake Graphical GTK User Interface
+#
+# Copyright (C) 2011 Intel Corporation
+#
+# Authored by Joshua Lock <josh@linux.intel.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import gtk
+import gobject
+
+class TaskListModel(gtk.ListStore):
+ """
+ This class defines an gtk.ListStore subclass which will convert the output
+ of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
+ 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) = range(8)
+
+ __gsignals__ = {
+ "tasklist-populated" : (gobject.SIGNAL_RUN_LAST,
+ gobject.TYPE_NONE,
+ ())
+ }
+
+ """
+ """
+ def __init__(self):
+ self.contents = None
+ self.tasks = None
+ self.packages = None
+ self.images = None
+
+ gtk.ListStore.__init__ (self,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_BOOLEAN)
+
+ """
+ Create, if required, and return a filtered gtk.TreeModel
+ containing only the items which are to be included in the
+ image
+ """
+ def contents_model(self):
+ if not self.contents:
+ self.contents = self.filter_new()
+ self.contents.set_visible_column(self.COL_INC)
+ return self.contents
+
+ """
+ Helper function to determine whether an item is a task
+ """
+ def task_model_filter(self, model, it):
+ if model.get_value(it, self.COL_TYPE) == 'task':
+ return True
+ else:
+ return False
+
+ """
+ Create, if required, and return a filtered gtk.TreeModel
+ containing only the items which are tasks
+ """
+ def tasks_model(self):
+ if not self.tasks:
+ self.tasks = self.filter_new()
+ self.tasks.set_visible_func(self.task_model_filter)
+ return self.tasks
+
+ """
+ Helper function to determine whether an item is an image
+ """
+ def image_model_filter(self, model, it):
+ if model.get_value(it, self.COL_TYPE) == 'image':
+ return True
+ else:
+ return False
+
+ """
+ Create, if required, and return a filtered gtk.TreeModel
+ containing only the items which are images
+ """
+ def images_model(self):
+ if not self.images:
+ self.images = self.filter_new()
+ self.images.set_visible_func(self.image_model_filter)
+ return self.images
+
+ """
+ Helper function to determine whether an item is a package
+ """
+ def package_model_filter(self, model, it):
+ if model.get_value(it, self.COL_TYPE) == 'package':
+ return True
+ else:
+ return False
+
+ """
+ Create, if required, and return a filtered gtk.TreeModel
+ containing only the items which are packages
+ """
+ def packages_model(self):
+ if not self.packages:
+ self.packages = self.filter_new()
+ self.packages.set_visible_func(self.package_model_filter)
+ return self.packages
+
+ """
+ The populate() function takes as input the data from a
+ bb.event.TargetsTreeGenerated event and populates the TaskList.
+ Once the population is done it emits gsignal tasklist-populated
+ to notify any listeners that the model is ready
+ """
+ def populate(self, event_model):
+ for item in event_model["pn"]:
+ atype = 'package'
+ name = item
+ summary = event_model["pn"][item]["summary"]
+ license = event_model["pn"][item]["license"]
+ group = event_model["pn"][item]["section"]
+
+ depends = event_model["depends"].get(item, "")
+ rdepends = event_model["rdepends-pn"].get(item, "")
+ depends = depends + rdepends
+ self.squish(depends)
+ deps = " ".join(depends)
+
+ if name.count('task-') > 0:
+ atype = 'task'
+ elif name.count('-image-') > 0:
+ atype = 'image'
+
+ self.set(self.append(), self.COL_NAME, name, self.COL_DESC, summary,
+ self.COL_LIC, license, self.COL_GROUP, group,
+ self.COL_DEPS, deps, self.COL_BINB, "",
+ self.COL_TYPE, atype, self.COL_INC, False)
+
+ self.emit("tasklist-populated")
+
+ """
+ squish lst so that it doesn't contain any duplicates
+ """
+ def squish(self, lst):
+ seen = {}
+ for l in lst:
+ seen[l] = 1
+ return seen.keys()
+
+ """
+ Mark the item at path as not included
+ NOTE:
+ path should be a gtk.TreeModelPath into self (not a filtered model)
+ """
+ def remove_item_path(self, path):
+ self[path][self.COL_BINB] = ""
+ self[path][self.COL_INC] = False
+
+ """
+ """
+ def mark(self, path):
+ name = self[path][self.COL_NAME]
+ it = self.get_iter_first()
+ removals = []
+ #print("Removing %s" % name)
+
+ self.remove_item_path(path)
+
+ # Remove all dependent packages, update binb
+ while it:
+ path = self.get_path(it)
+ # FIXME: need to ensure partial name matching doesn't happen, regexp?
+ if self[path][self.COL_INC] and self[path][self.COL_DEPS].count(name):
+ #print("%s depended on %s, marking for removal" % (self[path][self.COL_NAME], name))
+ # found a dependency, remove it
+ self.mark(path)
+ if self[path][self.COL_INC] and self[path][self.COL_BINB].count(name):
+ binb = self.find_alt_dependency(self[path][self.COL_NAME])
+ #print("%s was brought in by %s, binb set to %s" % (self[path][self.COL_NAME], name, binb))
+ self[path][self.COL_BINB] = binb
+ it = self.iter_next(it)
+
+ """
+ """
+ def sweep_up(self):
+ removals = []
+ it = self.get_iter_first()
+
+ while it:
+ path = self.get_path(it)
+ binb = self[path][self.COL_BINB]
+ if binb == "" or binb is None:
+ #print("Sweeping up %s" % self[path][self.COL_NAME])
+ if not path in removals:
+ removals.extend(path)
+ it = self.iter_next(it)
+
+ while removals:
+ path = removals.pop()
+ self.mark(path)
+
+ """
+ Remove an item from the contents
+ """
+ def remove_item(self, path):
+ self.mark(path)
+ self.sweep_up()
+
+ """
+ Find the name of an item in the image contents which depends on the item
+ at contents_path returns either an item name (str) or None
+ NOTE:
+ contents_path must be a path in the self.contents gtk.TreeModel
+ """
+ def find_alt_dependency(self, name):
+ it = self.get_iter_first()
+ while it:
+ # iterate all items in the model
+ path = self.get_path(it)
+ deps = self[path][self.COL_DEPS]
+ itname = self[path][self.COL_NAME]
+ inc = self[path][self.COL_INC]
+ if itname != name and inc and deps.count(name) > 0:
+ # if this item depends on the item, return this items name
+ #print("%s depends on %s" % (itname, name))
+ return itname
+ it = self.iter_next(it)
+ return ""
+
+ """
+ Convert a path in self to a path in the filtered contents model
+ """
+ def contents_path_for_path(self, path):
+ return self.contents.convert_child_path_to_path(path)
+
+ """
+ Check the self.contents gtk.TreeModel for an item
+ where COL_NAME matches item_name
+ Returns True if a match is found, False otherwise
+ """
+ def contents_includes_name(self, item_name):
+ it = self.contents.get_iter_first()
+ while it:
+ path = self.contents.get_path(it)
+ if self.contents[path][self.COL_NAME] == item_name:
+ return True
+ it = self.contents.iter_next(it)
+ return False
+
+ """
+ Add this item, and any of its dependencies, to the image contents
+ """
+ def include_item(self, item_path, binb=""):
+ name = self[item_path][self.COL_NAME]
+ deps = self[item_path][self.COL_DEPS]
+ cur_inc = self[item_path][self.COL_INC]
+ #print("Adding %s for %s dependency" % (name, binb))
+ if not cur_inc:
+ self[item_path][self.COL_INC] = True
+ self[item_path][self.COL_BINB] = binb
+ if deps:
+ #print("Dependencies of %s are %s" % (name, deps))
+ # add all of the deps and set their binb to this item
+ for dep in deps.split(" "):
+ # FIXME: this skipping virtuals can't be right? Unless we choose only to show target
+ # packages? In which case we should handle this server side...
+ # If the contents model doesn't already contain dep, add it
+ if not dep.startswith("virtual") and not self.contents_includes_name(dep):
+ path = self.find_path_for_item(dep)
+ if path:
+ self.include_item(path, name)
+ else:
+ pass
+
+ """
+ Find the model path for the item_name
+ Returns the path in the model or None
+ """
+ def find_path_for_item(self, item_name):
+ it = self.get_iter_first()
+ path = None
+ while it:
+ path = self.get_path(it)
+ if (self[path][self.COL_NAME] == item_name):
+ return path
+ else:
+ it = self.iter_next(it)
+ return None
+
+ """
+ Empty self.contents by setting the include of each entry to None
+ """
+ def reset(self):
+ it = self.contents.get_iter_first()
+ while it:
+ path = self.contents.get_path(it)
+ opath = self.contents.convert_path_to_child_path(path)
+ self[opath][self.COL_INC] = False
+ self[opath][self.COL_BINB] = ""
+ # As we've just removed the first item...
+ it = self.contents.get_iter_first()
+
+ """
+ Returns True if one of the selected tasks is an image, False otherwise
+ """
+ def targets_contains_image(self):
+ it = self.images.get_iter_first()
+ while it:
+ path = self.images.get_path(it)
+ inc = self.images[path][self.COL_INC]
+ if inc:
+ return True
+ it = self.images.iter_next(it)
+ return False
+
+ """
+ Return a list of all selected items which are not -native or -cross
+ """
+ def get_targets(self):
+ tasks = []
+
+ it = self.contents.get_iter_first()
+ while it:
+ path = self.contents.get_path(it)
+ name = self.contents[path][self.COL_NAME]
+ stype = self.contents[path][self.COL_TYPE]
+ if not name.count('-native') and not name.count('-cross'):
+ tasks.append(name)
+ it = self.contents.iter_next(it)
+ return tasks
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/13] bitbake/event: fix some whitespace issues
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (6 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 07/13] bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 09/13] bitbake/crumbs: update documentation header Joshua Lock
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/event.py | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index 176eeb8..b726b63 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -356,7 +356,6 @@ class TargetsTreeGenerated(Event):
"""
Event when a set of buildable targets has been generated
"""
-
def __init__(self, model):
Event.__init__(self)
self._model = model
@@ -365,10 +364,9 @@ class ConfigFilesFound(Event):
"""
Event when a list of appropriate config files has been generated
"""
-
def __init__(self, variable, values):
Event.__init__(self)
- self._variable = variable
+ self._variable = variable
self._values = values
class MsgBase(Event):
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/13] bitbake/crumbs: update documentation header
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (7 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 08/13] bitbake/event: fix some whitespace issues Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 10/13] bitbake/progress: add method to pulse the progress bar Joshua Lock
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/ui/crumbs/__init__.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/bitbake/lib/bb/ui/crumbs/__init__.py b/bitbake/lib/bb/ui/crumbs/__init__.py
index a4805ed..b7cbe1a 100644
--- a/bitbake/lib/bb/ui/crumbs/__init__.py
+++ b/bitbake/lib/bb/ui/crumbs/__init__.py
@@ -1,5 +1,5 @@
#
-# BitBake UI Implementation
+# Gtk+ UI pieces for BitBake
#
# Copyright (C) 2006-2007 Richard Purdie
#
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/13] bitbake/progress: add method to pulse the progress bar
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (8 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 09/13] bitbake/crumbs: update documentation header Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 11/13] bitbake/cooker: don't drop possible_world ref count Joshua Lock
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
When we're running a long operation with indeterminate duration it's useful
to use the gtk.ProgressBar's pulse method to show that something is happening
but we don't know how long it will take.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/ui/crumbs/progress.py | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/bitbake/lib/bb/ui/crumbs/progress.py b/bitbake/lib/bb/ui/crumbs/progress.py
index 36eca38..ce3a6c3 100644
--- a/bitbake/lib/bb/ui/crumbs/progress.py
+++ b/bitbake/lib/bb/ui/crumbs/progress.py
@@ -15,3 +15,7 @@ class ProgressBar(gtk.Dialog):
def update(self, x, y):
self.progress.set_fraction(float(x)/float(y))
self.progress.set_text("%2d %%" % (x*100/y))
+
+ def pulse(self):
+ self.progress.set_text("Loading...")
+ self.progress.pulse()
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 11/13] bitbake/cooker: don't drop possible_world ref count
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (9 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 10/13] bitbake/progress: add method to pulse the progress bar Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 12/13] bitbake: Add new UI hob, a prototype Gtk+ GUI for creating images Joshua Lock
2011-02-04 8:54 ` [PATCH 13/13] bitbake/progress: make progress dialog modal for parent window Joshua Lock
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
We need this if we want to run the buildWorldTargetList function more than
once, for example in a UI where we can change the MACHINE and DISTRO as much
as we like before triggering a build.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/cooker.py | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index 39cf011..1d84998 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -555,10 +555,6 @@ class BBCooker:
if terminal:
self.status.world_target.add(pn)
- # drop reference count now
- self.status.possible_world = None
- self.status.all_depends = None
-
def interactiveMode( self ):
"""Drop off into a shell"""
try:
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 12/13] bitbake: Add new UI hob, a prototype Gtk+ GUI for creating images
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (10 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 11/13] bitbake/cooker: don't drop possible_world ref count Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
2011-02-04 8:54 ` [PATCH 13/13] bitbake/progress: make progress dialog modal for parent window Joshua Lock
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Hob is a first stab at implementing an interactive GUI for BitBake.
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/ui/crumbs/hobeventhandler.py | 138 ++++++
bitbake/lib/bb/ui/hob.py | 596 +++++++++++++++++++++++++++
2 files changed, 734 insertions(+), 0 deletions(-)
create mode 100644 bitbake/lib/bb/ui/crumbs/hobeventhandler.py
create mode 100644 bitbake/lib/bb/ui/hob.py
diff --git a/bitbake/lib/bb/ui/crumbs/hobeventhandler.py b/bitbake/lib/bb/ui/crumbs/hobeventhandler.py
new file mode 100644
index 0000000..699354c
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hobeventhandler.py
@@ -0,0 +1,138 @@
+#
+# BitBake Graphical GTK User Interface
+#
+# Copyright (C) 2011 Intel Corporation
+#
+# Authored by Joshua Lock <josh@linux.intel.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import gobject
+from bb.ui.crumbs.progress import ProgressBar
+
+progress_total = 0
+
+class HobHandler(gobject.GObject):
+
+ """
+ This object does BitBake event handling for the hob gui.
+ """
+ __gsignals__ = {
+ "machines-updated" : (gobject.SIGNAL_RUN_LAST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ "distros-updated" : (gobject.SIGNAL_RUN_LAST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ "generating-data" : (gobject.SIGNAL_RUN_LAST,
+ gobject.TYPE_NONE,
+ ()),
+ "data-generated" : (gobject.SIGNAL_RUN_LAST,
+ gobject.TYPE_NONE,
+ ())
+ }
+
+ def __init__(self, taskmodel, server):
+ gobject.GObject.__init__(self)
+
+ self.model = taskmodel
+ self.server = server
+ self.current_command = None
+ self.building = False
+
+ self.command_map = {
+ "findConfigFilesDistro" : ("findConfigFiles", "MACHINE", "findConfigFilesMachine"),
+ "findConfigFilesMachine" : ("generateTargetsTree", "classes/image.bbclass", None),
+ "generateTargetsTree" : (None, None, None),
+ }
+
+ def run_next_command(self):
+ # FIXME: this is ugly and I *will* replace it
+ if self.current_command:
+ next_cmd = self.command_map[self.current_command]
+ command = next_cmd[0]
+ argument = next_cmd[1]
+ self.current_command = next_cmd[2]
+ if command == "generateTargetsTree":
+ self.emit("generating-data")
+ self.server.runCommand([command, argument])
+
+ def handle_event(self, event, running_build, pbar=None):
+ if not event:
+ return
+
+ # If we're running a build, use the RunningBuild event handler
+ if self.building:
+ running_build.handle_event(event)
+ elif isinstance(event, bb.event.TargetsTreeGenerated):
+ self.emit("data-generated")
+ if event._model:
+ self.model.populate(event._model)
+
+ elif isinstance(event, bb.event.ConfigFilesFound):
+ var = event._variable
+ if var == "distro":
+ distros = event._values
+ distros.sort()
+ self.emit("distros-updated", distros)
+ elif var == "machine":
+ machines = event._values
+ machines.sort()
+ self.emit("machines-updated", machines)
+
+ elif isinstance(event, bb.command.CommandCompleted):
+ self.run_next_command()
+ elif isinstance(event, bb.event.CacheLoadStarted) and pbar:
+ pbar.set_title("Loading cache")
+ bb.ui.crumbs.hobeventhandler.progress_total = event.total
+ pbar.update(0, bb.ui.crumbs.hobeventhandler.progress_total)
+ elif isinstance(event, bb.event.CacheLoadProgress) and pbar:
+ pbar.update(event.current, bb.ui.crumbs.hobeventhandler.progress_total)
+ elif isinstance(event, bb.event.CacheLoadCompleted) and pbar:
+ pbar.update(bb.ui.crumbs.hobeventhandler.progress_total, bb.ui.crumbs.hobeventhandler.progress_total)
+ elif isinstance(event, bb.event.ParseStarted) and pbar:
+ pbar.set_title("Processing recipes")
+ bb.ui.crumbs.hobeventhandler.progress_total = event.total
+ pbar.update(0, bb.ui.crumbs.hobeventhandler.progress_total)
+ elif isinstance(event, bb.event.ParseProgress) and pbar:
+ pbar.update(event.current, bb.ui.crumbs.hobeventhandler.progress_total)
+ elif isinstance(event, bb.event.ParseCompleted) and pbar:
+ pbar.hide()
+
+ return
+
+ def event_handle_idle_func (self, eventHandler, running_build, pbar):
+ # Consume as many messages as we can in the time available to us
+ event = eventHandler.getEvent()
+ while event:
+ self.handle_event(event, running_build, pbar)
+ event = eventHandler.getEvent()
+ return True
+
+ def set_machine(self, machine):
+ self.server.runCommand(["setVariable", "MACHINE", machine])
+ self.current_command = "findConfigFilesMachine"
+ self.emit("generating-data")
+ self.run_next_command()
+
+ def set_distro(self, distro):
+ self.server.runCommand(["setVariable", "DISTRO", distro])
+
+ def run_build(self, targets):
+ self.building = True
+ self.server.runCommand(["buildTargets", targets, "build"])
+
+ def cancel_build(self):
+ # Note: this may not be the right way to stop an in-progress build
+ self.server.runCommand(["stateStop"])
diff --git a/bitbake/lib/bb/ui/hob.py b/bitbake/lib/bb/ui/hob.py
new file mode 100644
index 0000000..5278881
--- /dev/null
+++ b/bitbake/lib/bb/ui/hob.py
@@ -0,0 +1,596 @@
+#
+# BitBake Graphical GTK User Interface
+#
+# Copyright (C) 2011 Intel Corporation
+#
+# Authored by Joshua Lock <josh@linux.intel.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import gobject
+import gtk
+from bb.ui.crumbs.progress import ProgressBar
+from bb.ui.crumbs.tasklistmodel import TaskListModel
+from bb.ui.crumbs.hobeventhandler import HobHandler
+from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild
+import xmlrpclib
+import logging
+import Queue
+
+class MainWindow (gtk.Window):
+
+ def __init__(self, taskmodel, handler, curr_mach=None, curr_distro=None):
+ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+ self.model = taskmodel
+ self.model.connect("tasklist-populated", self.update_model)
+ self.curr_mach = curr_mach
+ self.curr_distro = curr_distro
+ self.handler = handler
+ self.set_border_width(10)
+ self.connect("delete-event", gtk.main_quit)
+ self.set_title("BitBake Image Creator")
+ self.set_default_size(700, 600)
+
+ self.build = RunningBuild()
+ self.build.connect("build-succeeded", self.running_build_succeeded_cb)
+ self.build.connect("build-failed", self.running_build_failed_cb)
+
+ createview = self.create_build_gui()
+ buildview = self.view_build_gui()
+ self.nb = gtk.Notebook()
+ self.nb.append_page(createview)
+ self.nb.append_page(buildview)
+ self.nb.set_current_page(0)
+ self.nb.set_show_tabs(False)
+ self.add(self.nb)
+ self.generating = False
+
+ def scroll_tv_cb(self, model, path, it, view):
+ view.scroll_to_cell(path)
+
+ def running_build_failed_cb(self, running_build):
+ # FIXME: handle this
+ return
+
+ def running_build_succeeded_cb(self, running_build):
+ label = gtk.Label("Build completed, start another build?")
+ dialog = gtk.Dialog("Build complete",
+ self,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_NO, gtk.RESPONSE_NO,
+ gtk.STOCK_YES, gtk.RESPONSE_YES))
+ dialog.vbox.pack_start(label)
+ label.show()
+ response = dialog.run()
+ dialog.destroy()
+ if not response == gtk.RESPONSE_YES:
+ self.model.reset() # NOTE: really?
+ self.nb.set_current_page(0)
+ return
+
+ def machine_combo_changed_cb(self, combo, handler):
+ mach = combo.get_active_text()
+ if mach != self.curr_mach:
+ self.curr_mach = mach
+ handler.set_machine(mach)
+
+ def update_machines(self, handler, machines):
+ active = 0
+ for machine in machines:
+ self.machine_combo.append_text(machine)
+ if machine == self.curr_mach:
+ self.machine_combo.set_active(active)
+ active = active + 1
+ self.machine_combo.connect("changed", self.machine_combo_changed_cb, handler)
+
+ def update_distros(self, handler, distros):
+ # FIXME: when we add UI for changing distro this will be used
+ return
+
+ def data_generated(self, handler):
+ self.generating = False
+
+ def spin_idle_func(self, pbar):
+ if self.generating:
+ pbar.pulse()
+ return True
+ else:
+ pbar.hide()
+ return False
+
+ def busy(self, handler):
+ self.generating = True
+ pbar = ProgressBar(self)
+ pbar.connect("delete-event", gtk.main_quit) # NOTE: questionable...
+ pbar.pulse()
+ gobject.timeout_add (200,
+ self.spin_idle_func,
+ pbar)
+
+ def update_model(self, model):
+ pkgsaz_model = gtk.TreeModelSort(self.model.packages_model())
+ pkgsaz_model.set_sort_column_id(self.model.COL_NAME, gtk.SORT_ASCENDING)
+ self.pkgsaz_tree.set_model(pkgsaz_model)
+
+ # FIXME: need to implement a custom sort function, as otherwise the column
+ # is re-ordered when toggling the inclusion state (COL_INC)
+ pkgsgrp_model = gtk.TreeModelSort(self.model.packages_model())
+ pkgsgrp_model.set_sort_column_id(self.model.COL_GROUP, gtk.SORT_ASCENDING)
+ self.pkgsgrp_tree.set_model(pkgsgrp_model)
+
+ self.contents_tree.set_model(self.model.contents_model())
+ self.images_tree.set_model(self.model.images_model())
+ self.tasks_tree.set_model(self.model.tasks_model())
+
+ def reset_clicked_cb(self, button):
+ label = gtk.Label("Are you sure you want to reset the image contents?")
+ dialog = gtk.Dialog("Confirm reset", self,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ dialog.vbox.pack_start(label)
+ label.show()
+ response = dialog.run()
+ dialog.destroy()
+ if (response == gtk.RESPONSE_ACCEPT):
+ self.model.reset()
+ return
+
+ def bake_clicked_cb(self, button):
+ if not self.model.targets_contains_image():
+ label = gtk.Label("No image was selected. Just build the selected packages?")
+ dialog = gtk.Dialog("Warning, no image selected",
+ self,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_NO, gtk.RESPONSE_NO,
+ gtk.STOCK_YES, gtk.RESPONSE_YES))
+ dialog.vbox.pack_start(label)
+ label.show()
+ response = dialog.run()
+ dialog.destroy()
+ if not response == gtk.RESPONSE_YES:
+ return
+
+ # Note: We could "squash" the targets list to only include things not brought in by an image
+ task_list = self.model.get_targets()
+ if len(task_list):
+ tasks = " ".join(task_list)
+ # TODO: show a confirmation dialog
+ print("Including these extra tasks in IMAGE_INSTALL: %s" % tasks)
+ else:
+ return
+
+ self.nb.set_current_page(1)
+ self.handler.run_build(task_list)
+
+ return
+
+ def advanced_expander_cb(self, expander, param):
+ return
+
+ def images(self):
+ self.images_tree = gtk.TreeView()
+ self.images_tree.set_headers_visible(True)
+ self.images_tree.set_headers_clickable(False)
+ self.images_tree.set_enable_search(True)
+ self.images_tree.set_search_column(0)
+ self.images_tree.get_selection().set_mode(gtk.SELECTION_NONE)
+
+ col = gtk.TreeViewColumn('Package')
+ col1 = gtk.TreeViewColumn('Description')
+ col2 = gtk.TreeViewColumn('License')
+ col3 = gtk.TreeViewColumn('Include')
+ col3.set_resizable(False)
+
+ self.images_tree.append_column(col)
+ self.images_tree.append_column(col1)
+ self.images_tree.append_column(col2)
+ self.images_tree.append_column(col3)
+
+ cell = gtk.CellRendererText()
+ cell1 = gtk.CellRendererText()
+ cell2 = gtk.CellRendererText()
+ cell3 = gtk.CellRendererToggle()
+ cell3.set_property('activatable', True)
+ cell3.connect("toggled", self.toggle_include_cb, self.images_tree)
+
+ col.pack_start(cell, True)
+ col1.pack_start(cell1, True)
+ col2.pack_start(cell2, True)
+ col3.pack_start(cell3, True)
+
+ col.set_attributes(cell, text=self.model.COL_NAME)
+ col1.set_attributes(cell1, text=self.model.COL_DESC)
+ col2.set_attributes(cell2, text=self.model.COL_LIC)
+ col3.set_attributes(cell3, active=self.model.COL_INC)
+
+ self.images_tree.show()
+
+ scroll = gtk.ScrolledWindow()
+ scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ scroll.set_shadow_type(gtk.SHADOW_IN)
+ scroll.add(self.images_tree)
+
+ return scroll
+
+ def toggle_package(self, path, model):
+ # Convert path to path in original model
+ opath = model.convert_path_to_child_path(path)
+ # current include status
+ inc = self.model[opath][self.model.COL_INC]
+ if inc:
+ self.model.mark(opath)
+ self.model.sweep_up()
+ #self.model.remove_package_full(cpath)
+ else:
+ self.model.include_item(opath)
+ return
+
+ def remove_package_cb(self, cell, path):
+ model = self.model.contents_model()
+ label = gtk.Label("Are you sure you want to remove this item?")
+ dialog = gtk.Dialog("Confirm removal", self,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ dialog.vbox.pack_start(label)
+ label.show()
+ response = dialog.run()
+ dialog.destroy()
+ if (response == gtk.RESPONSE_ACCEPT):
+ self.toggle_package(path, model)
+
+ def toggle_include_cb(self, cell, path, tv):
+ model = tv.get_model()
+ self.toggle_package(path, model)
+
+ def toggle_pkg_include_cb(self, cell, path, tv):
+ # there's an extra layer of models in the packages case.
+ sort_model = tv.get_model()
+ cpath = sort_model.convert_path_to_child_path(path)
+ self.toggle_package(cpath, sort_model.get_model())
+
+ def pkgsaz(self):
+ self.pkgsaz_tree = gtk.TreeView()
+ self.pkgsaz_tree.set_headers_visible(True)
+ self.pkgsaz_tree.set_headers_clickable(True)
+ self.pkgsaz_tree.set_enable_search(True)
+ self.pkgsaz_tree.set_search_column(0)
+ self.pkgsaz_tree.get_selection().set_mode(gtk.SELECTION_NONE)
+
+ col = gtk.TreeViewColumn('Package')
+ col1 = gtk.TreeViewColumn('Description')
+ col1.set_resizable(True)
+ col2 = gtk.TreeViewColumn('License')
+ col2.set_resizable(True)
+ col3 = gtk.TreeViewColumn('Group')
+ col4 = gtk.TreeViewColumn('Include')
+ col4.set_resizable(False)
+
+ self.pkgsaz_tree.append_column(col)
+ self.pkgsaz_tree.append_column(col1)
+ self.pkgsaz_tree.append_column(col2)
+ self.pkgsaz_tree.append_column(col3)
+ self.pkgsaz_tree.append_column(col4)
+
+ cell = gtk.CellRendererText()
+ cell1 = gtk.CellRendererText()
+ cell1.set_property('width-chars', 20)
+ cell2 = gtk.CellRendererText()
+ cell2.set_property('width-chars', 20)
+ cell3 = gtk.CellRendererText()
+ cell4 = gtk.CellRendererToggle()
+ cell4.set_property('activatable', True)
+ cell4.connect("toggled", self.toggle_pkg_include_cb, self.pkgsaz_tree)
+
+ col.pack_start(cell, True)
+ col1.pack_start(cell1, True)
+ col2.pack_start(cell2, True)
+ col3.pack_start(cell3, True)
+ col4.pack_start(cell4, True)
+
+ col.set_attributes(cell, text=self.model.COL_NAME)
+ col1.set_attributes(cell1, text=self.model.COL_DESC)
+ col2.set_attributes(cell2, text=self.model.COL_LIC)
+ col3.set_attributes(cell3, text=self.model.COL_GROUP)
+ col4.set_attributes(cell4, active=self.model.COL_INC)
+
+ self.pkgsaz_tree.show()
+
+ scroll = gtk.ScrolledWindow()
+ scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ scroll.set_shadow_type(gtk.SHADOW_IN)
+ scroll.add(self.pkgsaz_tree)
+
+ return scroll
+
+ def pkgsgrp(self):
+ self.pkgsgrp_tree = gtk.TreeView()
+ self.pkgsgrp_tree.set_headers_visible(True)
+ self.pkgsgrp_tree.set_headers_clickable(False)
+ self.pkgsgrp_tree.set_enable_search(True)
+ self.pkgsgrp_tree.set_search_column(0)
+ self.pkgsgrp_tree.get_selection().set_mode(gtk.SELECTION_NONE)
+
+ col = gtk.TreeViewColumn('Package')
+ col1 = gtk.TreeViewColumn('Description')
+ col1.set_resizable(True)
+ col2 = gtk.TreeViewColumn('License')
+ col2.set_resizable(True)
+ col3 = gtk.TreeViewColumn('Group')
+ col4 = gtk.TreeViewColumn('Include')
+ col4.set_resizable(False)
+
+ self.pkgsgrp_tree.append_column(col)
+ self.pkgsgrp_tree.append_column(col1)
+ self.pkgsgrp_tree.append_column(col2)
+ self.pkgsgrp_tree.append_column(col3)
+ self.pkgsgrp_tree.append_column(col4)
+
+ cell = gtk.CellRendererText()
+ cell1 = gtk.CellRendererText()
+ cell1.set_property('width-chars', 20)
+ cell2 = gtk.CellRendererText()
+ cell2.set_property('width-chars', 20)
+ cell3 = gtk.CellRendererText()
+ cell4 = gtk.CellRendererToggle()
+ cell4.set_property("activatable", True)
+ cell4.connect("toggled", self.toggle_pkg_include_cb, self.pkgsgrp_tree)
+
+ col.pack_start(cell, True)
+ col1.pack_start(cell1, True)
+ col2.pack_start(cell2, True)
+ col3.pack_start(cell3, True)
+ col4.pack_start(cell4, True)
+
+ col.set_attributes(cell, text=self.model.COL_NAME)
+ col1.set_attributes(cell1, text=self.model.COL_DESC)
+ col2.set_attributes(cell2, text=self.model.COL_LIC)
+ col3.set_attributes(cell3, text=self.model.COL_GROUP)
+ col4.set_attributes(cell4, active=self.model.COL_INC)
+
+ self.pkgsgrp_tree.show()
+
+ scroll = gtk.ScrolledWindow()
+ scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ scroll.set_shadow_type(gtk.SHADOW_IN)
+ scroll.add(self.pkgsgrp_tree)
+
+ return scroll
+
+ def tasks(self):
+ self.tasks_tree = gtk.TreeView()
+ self.tasks_tree.set_headers_visible(True)
+ self.tasks_tree.set_headers_clickable(False)
+ self.tasks_tree.set_enable_search(True)
+ self.tasks_tree.set_search_column(0)
+ self.tasks_tree.get_selection().set_mode(gtk.SELECTION_NONE)
+
+ col = gtk.TreeViewColumn('Package')
+ col1 = gtk.TreeViewColumn('Description')
+ col2 = gtk.TreeViewColumn('Include')
+ col2.set_resizable(False)
+
+ self.tasks_tree.append_column(col)
+ self.tasks_tree.append_column(col1)
+ self.tasks_tree.append_column(col2)
+
+ cell = gtk.CellRendererText()
+ cell1 = gtk.CellRendererText()
+ cell2 = gtk.CellRendererToggle()
+ cell2.set_property('activatable', True)
+ cell2.connect("toggled", self.toggle_include_cb, self.tasks_tree)
+
+ col.pack_start(cell, True)
+ col1.pack_start(cell1, True)
+ col2.pack_start(cell2, True)
+
+ col.set_attributes(cell, text=self.model.COL_NAME)
+ col1.set_attributes(cell1, text=self.model.COL_DESC)
+ col2.set_attributes(cell2, active=self.model.COL_INC)
+
+ self.tasks_tree.show()
+
+ scroll = gtk.ScrolledWindow()
+ scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ scroll.set_shadow_type(gtk.SHADOW_IN)
+ scroll.add(self.tasks_tree)
+
+ return scroll
+
+ def cancel_build(self, button):
+ label = gtk.Label("Do you really want to stop this build?")
+ dialog = gtk.Dialog("Cancel build",
+ self,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_NO, gtk.RESPONSE_NO,
+ gtk.STOCK_YES, gtk.RESPONSE_YES))
+ dialog.vbox.pack_start(label)
+ label.show()
+ response = dialog.run()
+ dialog.destroy()
+ if not response == gtk.RESPONSE_YES:
+ self.handler.cancel_build()
+ return
+
+ def view_build_gui(self):
+ vbox = gtk.VBox(False, 6)
+ vbox.show()
+ build_tv = RunningBuildTreeView()
+ build_tv.show()
+ build_tv.set_model(self.build.model)
+ self.build.model.connect("row-inserted", self.scroll_tv_cb, build_tv)
+ scrolled_view = gtk.ScrolledWindow ()
+ scrolled_view.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolled_view.add(build_tv)
+ scrolled_view.show()
+ vbox.pack_start(scrolled_view, expand=True, fill=True)
+ hbox = gtk.HBox(False, 6)
+ hbox.show()
+ vbox.pack_start(hbox, expand=False, fill=False)
+ cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
+ cancel.connect("clicked", self.cancel_build)
+ cancel.show()
+ hbox.pack_end(cancel, expand=False, fill=False)
+
+ return vbox
+
+ def create_build_gui(self):
+ vbox = gtk.VBox(False, 6)
+ vbox.show()
+ hbox = gtk.HBox(False, 6)
+ hbox.show()
+ vbox.pack_start(hbox, expand=False, fill=False)
+
+ label = gtk.Label("Machine:")
+ label.show()
+ hbox.pack_start(label, expand=False, fill=False, padding=6)
+ self.machine_combo = gtk.combo_box_new_text()
+ self.machine_combo.set_active(0)
+ self.machine_combo.show()
+ self.machine_combo.set_tooltip_text("Selects the architecture of the target board for which you would like to build an image.")
+ hbox.pack_start(self.machine_combo, expand=False, fill=False, padding=6)
+
+ ins = gtk.Notebook()
+ vbox.pack_start(ins, expand=True, fill=True)
+ ins.set_show_tabs(True)
+ label = gtk.Label("Images")
+ label.show()
+ ins.append_page(self.images(), tab_label=label)
+ label = gtk.Label("Tasks")
+ label.show()
+ ins.append_page(self.tasks(), tab_label=label)
+ label = gtk.Label("Packages (by Group)")
+ label.show()
+ ins.append_page(self.pkgsgrp(), tab_label=label)
+ label = gtk.Label("Packages (by Name)")
+ label.show()
+ ins.append_page(self.pkgsaz(), tab_label=label)
+ ins.set_current_page(0)
+ ins.show_all()
+
+ hbox = gtk.HBox()
+ hbox.show()
+ vbox.pack_start(hbox, expand=False, fill=False)
+ label = gtk.Label("Image contents:")
+ label.show()
+ hbox.pack_start(label, expand=False, fill=False, padding=6)
+ con = self.contents()
+ con.show()
+ vbox.pack_start(con, expand=True, fill=True)
+
+ #advanced = gtk.Expander(label="Advanced")
+ #advanced.connect("notify::expanded", self.advanced_expander_cb)
+ #advanced.show()
+ #vbox.pack_start(advanced, expand=False, fill=False)
+
+ hbox = gtk.HBox()
+ hbox.show()
+ vbox.pack_start(hbox, expand=False, fill=False)
+ bake = gtk.Button("Bake")
+ bake.connect("clicked", self.bake_clicked_cb)
+ bake.show()
+ hbox.pack_end(bake, expand=False, fill=False, padding=6)
+ reset = gtk.Button("Reset")
+ reset.connect("clicked", self.reset_clicked_cb)
+ reset.show()
+ hbox.pack_end(reset, expand=False, fill=False, padding=6)
+
+ return vbox
+
+ def contents(self):
+ self.contents_tree = gtk.TreeView()
+ self.contents_tree.set_headers_visible(True)
+ self.contents_tree.get_selection().set_mode(gtk.SELECTION_NONE)
+
+ # allow searching in the package column
+ self.contents_tree.set_search_column(0)
+
+ col = gtk.TreeViewColumn('Package')
+ col.set_sort_column_id(0)
+ col1 = gtk.TreeViewColumn('Brought in by')
+ col1.set_resizable(True)
+ col2 = gtk.TreeViewColumn('Remove')
+ col2.set_expand(False)
+
+ self.contents_tree.append_column(col)
+ self.contents_tree.append_column(col1)
+ self.contents_tree.append_column(col2)
+
+ cell = gtk.CellRendererText()
+ cell1 = gtk.CellRendererText()
+ cell1.set_property('width-chars', 20)
+ cell2 = gtk.CellRendererToggle()
+ cell2.connect("toggled", self.remove_package_cb)
+
+ col.pack_start(cell, True)
+ col1.pack_start(cell1, True)
+ col2.pack_start(cell2, True)
+
+ col.set_attributes(cell, text=self.model.COL_NAME)
+ col1.set_attributes(cell1, text=self.model.COL_BINB)
+ col2.set_attributes(cell2, active=self.model.COL_INC)
+
+ self.contents_tree.show()
+
+ scroll = gtk.ScrolledWindow()
+ scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ scroll.set_shadow_type(gtk.SHADOW_IN)
+ scroll.add(self.contents_tree)
+
+ return scroll
+
+def main (server, eventHandler):
+ gobject.threads_init()
+ gtk.gdk.threads_init()
+
+ taskmodel = TaskListModel()
+ handler = HobHandler(taskmodel, server)
+ mach = server.runCommand(["getVariable", "MACHINE"])
+ distro = server.runCommand(["getVariable", "DISTRO"])
+
+ window = MainWindow(taskmodel, handler, mach, distro)
+ window.show_all ()
+ handler.connect("machines-updated", window.update_machines)
+ handler.connect("distros-updated", window.update_distros)
+ handler.connect("generating-data", window.busy)
+ handler.connect("data-generated", window.data_generated)
+ pbar = ProgressBar(window)
+ pbar.connect("delete-event", gtk.main_quit)
+
+ try:
+ # kick the while thing off
+ handler.current_command = "findConfigFilesDistro"
+ server.runCommand(["findConfigFiles", "DISTRO"])
+ except xmlrpclib.Fault:
+ print("XMLRPC Fault getting commandline:\n %s" % x)
+ return 1
+
+ # This timeout function regularly probes the event queue to find out if we
+ # have any messages waiting for us.
+ gobject.timeout_add (100,
+ handler.event_handle_idle_func,
+ eventHandler,
+ window.build,
+ pbar)
+
+ try:
+ gtk.main()
+ except EnvironmentError as ioerror:
+ # ignore interrupted io
+ if ioerror.args[0] == 4:
+ pass
+ finally:
+ server.runCommand(["stateStop"])
+
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 13/13] bitbake/progress: make progress dialog modal for parent window
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
` (11 preceding siblings ...)
2011-02-04 8:54 ` [PATCH 12/13] bitbake: Add new UI hob, a prototype Gtk+ GUI for creating images Joshua Lock
@ 2011-02-04 8:54 ` Joshua Lock
12 siblings, 0 replies; 14+ messages in thread
From: Joshua Lock @ 2011-02-04 8:54 UTC (permalink / raw)
To: poky
From: Joshua Lock <josh@linux.intel.com>
Signed-off-by: Joshua Lock <josh@linux.intel.com>
---
bitbake/lib/bb/ui/crumbs/progress.py | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/bitbake/lib/bb/ui/crumbs/progress.py b/bitbake/lib/bb/ui/crumbs/progress.py
index ce3a6c3..0c7ad96 100644
--- a/bitbake/lib/bb/ui/crumbs/progress.py
+++ b/bitbake/lib/bb/ui/crumbs/progress.py
@@ -3,11 +3,10 @@ import gtk
class ProgressBar(gtk.Dialog):
def __init__(self, parent):
- gtk.Dialog.__init__(self)
+ gtk.Dialog.__init__(self, flags=(gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT))
self.set_title("Parsing metadata, please wait...")
self.set_default_size(500, 0)
self.set_transient_for(parent)
- self.set_destroy_with_parent(True)
self.progress = gtk.ProgressBar()
self.vbox.pack_start(self.progress)
self.show_all()
--
1.7.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2011-02-04 8:54 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-04 8:53 [RFC] [PATCH 00/13] Prototype GUI Image Creator Joshua Lock
2011-02-04 8:53 ` [PATCH 01/13] bitbake/cache: store a list of inherited files in the cache Joshua Lock
2011-02-04 8:53 ` [PATCH 02/13] bitbake: implement command to get all possible targets and their dependencies Joshua Lock
2011-02-04 8:53 ` [PATCH 03/13] bitbake: implement command to find configuration files for a config variable Joshua Lock
2011-02-04 8:53 ` [PATCH 04/13] bitbake/cooker: add generateTargetsTree method Joshua Lock
2011-02-04 8:53 ` [PATCH 05/13] bitbake/cooker: reduce code duplication Joshua Lock
2011-02-04 8:53 ` [PATCH 06/13] bitbake/[cooker|cache]: cache summary, license and group. Add to targets tree Joshua Lock
2011-02-04 8:54 ` [PATCH 07/13] bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass Joshua Lock
2011-02-04 8:54 ` [PATCH 08/13] bitbake/event: fix some whitespace issues Joshua Lock
2011-02-04 8:54 ` [PATCH 09/13] bitbake/crumbs: update documentation header Joshua Lock
2011-02-04 8:54 ` [PATCH 10/13] bitbake/progress: add method to pulse the progress bar Joshua Lock
2011-02-04 8:54 ` [PATCH 11/13] bitbake/cooker: don't drop possible_world ref count Joshua Lock
2011-02-04 8:54 ` [PATCH 12/13] bitbake: Add new UI hob, a prototype Gtk+ GUI for creating images Joshua Lock
2011-02-04 8:54 ` [PATCH 13/13] bitbake/progress: make progress dialog modal for parent window Joshua Lock
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.