mirror of
https://git.yoctoproject.org/poky
synced 2026-05-09 17:39:31 +00:00
081990b2a3
The different code paths for package vs image builds have lead to some bit rot in the package only build and an incompatability between package only builds and the build again mechanism. This patch unifies the code paths and fixes build again for package only builds. Fixes [YOCTO #1480] (Bitbake rev: ab6c63f35739c30df0e8a9d0f1ae982b96e538ed) Signed-off-by: Joshua Lock <josh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
340 lines
14 KiB
Python
340 lines
14 KiB
Python
#
|
|
# 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 logging
|
|
import tempfile
|
|
import datetime
|
|
|
|
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,)),
|
|
"sdk-machines-updated": (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_PYOBJECT,)),
|
|
"distros-updated" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_PYOBJECT,)),
|
|
"package-formats-found" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_PYOBJECT,)),
|
|
"config-found" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_STRING,)),
|
|
"generating-data" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
()),
|
|
"data-generated" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
()),
|
|
"fatal-error" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,)),
|
|
"command-failed" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_STRING,)),
|
|
"reload-triggered" : (gobject.SIGNAL_RUN_LAST,
|
|
gobject.TYPE_NONE,
|
|
(gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,)),
|
|
}
|
|
|
|
(CFG_PATH_LOCAL, CFG_PATH_PRE, CFG_PATH_POST, CFG_PATH_LAYERS, CFG_FILES_DISTRO, CFG_FILES_MACH, CFG_FILES_SDK, FILES_MATCH_CLASS, GENERATE_TGTS, REPARSE_FILES, BUILD_IMAGE) = range(11)
|
|
|
|
def __init__(self, taskmodel, server):
|
|
gobject.GObject.__init__(self)
|
|
|
|
self.current_command = None
|
|
self.building = False
|
|
self.build_toolchain = False
|
|
self.build_toolchain_headers = False
|
|
self.generating = False
|
|
self.build_queue = []
|
|
self.current_phase = None
|
|
self.bbpath_ok = False
|
|
self.bbfiles_ok = False
|
|
self.image_dir = os.path.join(tempfile.gettempdir(), 'hob-images')
|
|
|
|
self.model = taskmodel
|
|
self.server = server
|
|
|
|
self.image_output_types = self.server.runCommand(["getVariable", "IMAGE_FSTYPES"]).split(" ")
|
|
|
|
def run_next_command(self):
|
|
if self.current_command and not self.generating:
|
|
self.emit("generating-data")
|
|
self.generating = True
|
|
|
|
if self.current_command == self.CFG_PATH_LOCAL:
|
|
self.current_command = self.CFG_PATH_PRE
|
|
self.server.runCommand(["findConfigFilePath", "hob-pre.conf"])
|
|
elif self.current_command == self.CFG_PATH_PRE:
|
|
self.current_command = self.CFG_PATH_POST
|
|
self.server.runCommand(["findConfigFilePath", "hob-post.conf"])
|
|
elif self.current_command == self.CFG_PATH_POST:
|
|
self.current_command = self.CFG_PATH_LAYERS
|
|
self.server.runCommand(["findConfigFilePath", "bblayers.conf"])
|
|
elif self.current_command == self.CFG_PATH_LAYERS:
|
|
self.current_command = self.CFG_FILES_DISTRO
|
|
self.server.runCommand(["findConfigFiles", "DISTRO"])
|
|
elif self.current_command == self.CFG_FILES_DISTRO:
|
|
self.current_command = self.CFG_FILES_MACH
|
|
self.server.runCommand(["findConfigFiles", "MACHINE"])
|
|
elif self.current_command == self.CFG_FILES_MACH:
|
|
self.current_command = self.CFG_FILES_SDK
|
|
self.server.runCommand(["findConfigFiles", "MACHINE-SDK"])
|
|
elif self.current_command == self.CFG_FILES_SDK:
|
|
self.current_command = self.FILES_MATCH_CLASS
|
|
self.server.runCommand(["findFilesMatchingInDir", "rootfs_", "classes"])
|
|
elif self.current_command == self.FILES_MATCH_CLASS:
|
|
self.current_command = self.GENERATE_TGTS
|
|
self.server.runCommand(["generateTargetsTree", "classes/image.bbclass"])
|
|
elif self.current_command == self.GENERATE_TGTS:
|
|
if self.generating:
|
|
self.emit("data-generated")
|
|
self.generating = False
|
|
self.current_command = None
|
|
elif self.current_command == self.REPARSE_FILES:
|
|
if self.build_queue:
|
|
self.current_command = self.BUILD_IMAGE
|
|
else:
|
|
self.current_command = self.CFG_PATH_LAYERS
|
|
self.server.runCommand(["resetCooker"])
|
|
self.server.runCommand(["reparseFiles"])
|
|
elif self.current_command == self.BUILD_IMAGE:
|
|
if self.generating:
|
|
self.emit("data-generated")
|
|
self.generating = False
|
|
self.building = True
|
|
self.server.runCommand(["buildTargets", self.build_queue, "build"])
|
|
self.build_queue = []
|
|
self.current_command = None
|
|
|
|
def handle_event(self, event, running_build, pbar):
|
|
if not event:
|
|
return
|
|
|
|
# If we're running a build, use the RunningBuild event handler
|
|
if self.building:
|
|
self.current_phase = "building"
|
|
running_build.handle_event(event)
|
|
elif isinstance(event, bb.event.TargetsTreeGenerated):
|
|
self.current_phase = "data generation"
|
|
if event._model:
|
|
self.model.populate(event._model)
|
|
elif isinstance(event, bb.event.ConfigFilesFound):
|
|
self.current_phase = "configuration lookup"
|
|
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 var == "machine-sdk":
|
|
sdk_machines = event._values
|
|
sdk_machines.sort()
|
|
self.emit("sdk-machines-updated", sdk_machines)
|
|
elif isinstance(event, bb.event.ConfigFilePathFound):
|
|
self.current_phase = "configuration lookup"
|
|
path = event._path
|
|
self.emit("config-found", path)
|
|
elif isinstance(event, bb.event.FilesMatchingFound):
|
|
self.current_phase = "configuration lookup"
|
|
# FIXME: hard coding, should at least be a variable shared between
|
|
# here and the caller
|
|
if event._pattern == "rootfs_":
|
|
formats = []
|
|
for match in event._matches:
|
|
classname, sep, cls = match.rpartition(".")
|
|
fs, sep, format = classname.rpartition("_")
|
|
formats.append(format)
|
|
formats.sort()
|
|
self.emit("package-formats-found", formats)
|
|
elif isinstance(event, bb.command.CommandCompleted):
|
|
self.current_phase = None
|
|
self.run_next_command()
|
|
elif isinstance(event, bb.command.CommandFailed):
|
|
self.emit("command-failed", event.error)
|
|
elif isinstance(event, bb.event.CacheLoadStarted):
|
|
self.current_phase = "cache loading"
|
|
bb.ui.crumbs.hobeventhandler.progress_total = event.total
|
|
pbar.set_text("Loading cache: %s/%s" % (0, bb.ui.crumbs.hobeventhandler.progress_total))
|
|
elif isinstance(event, bb.event.CacheLoadProgress):
|
|
self.current_phase = "cache loading"
|
|
pbar.set_text("Loading cache: %s/%s" % (event.current, bb.ui.crumbs.hobeventhandler.progress_total))
|
|
elif isinstance(event, bb.event.CacheLoadCompleted):
|
|
self.current_phase = None
|
|
pbar.set_text("Loading...")
|
|
elif isinstance(event, bb.event.ParseStarted):
|
|
self.current_phase = "recipe parsing"
|
|
if event.total == 0:
|
|
return
|
|
bb.ui.crumbs.hobeventhandler.progress_total = event.total
|
|
pbar.set_text("Processing recipes: %s/%s" % (0, bb.ui.crumbs.hobeventhandler.progress_total))
|
|
elif isinstance(event, bb.event.ParseProgress):
|
|
self.current_phase = "recipe parsing"
|
|
pbar.set_text("Processing recipes: %s/%s" % (event.current, bb.ui.crumbs.hobeventhandler.progress_total))
|
|
elif isinstance(event, bb.event.ParseCompleted):
|
|
self.current_phase = None
|
|
pbar.set_fraction(1.0)
|
|
pbar.set_text("Loading...")
|
|
elif isinstance(event, logging.LogRecord):
|
|
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
|
|
if event.levelno >= format.CRITICAL:
|
|
self.emit("fatal-error", event.getMessage(), self.current_phase)
|
|
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])
|
|
|
|
def set_sdk_machine(self, sdk_machine):
|
|
self.server.runCommand(["setVariable", "SDKMACHINE", sdk_machine])
|
|
|
|
def set_distro(self, distro):
|
|
self.server.runCommand(["setVariable", "DISTRO", distro])
|
|
|
|
def set_package_format(self, format):
|
|
self.server.runCommand(["setVariable", "PACKAGE_CLASSES", "package_%s" % format])
|
|
|
|
def reload_data(self, config=None):
|
|
img = self.model.selected_image
|
|
selected_packages, _ = self.model.get_selected_packages()
|
|
self.emit("reload-triggered", img, " ".join(selected_packages))
|
|
self.current_command = self.REPARSE_FILES
|
|
self.run_next_command()
|
|
|
|
def set_bbthreads(self, threads):
|
|
self.server.runCommand(["setVariable", "BB_NUMBER_THREADS", threads])
|
|
|
|
def set_pmake(self, threads):
|
|
pmake = "-j %s" % threads
|
|
self.server.runCommand(["setVariable", "BB_NUMBER_THREADS", pmake])
|
|
|
|
def build_targets(self, tgts, configurator, build_type="image"):
|
|
self.build_type = build_type
|
|
targets = []
|
|
nbbp = None
|
|
nbbf = None
|
|
targets.extend(tgts)
|
|
if self.build_toolchain and self.build_toolchain_headers:
|
|
targets.append("meta-toolchain-sdk")
|
|
elif self.build_toolchain:
|
|
targets.append("meta-toolchain")
|
|
self.build_queue = targets
|
|
|
|
if not self.bbpath_ok:
|
|
bbpath = self.server.runCommand(["getVariable", "BBPATH"])
|
|
if self.image_dir in bbpath.split(":"):
|
|
self.bbpath_ok = True
|
|
else:
|
|
nbbp = self.image_dir
|
|
|
|
if not self.bbfiles_ok:
|
|
import re
|
|
pattern = "%s/\*.bb" % self.image_dir
|
|
bbfiles = self.server.runCommand(["getVariable", "BBFILES"]).split(" ")
|
|
for files in bbfiles:
|
|
if re.match(pattern, files):
|
|
self.bbfiles_ok = True
|
|
|
|
if not self.bbfiles_ok:
|
|
nbbf = "%s/*.bb" % self.image_dir
|
|
|
|
if nbbp or nbbf:
|
|
configurator.insertTempBBPath(nbbp, nbbf)
|
|
self.bbpath_ok = True
|
|
self.bbfiles_ok = True
|
|
|
|
self.current_command = self.REPARSE_FILES
|
|
self.run_next_command()
|
|
|
|
def cancel_build(self, force=False):
|
|
if force:
|
|
# Force the cooker to stop as quickly as possible
|
|
self.server.runCommand(["stateStop"])
|
|
else:
|
|
# Wait for tasks to complete before shutting down, this helps
|
|
# leave the workdir in a usable state
|
|
self.server.runCommand(["stateShutdown"])
|
|
|
|
def set_incompatible_license(self, incompatible):
|
|
self.server.runCommand(["setVariable", "INCOMPATIBLE_LICENSE", incompatible])
|
|
|
|
def toggle_toolchain(self, enabled):
|
|
if self.build_toolchain != enabled:
|
|
self.build_toolchain = enabled
|
|
|
|
def toggle_toolchain_headers(self, enabled):
|
|
if self.build_toolchain_headers != enabled:
|
|
self.build_toolchain_headers = enabled
|
|
|
|
def set_fstypes(self, fstypes):
|
|
self.server.runCommand(["setVariable", "IMAGE_FSTYPES", fstypes])
|
|
|
|
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).lstrip(" ")
|
|
self.set_fstypes(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).lstrip(" ")
|
|
self.set_fstypes(fstypes)
|
|
return self.image_output_types
|
|
|
|
def get_image_deploy_dir(self):
|
|
return self.server.runCommand(["getVariable", "DEPLOY_DIR_IMAGE"])
|
|
|
|
def make_temp_dir(self):
|
|
bb.utils.mkdirhier(self.image_dir)
|
|
|
|
def remove_temp_dir(self):
|
|
bb.utils.remove(self.image_dir, True)
|
|
|
|
def get_temp_recipe_path(self, name):
|
|
timestamp = datetime.date.today().isoformat()
|
|
image_file = "hob-%s-variant-%s.bb" % (name, timestamp)
|
|
recipepath = os.path.join(self.image_dir, image_file)
|
|
return recipepath
|