[OE-core] [PATCH 1/1] Add wic support to generate rootfs image for uboot
Saul Wold
sgw at linux.intel.com
Thu Jun 12 02:49:02 UTC 2014
On 06/10/2014 06:41 AM, Adrian Calianu wrote:
> Add support in wic to build ramdisk uboot images from list of packages or
> from an existing rootfs folder.
>
> Some prerequisites are required for this new build setup:
> ../poky/scripts/lib/image/config/wic.conf
> [create]
> arch=target_arch (example: powerpc, arm, x86)
> pkgmgr=opkg
> repourl=http://example.distro/p2020rdb/ipk/all http://example.distro/p2020rdb/ipk/p2020rdb http://example.distro/p2020rdb/ipk/ppce500v2
>
> 1) Build an rootfs image from an existing bitbake build:
> wic create ../poky/scripts/lib/image/canned-wks/uboot.wks -e core-image-minimal -o .../output
>
> 2) Build an rootfs image from an existing rootfs and native_sysroot:
> wic create ../poky/scripts/lib/image/canned-wks/uboot.wks -r .../path_to_rootfs -n .../path_to_native_sysroot -o .../output
>
> 3) Build an rootfs image only from a package list (on wks file):
>
> Add the package list to be installed as rootfs on ../poky/scripts/lib/image/canned-wks/uboot.wks:
> %packages
> packagegroup-core-boot
> pramfs-init
> run-postinsts
> packagegroup-core-ssh-dropbear
> %end
>
> Generate rootfs image:
> wic create ../poky/scripts/lib/image/canned-wks/uboot.wks -n .../path_to_native_sysroot -o .../output
>
> Signed-off-by: Adrian Calianu <adrian.calianu at enea.com>
> ---
> scripts/lib/image/canned-wks/uboot.wks | 17 +
> scripts/lib/image/config/wic.conf | 4 +
> scripts/lib/image/engine.py | 7 +-
> scripts/lib/mic/imager/direct.py | 4 +
> .../lib/mic/kickstart/custom_commands/partition.py | 128 ++++
> scripts/lib/mic/plugin.py | 11 +-
> scripts/lib/mic/pluginbase.py | 9 +
> scripts/lib/mic/plugins/source/uboot.py | 173 +++++
> scripts/lib/mic/utils/oe/package_manager.py | 810 ++++++++++++++++++++
> scripts/wic | 88 ++-
> 10 files changed, 1219 insertions(+), 32 deletions(-)
> create mode 100644 scripts/lib/image/canned-wks/uboot.wks
> create mode 100644 scripts/lib/mic/plugins/source/uboot.py
> create mode 100644 scripts/lib/mic/utils/oe/package_manager.py
>
This patch does not seem to be applying cleanly, can you please verify
that it was produced against the latest master?
Thanks
Sau!
> diff --git a/scripts/lib/image/canned-wks/uboot.wks b/scripts/lib/image/canned-wks/uboot.wks
> new file mode 100644
> index 0000000..7de0572
> --- /dev/null
> +++ b/scripts/lib/image/canned-wks/uboot.wks
> @@ -0,0 +1,17 @@
> +# short-description: . Create a ramdisk image for U-Boot
> +# long-description: Creates a ramdisk image for U-Boot that user
> +# can directly load it into ram through tftp
> +#
> +# part - is a wic command that drive the process of generating a valid file system
> +# - --source=uboot : wic plugin that generates a ramdisk image for U-Boot
> +# - --fstype=ext2 : file system type( ext2 / ext3 / ext 4)
> +#
> +# %packages %end - option to provide a list of packages that will be installed
> +# into rootfs. All packages dependencies will be installed by
> +# package manager(default opkg).
> +
> +
> +part / --source=uboot --fstype=ext2 --label imageName --align 1024
> +
> +%packages
> +%end
> diff --git a/scripts/lib/image/config/wic.conf b/scripts/lib/image/config/wic.conf
> index e96d6ae..2a2750b 100644
> --- a/scripts/lib/image/config/wic.conf
> +++ b/scripts/lib/image/config/wic.conf
> @@ -4,4 +4,8 @@ distro_name = OpenEmbedded
>
> [create]
> ; settings for create subcommand
> +; repourl=http://linux.com/ipk/all http://linux.com/ipk/target http://linux.com/ipk/arch
> +arch=powerpc
> +pkgmgr=opkg
> runtime=native
> +install_pkgs=source
> diff --git a/scripts/lib/image/engine.py b/scripts/lib/image/engine.py
> index 3bda1bf..1256236 100644
> --- a/scripts/lib/image/engine.py
> +++ b/scripts/lib/image/engine.py
> @@ -96,9 +96,10 @@ def build_canned_image_list(dl):
> layers_path = get_bitbake_var("BBLAYERS")
> canned_wks_layer_dirs = []
>
> - for layer_path in layers_path.split():
> - path = os.path.join(layer_path, SCRIPTS_CANNED_IMAGE_DIR)
> - canned_wks_layer_dirs.append(path)
> + if layers_path is not None:
> + for layer_path in layers_path.split():
> + path = os.path.join(layer_path, SCRIPTS_CANNED_IMAGE_DIR)
> + canned_wks_layer_dirs.append(path)
>
> path = os.path.join(dl, CANNED_IMAGE_DIR)
> canned_wks_layer_dirs.append(path)
> diff --git a/scripts/lib/mic/imager/direct.py b/scripts/lib/mic/imager/direct.py
> index 2cf4c8d..fef9d0e 100644
> --- a/scripts/lib/mic/imager/direct.py
> +++ b/scripts/lib/mic/imager/direct.py
> @@ -262,6 +262,10 @@ class DirectImageCreator(BaseImageCreator):
> # when/if we need to actually do package selection we
> # should modify things to use those objects, but for now
> # we can avoid that.
> +
> + p.install_pkgs(self, self.workdir, self.oe_builddir, self.rootfs_dir,
> + self.bootimg_dir, self.kernel_dir, self.native_sysroot)
> +
> p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
> self.bootimg_dir, self.kernel_dir, self.native_sysroot)
>
> diff --git a/scripts/lib/mic/kickstart/custom_commands/partition.py b/scripts/lib/mic/kickstart/custom_commands/partition.py
> index 6b575c0..450d2d4 100644
> --- a/scripts/lib/mic/kickstart/custom_commands/partition.py
> +++ b/scripts/lib/mic/kickstart/custom_commands/partition.py
> @@ -31,7 +31,11 @@ from mic.utils.oe.misc import *
> from mic.kickstart.custom_commands import *
> from mic.plugin import pluginmgr
>
> +import os
> +from mic.utils.oe.package_manager import *
> +
> partition_methods = {
> + "do_install_pkgs":None,
> "do_stage_partition":None,
> "do_prepare_partition":None,
> "do_configure_partition":None,
> @@ -115,6 +119,102 @@ class Wic_PartData(Mic_PartData):
> else:
> return 0
>
> + def install_pkgs(self, creator, cr_workdir, oe_builddir, rootfs_dir,
> + bootimg_dir, kernel_dir, native_sysroot):
> + """
> + Prepare content for individual partitions, installing packages.
> + """
> +
> + if not self.source:
> + return
> +
> + self._source_methods = pluginmgr.get_source_plugin_methods(self.source, partition_methods)
> + self._source_methods["do_install_pkgs"](self, creator,
> + cr_workdir,
> + oe_builddir,
> + rootfs_dir,
> + bootimg_dir,
> + kernel_dir,
> + native_sysroot)
> +
> + def install_pkgs_ipk(self, cr_workdir, oe_builddir, rootfs_dir,
> + native_sysroot, packages, repourl):
> + """
> + Install packages specified into wks file using opkg package manager.
> + This method is dependend on bb module.
> + """
> +
> + gVar = {}
> + gVar["DEPLOY_DIR_IPK"] = os.path.join(oe_builddir, "tmp/deploy/ipk")
> +
> + # Run postinstall scripts even in offline mode
> + # Use the arch priority package rather than higher version one if more than one candidate is found.
> + #d.setVar("OPKG_ARGS", "--force_postinstall --prefer-arch-to-version")
> + gVar["OPKG_ARGS"] = "--force_postinstall"
> +
> + # OPKG path relative to /output_path
> + gVar["OPKGLIBDIR"] = "var/lib"
> +
> + source_url = repourl.split()
> +
> + # Generate feed uri's names, it doesn't seem to matter what name they have
> + feed_uris = ""
> + cnt = 0
> + archs = ""
> + for url in source_url:
> + feed_uris += "cl_def_feed%d##%s\n" % (cnt, url)
> + cnt += 1
> + head, tail = os.path.split(url)
> + archs += " " + tail
> +
> + # IPK_FEED_URIS with special formating defines the URI's used as source for packages
> + gVar['IPK_FEED_URIS'] = feed_uris
> +
> + gVar['BUILD_IMAGES_FROM_FEEDS'] = "1"
> +
> + # We need to provide sysroot for utilities
> + gVar['STAGING_DIR_NATIVE'] = native_sysroot
> +
> + # Set WORKDIR for output
> + gVar['WORKDIR'] = cr_workdir
> +
> + # Set TMPDIR for output
> + gVar['TMPDIR'] = os.path.join(cr_workdir, "tmp")
> +
> + if 'ROOTFS_DIR' in rootfs_dir:
> + target_dir = rootfs_dir['ROOTFS_DIR']
> + elif os.path.isdir(rootfs_dir):
> + target_dir = rootfs_dir
> + else:
> + msg = "Couldn't find --rootfs-dir=%s connection"
> + msg += " or it is not a valid path, exiting"
> + msger.error(msg % rootfs_dir)
> +
> + # Need native sysroot /usr/bin/ for opkg-cl
> + # chnage PATH var to avoid issues with host tools
> + defpath = os.environ['PATH']
> + os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:"
> +
> + pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
> + pseudo += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % target_dir
> + pseudo += "export PSEUDO_PASSWD=%s;" % target_dir
> + pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
> + pseudo += "%s/usr/bin/pseudo " % native_sysroot
> +
> + pm = WicOpkgPM(gVar,
> + target_dir,
> + 'opkg.conf',
> + archs,
> + pseudo,
> + native_sysroot)
> +
> + pm.update()
> +
> + pm.install(packages)
> +
> + os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/"
> +
> +
> def prepare(self, cr, cr_workdir, oe_builddir, rootfs_dir, bootimg_dir,
> kernel_dir, native_sysroot):
> """
> @@ -225,6 +325,34 @@ class Wic_PartData(Mic_PartData):
>
> return 0
>
> + def prepare_for_uboot(self, arch, cr_workdir, oe_builddir, rootfs_dir,
> + native_sysroot):
> + """
> + Generates u-boot image from source_file( ext2/3/4 )
> +
> + """
> + pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
> + pseudo += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % rootfs_dir
> + pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir
> + pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
> + pseudo += "%s/usr/bin/pseudo " % native_sysroot
> +
> + # 1) compress image
> + rootfs = self.source_file
> + rootfs_gzip = "%s.gz" % rootfs
> + gzip_cmd = "gzip -f -9 -c %s > %s" % (rootfs, rootfs_gzip)
> + rc, out = exec_native_cmd(pseudo + gzip_cmd, native_sysroot)
> +
> + # 2) image for U-Boot
> + rootfs_uboot = "%s.u-boot" % rootfs_gzip
> + mkimage_cmd = "mkimage -A %s -O linux -T ramdisk -C gzip -n %s -d %s %s" % \
> + (arch, self.label, rootfs_gzip, rootfs_uboot)
> + rc, out = exec_native_cmd(pseudo + mkimage_cmd, native_sysroot)
> +
> + msger.info("\n\n\tThe new U-Boot ramdisk image can be found here:\n\t\t%s\n\n" % rootfs_uboot)
> +
> + return 0
> +
> def prepare_rootfs_btrfs(self, cr_workdir, oe_builddir, rootfs_dir,
> native_sysroot, pseudo):
> """
> diff --git a/scripts/lib/mic/plugin.py b/scripts/lib/mic/plugin.py
> index bec33d6..585fd6d 100644
> --- a/scripts/lib/mic/plugin.py
> +++ b/scripts/lib/mic/plugin.py
> @@ -53,12 +53,13 @@ class PluginMgr(object):
> self.layers_path = get_bitbake_var("BBLAYERS")
> layer_dirs = []
>
> - for layer_path in self.layers_path.split():
> - path = os.path.join(layer_path, SCRIPTS_PLUGIN_DIR, ptype)
> - layer_dirs.append(path)
> + if self.layers_path is not None:
> + for layer_path in self.layers_path.split():
> + path = os.path.join(layer_path, SCRIPTS_PLUGIN_DIR, ptype)
> + layer_dirs.append(path)
>
> - path = os.path.join(dl, ptype)
> - layer_dirs.append(path)
> + path = os.path.join(dl, ptype)
> + layer_dirs.append(path)
>
> return layer_dirs
>
> diff --git a/scripts/lib/mic/pluginbase.py b/scripts/lib/mic/pluginbase.py
> index 9cf4c62..881d996 100644
> --- a/scripts/lib/mic/pluginbase.py
> +++ b/scripts/lib/mic/pluginbase.py
> @@ -89,6 +89,15 @@ class SourcePlugin(_Plugin):
> """
>
> @classmethod
> + def do_install_pkgs(self, part, creator, cr_workdir, oe_builddir, rootfs_dir,
> + bootimg_dir, kernel_dir, native_sysroot):
> + """
> + Called before partitions have been prepared and assembled into a
> + disk image. Install packages into rootfs
> + """
> + msger.debug("SourcePlugin: do_install_pkgs: part %s" % part)
> +
> + @classmethod
> def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir,
> bootimg_dir, kernel_dir, native_sysroot):
> """
> diff --git a/scripts/lib/mic/plugins/source/uboot.py b/scripts/lib/mic/plugins/source/uboot.py
> new file mode 100644
> index 0000000..57cb3cf
> --- /dev/null
> +++ b/scripts/lib/mic/plugins/source/uboot.py
> @@ -0,0 +1,173 @@
> +# ex:ts=4:sw=4:sts=4:et
> +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
> +#
> +# Copyright (c) 2014, Enea AB.
> +# All rights reserved.
> +#
> +# 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.
> +#
> +# DESCRIPTION
> +# This implements the 'uboot' source plugin class for 'wic'
> +#
> +# AUTHORS
> +# Adrian Calianu <adrian.calianu (at] enea.com>
> +#
> +
> +import os
> +import shutil
> +import re
> +import tempfile
> +
> +from mic import kickstart, chroot, msger
> +from mic.utils import misc, fs_related, errors, runner, cmdln
> +from mic.conf import configmgr
> +from mic.plugin import pluginmgr
> +from mic.utils.partitionedfs import PartitionedMount
> +import mic.imager.direct as direct
> +from mic.pluginbase import SourcePlugin
> +from mic.utils.oe.misc import *
> +from mic.imager.direct import DirectImageCreator
> +
> +def create_local_rootfs(part, creator, cr_workdir, krootfs_dir, native_sysroot):
> + # In order to have a full control over rootfs we will make a local copy under workdir
> + # and change rootfs_dir to new location.
> + # In this way we can install more than one ROOTFS_DIRs and/or use
> + # an empty rootfs to install packages, so a rootfs could be generated only from pkgs
> + # TBD: create workdir/rootfs ; copy rootfs-> workdir/rootfs; set rootfs=workdir/rootfs
> +
> + cr_workdir = os.path.abspath(cr_workdir)
> + new_rootfs_dir = "%s/rootfs_%s" % (cr_workdir, creator.name)
> +
> + rootfs_exists = 1
> + if part.rootfs is None:
> + if not 'ROOTFS_DIR' in krootfs_dir:
> + msg = "Couldn't find --rootfs-dir, exiting, "
> + msger.info(msg)
> + rootfs_exists = 0
> + rootfs_dir = krootfs_dir['ROOTFS_DIR']
> + creator.rootfs_dir['ROOTFS_DIR'] = new_rootfs_dir
> + else:
> + if part.rootfs in krootfs_dir:
> + rootfs_dir = krootfs_dir[part.rootfs]
> + creator.rootfs_dir[part.rootfs] = new_rootfs_dir
> + elif os.path.isdir(part.rootfs):
> + rootfs_dir = part.rootfs
> + part.rootfs = new_rootfs_dir
> + else:
> + msg = "Couldn't find --rootfs-dir=%s connection"
> + msg += " or it is not a valid path, exiting"
> + msger.info(msg % part.rootfs)
> + rootfs_exists = 0
> + creator.rootfs_dir['ROOTFS_DIR'] = new_rootfs_dir
> +
> + pseudox = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
> + pseudox += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % new_rootfs_dir
> + pseudox += "export PSEUDO_PASSWD=%s;" % new_rootfs_dir
> + pseudox += "export PSEUDO_NOSYMLINKEXP=1;"
> + pseudox += "%s/usr/bin/pseudo " % native_sysroot
> +
> + mkdir_cmd = "mkdir %s" % (new_rootfs_dir)
> + # rc, out = exec_native_cmd(pseudox + mkdir_cmd, native_sysroot)
> + rc, out = exec_cmd(mkdir_cmd, True)
> +
> + if rootfs_exists == 1 and os.path.isdir(rootfs_dir):
> + defpath = os.environ['PATH']
> + os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:"
> +
> + rootfs_dir = os.path.abspath(rootfs_dir)
> +
> + pseudoc = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
> + pseudoc += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % rootfs_dir
> + pseudoc += "export PSEUDO_PASSWD=%s;" % rootfs_dir
> + pseudoc += "export PSEUDO_NOSYMLINKEXP=1;"
> + pseudoc += "%s/usr/bin/pseudo " % native_sysroot
> +
> + tarc_cmd = "tar cvpf %s/rootfs.tar -C %s ." % (cr_workdir, rootfs_dir)
> + rc, out = exec_native_cmd(pseudoc + tarc_cmd, native_sysroot)
> +
> + tarx_cmd = "tar xpvf %s/rootfs.tar -C %s" % (cr_workdir, new_rootfs_dir)
> + rc, out = exec_native_cmd(pseudox + tarx_cmd, native_sysroot)
> +
> + rm_cmd = "rm %s/rootfs.tar" % cr_workdir
> + rc, out = exec_cmd(rm_cmd, True)
> +
> + os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/"
> +
> + return new_rootfs_dir
> +
> +class UBootPlugin(SourcePlugin):
> + name = 'uboot'
> +
> + @classmethod
> + def do_install_pkgs(self, part, creator, cr_workdir, oe_builddir, krootfs_dir,
> + bootimg_dir, kernel_dir, native_sysroot):
> + """
> + Called before all partitions have been prepared and assembled into a
> + disk image. Intall packages based on wic configuration.
> + """
> +
> + # set new rootfs_dir
> + rootfs_dir = create_local_rootfs(part, creator, cr_workdir, krootfs_dir, native_sysroot)
> +
> + # wks file parsing
> + packages = kickstart.get_packages(creator.ks)
> +
> + # wic.conf file parsing = found under 'creator'
> + local_pkgs_path = creator._local_pkgs_path
> + repourl = creator.repourl
> + pkgmgr = creator.pkgmgr_name
> +
> + # install packages
> + if packages and pkgmgr in ["opkg"]:
> + if len(repourl) > 0 :
> + part.install_pkgs_ipk(cr_workdir, oe_builddir, rootfs_dir, native_sysroot,
> + packages, repourl)
> + else:
> + msger.error("No packages repository provided in wic.conf")
> +
> + @classmethod
> + def do_prepare_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir,
> + kernel_dir, krootfs_dir, native_sysroot):
> + """
> + Called to do the actual content population for a partition i.e. it
> + 'prepares' the partition to be incorporated into the image.
> + In this case, prepare content for legacy bios boot partition.
> + """
> + if part.rootfs is None:
> + if not 'ROOTFS_DIR' in krootfs_dir:
> + msg = "Couldn't find --rootfs-dir, exiting"
> + msger.error(msg)
> + rootfs_dir = krootfs_dir['ROOTFS_DIR']
> + else:
> + if part.rootfs in krootfs_dir:
> + rootfs_dir = krootfs_dir[part.rootfs]
> + elif os.path.isdir(part.rootfs):
> + rootfs_dir = part.rootfs
> + else:
> + msg = "Couldn't find --rootfs-dir=%s connection"
> + msg += " or it is not a valid path, exiting"
> + msger.error(msg % part.rootfs)
> +
> + part.set_rootfs(rootfs_dir)
> +
> + # change partition label wich will reflect into the final rootfs image name
> + part.label = "%s_%s" % (part.label, cr.name)
> +
> + defpath = os.environ['PATH']
> + os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:"
> +
> + part.prepare_rootfs(cr_workdir, oe_builddir, rootfs_dir, native_sysroot)
> + part.prepare_for_uboot(cr.target_arch,cr_workdir, oe_builddir, rootfs_dir, native_sysroot)
> +
> + os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/"
> diff --git a/scripts/lib/mic/utils/oe/package_manager.py b/scripts/lib/mic/utils/oe/package_manager.py
> new file mode 100644
> index 0000000..92ce98e
> --- /dev/null
> +++ b/scripts/lib/mic/utils/oe/package_manager.py
> @@ -0,0 +1,810 @@
> +# ex:ts=4:sw=4:sts=4:et
> +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
> +#
> +# Copyright (c) 2014, Enea AB.
> +# All rights reserved.
> +#
> +# 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.
> +#
> +# DESCRIPTION
> +# This implements the opkg package manager wrapper as a combination of
> +# meta/lib/oe/package_manager.py and bitbake/lib/bb/utils.py files and
> +# adaptation of those files to 'wic'.
> +#
> +# AUTHORS
> +# Adrian Calianu <adrian.calianu (at] enea.com>
> +#
> +# This file incorporates work covered by the following copyright and
> +# permission notice:
> +#
> +# meta/COPYING.GPLv2 (GPLv2)
> +# meta/COPYING.MIT (MIT)
> +#
> +# Copyright (C) 2004 Michael Lauer
> +#
> +# Permission to use, copy, modify, and/or distribute this software
> +# for any purpose with or without fee is hereby granted, provided
> +# that the above copyright notice and this permission notice appear
> +# in all copies.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
> +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
> +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
> +# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
> +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
> +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
> +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> +
> +
> +from abc import ABCMeta, abstractmethod
> +import os
> +import glob
> +import subprocess
> +import shutil
> +import multiprocessing
> +import re
> +import errno
> +import fcntl
> +
> +from mic.utils.oe.misc import *
> +from mic import msger
> +
> +def mkdirhier(directory):
> + """Create a directory like 'mkdir -p', but does not complain if
> + directory already exists like os.makedirs
> + """
> +
> + try:
> + os.makedirs(directory)
> + except OSError as e:
> + if e.errno != errno.EEXIST:
> + raise e
> +
> +def remove(path, recurse=False):
> + """Equivalent to rm -f or rm -rf"""
> + if not path:
> + return
> + if recurse:
> + # shutil.rmtree(name) would be ideal but its too slow
> + subprocess.call(['rm', '-rf'] + glob.glob(path))
> + return
> + for name in glob.glob(path):
> + try:
> + os.unlink(name)
> + except OSError as exc:
> + if exc.errno != errno.ENOENT:
> + raise
> +
> +def lockfile(name, shared=False, retry=True):
> + """
> + Use the file fn as a lock file, return when the lock has been acquired.
> + Returns a variable to pass to unlockfile().
> + """
> + dirname = os.path.dirname(name)
> + mkdirhier(dirname)
> +
> + if not os.access(dirname, os.W_OK):
> + logger.error("Unable to acquire lock '%s', directory is not writable",
> + name)
> + sys.exit(1)
> +
> + op = fcntl.LOCK_EX
> + if shared:
> + op = fcntl.LOCK_SH
> + if not retry:
> + op = op | fcntl.LOCK_NB
> +
> + while True:
> + # If we leave the lockfiles lying around there is no problem
> + # but we should clean up after ourselves. This gives potential
> + # for races though. To work around this, when we acquire the lock
> + # we check the file we locked was still the lock file on disk.
> + # by comparing inode numbers. If they don't match or the lockfile
> + # no longer exists, we start again.
> +
> + # This implementation is unfair since the last person to request the
> + # lock is the most likely to win it.
> +
> + try:
> + lf = open(name, 'a+')
> + fileno = lf.fileno()
> + fcntl.flock(fileno, op)
> + statinfo = os.fstat(fileno)
> + if os.path.exists(lf.name):
> + statinfo2 = os.stat(lf.name)
> + if statinfo.st_ino == statinfo2.st_ino:
> + return lf
> + lf.close()
> + except Exception:
> + try:
> + lf.close()
> + except Exception:
> + pass
> + pass
> + if not retry:
> + return None
> +
> +def unlockfile(lf):
> + """
> + Unlock a file locked using lockfile()
> + """
> + try:
> + # If we had a shared lock, we need to promote to exclusive before
> + # removing the lockfile. Attempt this, ignore failures.
> + fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
> + os.unlink(lf.name)
> + except (IOError, OSError):
> + pass
> + fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
> + lf.close()
> +
> +def which(path, item, direction = 0, history = False):
> + """
> + Locate a file in a PATH
> + """
> +
> + hist = []
> + paths = (path or "").split(':')
> + if direction != 0:
> + paths.reverse()
> +
> + for p in paths:
> + next = os.path.join(p, item)
> + hist.append(next)
> + if os.path.exists(next):
> + if not os.path.isabs(next):
> + next = os.path.abspath(next)
> + if history:
> + return next, hist
> + return next
> +
> + if history:
> + return "", hist
> + return ""
> +
> +
> +
> +# this can be used by all PM backends to create the index files in parallel
> +def wic_create_index(arg):
> + index_cmd = arg
> +
> + try:
> + msger.info("Executing '%s' ..." % index_cmd)
> + subprocess.check_output(index_cmd, stderr=subprocess.STDOUT, shell=True)
> + except subprocess.CalledProcessError as e:
> + return("Index creation command '%s' failed with return code %d:\n%s" %
> + (e.cmd, e.returncode, e.output))
> +
> + return None
> +
> +
> +class WicIndexer(object):
> + __metaclass__ = ABCMeta
> +
> + def __init__(self, d, deploy_dir):
> + self.d = d
> + self.deploy_dir = deploy_dir
> +
> + @abstractmethod
> + def write_index(self):
> + pass
> +
> +class WicOpkgIndexer(WicIndexer):
> + def write_index(self):
> + arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS",
> + "SDK_PACKAGE_ARCHS",
> + "MULTILIB_ARCHS"]
> +
> + opkg_index_cmd = which(os.getenv('PATH'), "opkg-make-index")
> +
> + if not os.path.exists(os.path.join(self.deploy_dir, "Packages")):
> + open(os.path.join(self.deploy_dir, "Packages"), "w").close()
> +
> + index_cmds = []
> + for arch_var in arch_vars:
> + if self.d.has_key(arch_var):
> + archs = self.d[arch_var]
> + else:
> + archs = None
> +
> + if archs is None:
> + continue
> +
> + for arch in archs.split():
> + pkgs_dir = os.path.join(self.deploy_dir, arch)
> + pkgs_file = os.path.join(pkgs_dir, "Packages")
> +
> + if not os.path.isdir(pkgs_dir):
> + continue
> +
> + if not os.path.exists(pkgs_file):
> + open(pkgs_file, "w").close()
> +
> + index_cmds.append('%s -r %s -p %s -m %s' %
> + (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir))
> +
> + if len(index_cmds) == 0:
> + msger.info("There are no packages in %s!" % self.deploy_dir)
> + return
> +
> + nproc = multiprocessing.cpu_count()
> + pool = multiprocessing.Pool(nproc)
> + results = list(pool.imap(wic_create_index, index_cmds))
> + pool.close()
> + pool.join()
> +
> + for result in results:
> + if result is not None:
> + return(result)
> +
> +class WicPkgsList(object):
> + __metaclass__ = ABCMeta
> +
> + def __init__(self, d, rootfs_dir):
> + self.d = d
> + self.rootfs_dir = rootfs_dir
> +
> + @abstractmethod
> + def list(self, format=None):
> + pass
> +
> +
> +class WicOpkgPkgsList(WicPkgsList):
> + def __init__(self, d, rootfs_dir, config_file):
> + super(WicOpkgPkgsList, self).__init__(d, rootfs_dir)
> +
> + self.opkg_cmd = which(os.getenv('PATH'), "opkg-cl")
> + self.opkg_args = "-f %s -o %s " % (config_file, rootfs_dir)
> + if self.d.has_key("OPKG_ARGS"):
> + self.opkg_args += self.d["OPKG_ARGS"]
> +
> + def list(self, format=None):
> + opkg_query_cmd = which(os.getenv('PATH'), "opkg-query-helper.py")
> +
> + if format == "arch":
> + cmd = "%s %s status | %s -a" % \
> + (self.opkg_cmd, self.opkg_args, opkg_query_cmd)
> + elif format == "file":
> + cmd = "%s %s status | %s -f" % \
> + (self.opkg_cmd, self.opkg_args, opkg_query_cmd)
> + elif format == "ver":
> + cmd = "%s %s status | %s -v" % \
> + (self.opkg_cmd, self.opkg_args, opkg_query_cmd)
> + elif format == "deps":
> + cmd = "%s %s status | %s" % \
> + (self.opkg_cmd, self.opkg_args, opkg_query_cmd)
> + else:
> + cmd = "%s %s list_installed | cut -d' ' -f1" % \
> + (self.opkg_cmd, self.opkg_args)
> +
> + try:
> + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True).strip()
> + except subprocess.CalledProcessError as e:
> + msger.error("Cannot get the installed packages list. Command '%s' "
> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
> +
> + if output and format == "file":
> + tmp_output = ""
> + for line in output.split('\n'):
> + pkg, pkg_file, pkg_arch = line.split()
> + full_path = os.path.join(self.rootfs_dir, pkg_arch, pkg_file)
> + if os.path.exists(full_path):
> + tmp_output += "%s %s %s\n" % (pkg, full_path, pkg_arch)
> + else:
> + tmp_output += "%s %s %s\n" % (pkg, pkg_file, pkg_arch)
> +
> + output = tmp_output
> +
> + return output
> +
> +
> +class WicPackageManager(object):
> + """
> + This is an abstract class. Do not instantiate this directly.
> + """
> + __metaclass__ = ABCMeta
> +
> + def __init__(self, d, pseudo, native_sysroot):
> + self.d = d
> + self.deploy_dir = None
> + self.deploy_lock = None
> + if self.d.has_key('PACKAGE_FEED_URIS'):
> + self.feed_uris = self.d['PACKAGE_FEED_URIS']
> + else:
> + self.feed_uris = ""
> + self.pseudo = pseudo
> + self.native_sysroot = native_sysroot
> +
> + """
> + Update the package manager package database.
> + """
> + @abstractmethod
> + def update(self):
> + pass
> +
> + """
> + Install a list of packages. 'pkgs' is a list object. If 'attempt_only' is
> + True, installation failures are ignored.
> + """
> + @abstractmethod
> + def install(self, pkgs, attempt_only=False):
> + pass
> +
> + """
> + Remove a list of packages. 'pkgs' is a list object. If 'with_dependencies'
> + is False, the any dependencies are left in place.
> + """
> + @abstractmethod
> + def remove(self, pkgs, with_dependencies=True):
> + pass
> +
> + """
> + This function creates the index files
> + """
> + @abstractmethod
> + def write_index(self):
> + pass
> +
> + @abstractmethod
> + def remove_packaging_data(self):
> + pass
> +
> + @abstractmethod
> + def list_installed(self, format=None):
> + pass
> +
> + @abstractmethod
> + def insert_feeds_uris(self):
> + pass
> +
> + """
> + Install complementary packages based upon the list of currently installed
> + packages e.g. locales, *-dev, *-dbg, etc. This will only attempt to install
> + these packages, if they don't exist then no error will occur. Note: every
> + backend needs to call this function explicitly after the normal package
> + installation
> + """
> + def install_complementary(self, globs=None):
> + # we need to write the list of installed packages to a file because the
> + # oe-pkgdata-util reads it from a file
> + if self.d.has_key('WORKDIR'):
> + installed_pkgs_file = os.path.join(self.d['WORKDIR'],
> + "installed_pkgs.txt")
> + else:
> + msger.error("No WORKDIR provided!")
> +
> + with open(installed_pkgs_file, "w+") as installed_pkgs:
> + installed_pkgs.write(self.list_installed("arch"))
> +
> + if globs is None:
> + if self.d.has_key('IMAGE_INSTALL_COMPLEMENTARY'):
> + globs = self.d['IMAGE_INSTALL_COMPLEMENTARY']
> + split_linguas = set()
> +
> + if self.d.has_key('IMAGE_LINGUAS'):
> + for translation in self.d['IMAGE_LINGUAS'].split():
> + split_linguas.add(translation)
> + split_linguas.add(translation.split('-')[0])
> +
> + split_linguas = sorted(split_linguas)
> +
> + for lang in split_linguas:
> + globs += " *-locale-%s" % lang
> +
> + if globs is None:
> + return
> +
> + if not self.d.has_key('PKGDATA_DIR'):
> + msger.error("No PKGDATA_DIR provided!")
> +
> + cmd = [which(os.getenv('PATH'), "oe-pkgdata-util"),
> + "glob", self.d['PKGDATA_DIR'], installed_pkgs_file,
> + globs]
> +
> + rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot)
> + if rc != 0:
> + msger.error("Could not compute complementary packages list. Command "
> + "'%s' returned %d" %
> + (' '.join(cmd), rc))
> +
> + self.install(out.split(), attempt_only=True)
> +
> +
> + def deploy_dir_lock(self):
> + if self.deploy_dir is None:
> + raise RuntimeError("deploy_dir is not set!")
> +
> + lock_file_name = os.path.join(self.deploy_dir, "deploy.lock")
> +
> + self.deploy_lock = lockfile(lock_file_name)
> +
> + def deploy_dir_unlock(self):
> + if self.deploy_lock is None:
> + return
> +
> + unlockfile(self.deploy_lock)
> +
> + self.deploy_lock = None
> +
> +
> +class WicOpkgPM(WicPackageManager):
> + def __init__(self, d, target_rootfs, config_file, archs, pseudo, native_sysroot, task_name='target'):
> + super(WicOpkgPM, self).__init__(d, pseudo, native_sysroot)
> +
> + self.target_rootfs = target_rootfs
> + self.config_file = config_file
> + self.pkg_archs = archs
> + self.task_name = task_name
> +
> + if self.d.has_key("DEPLOY_DIR_IPK"):
> + self.deploy_dir = self.d["DEPLOY_DIR_IPK"]
> +
> + self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock")
> + self.opkg_cmd = which(os.getenv('PATH'), "opkg-cl")
> + self.opkg_args = "-f %s -o %s " % (self.config_file, target_rootfs)
> + if self.d.has_key("OPKG_ARGS"):
> + self.opkg_args += self.d["OPKG_ARGS"]
> +
> + if self.d.has_key('OPKGLIBDIR'):
> + opkg_lib_dir = self.d['OPKGLIBDIR']
> + else:
> + opkg_lib_dir = ""
> +
> + if opkg_lib_dir[0] == "/":
> + opkg_lib_dir = opkg_lib_dir[1:]
> +
> + self.opkg_dir = os.path.join(target_rootfs, opkg_lib_dir, "opkg")
> +
> + mkdirhier(self.opkg_dir)
> +
> + if self.d.has_key("TMPDIR"):
> + tmp_dir = self.d["TMPDIR"]
> + else:
> + tmp_dir = ""
> +
> + self.saved_opkg_dir = '%s/saved/%s' % (tmp_dir, self.task_name)
> + if not os.path.exists('%s/saved' % tmp_dir):
> + mkdirhier('%s/saved' % tmp_dir)
> +
> + if self.d.has_key('BUILD_IMAGES_FROM_FEEDS') and self.d['BUILD_IMAGES_FROM_FEEDS'] != "1":
> + self._create_config()
> + else:
> + self._create_custom_config()
> +
> + self.indexer = WicOpkgIndexer(self.d, self.deploy_dir)
> +
> + """
> + This function will change a package's status in /var/lib/opkg/status file.
> + If 'packages' is None then the new_status will be applied to all
> + packages
> + """
> + def mark_packages(self, status_tag, packages=None):
> + status_file = os.path.join(self.opkg_dir, "status")
> +
> + with open(status_file, "r") as sf:
> + with open(status_file + ".tmp", "w+") as tmp_sf:
> + if packages is None:
> + tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)",
> + r"Package: \1\n\2Status: \3%s" % status_tag,
> + sf.read()))
> + else:
> + if type(packages).__name__ != "list":
> + raise TypeError("'packages' should be a list object")
> +
> + status = sf.read()
> + for pkg in packages:
> + status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg,
> + r"Package: %s\n\1Status: \2%s" % (pkg, status_tag),
> + status)
> +
> + tmp_sf.write(status)
> +
> + os.rename(status_file + ".tmp", status_file)
> +
> + def _create_custom_config(self):
> + msger.info("Building from feeds activated!")
> +
> + with open(self.config_file, "w+") as config_file:
> + priority = 1
> + for arch in self.pkg_archs.split():
> + config_file.write("arch %s %d\n" % (arch, priority))
> + priority += 5
> +
> + if self.d.has_key('IPK_FEED_URIS'):
> + ipk_feed_uris = self.d['IPK_FEED_URIS']
> + else:
> + ipk_feed_uris = ""
> +
> + for line in ipk_feed_uris.split():
> + feed_match = re.match("^[ \t]*(.*)##([^ \t]*)[ \t]*$", line)
> +
> + if feed_match is not None:
> + feed_name = feed_match.group(1)
> + feed_uri = feed_match.group(2)
> +
> + msger.info("Add %s feed with URL %s" % (feed_name, feed_uri))
> +
> + config_file.write("src/gz %s %s\n" % (feed_name, feed_uri))
> +
> + """
> + Allow to use package deploy directory contents as quick devel-testing
> + feed. This creates individual feed configs for each arch subdir of those
> + specified as compatible for the current machine.
> + NOTE: Development-helper feature, NOT a full-fledged feed.
> + """
> + if self.d.has_key('FEED_DEPLOYDIR_BASE_URI'):
> + feed_deploydir_base_dir = self.d['FEED_DEPLOYDIR_BASE_URI']
> + else:
> + feed_deploydir_base_dir = ""
> +
> + if feed_deploydir_base_dir != "":
> + for arch in self.pkg_archs.split():
> + if self.d.has_key("sysconfdir"):
> + sysconfdir = self.d["sysconfdir"]
> + else:
> + sysconfdir = None
> +
> + cfg_file_name = os.path.join(self.target_rootfs,
> + sysconfdir,
> + "opkg",
> + "local-%s-feed.conf" % arch)
> +
> + with open(cfg_file_name, "w+") as cfg_file:
> + cfg_file.write("src/gz local-%s %s/%s" %
> + arch,
> + feed_deploydir_base_dir,
> + arch)
> +
> + def _create_config(self):
> + with open(self.config_file, "w+") as config_file:
> + priority = 1
> + for arch in self.pkg_archs.split():
> + config_file.write("arch %s %d\n" % (arch, priority))
> + priority += 5
> +
> + config_file.write("src oe file:%s\n" % self.deploy_dir)
> +
> + for arch in self.pkg_archs.split():
> + pkgs_dir = os.path.join(self.deploy_dir, arch)
> + if os.path.isdir(pkgs_dir):
> + config_file.write("src oe-%s file:%s\n" %
> + (arch, pkgs_dir))
> +
> + def insert_feeds_uris(self):
> + if self.feed_uris == "":
> + return
> +
> + rootfs_config = os.path.join('%s/etc/opkg/base-feeds.conf'
> + % self.target_rootfs)
> +
> + with open(rootfs_config, "w+") as config_file:
> + uri_iterator = 0
> + for uri in self.feed_uris.split():
> + config_file.write("src/gz url-%d %s/ipk\n" %
> + (uri_iterator, uri))
> +
> + for arch in self.pkg_archs.split():
> + if not os.path.exists(os.path.join(self.deploy_dir, arch)):
> + continue
> + msger.info('Note: adding opkg channel url-%s-%d (%s)' %
> + (arch, uri_iterator, uri))
> +
> + config_file.write("src/gz uri-%s-%d %s/ipk/%s\n" %
> + (arch, uri_iterator, uri, arch))
> + uri_iterator += 1
> +
> + def update(self):
> + self.deploy_dir_lock()
> +
> + cmd = "%s %s update" % (self.opkg_cmd, self.opkg_args)
> +
> + rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot)
> + if rc != 0:
> + self.deploy_dir_unlock()
> + msger.error("Unable to update the package index files. Command '%s' "
> + "returned %d" % (cmd, rc))
> +
> + self.deploy_dir_unlock()
> +
> + def install(self, pkgs, attempt_only=False):
> + if attempt_only and len(pkgs) == 0:
> + return
> +
> + cmd = "%s %s install %s" % (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
> +
> + os.environ['D'] = self.target_rootfs
> + os.environ['OFFLINE_ROOT'] = self.target_rootfs
> + os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs
> + os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs
> + if self.d.has_key('WORKDIR'):
> + os.environ['INTERCEPT_DIR'] = os.path.join(self.d['WORKDIR'],
> + "intercept_scripts")
> + else:
> + os.environ['INTERCEPT_DIR'] = "."
> + msger.warning("No WORKDIR provided!")
> +
> + if self.d.has_key('STAGING_DIR_NATIVE'):
> + os.environ['NATIVE_ROOT'] = self.d['STAGING_DIR_NATIVE']
> + else:
> + msger.error("No STAGING_DIR_NATIVE provided!")
> +
> + rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot)
> + if rc != 0:
> + msger.error("Unable to install packages. "
> + "Command '%s' returned %d" % (cmd, rc))
> +
> +
> + def remove(self, pkgs, with_dependencies=True):
> + if with_dependencies:
> + cmd = "%s %s --force-depends --force-remove --force-removal-of-dependent-packages remove %s" % \
> + (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
> + else:
> + cmd = "%s %s --force-depends remove %s" % \
> + (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
> +
> + rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot)
> + if rc != 0:
> + msger.error("Unable to remove packages. Command '%s' "
> + "returned %d" % (cmd, rc))
> +
> +
> + def write_index(self):
> + self.deploy_dir_lock()
> +
> + result = self.indexer.write_index()
> +
> + self.deploy_dir_unlock()
> +
> + if result is not None:
> + msger.error(result)
> +
> + def remove_packaging_data(self):
> + remove(self.opkg_dir, True)
> + # create the directory back, it's needed by PM lock
> + mkdirhier(self.opkg_dir)
> +
> + def list_installed(self, format=None):
> + return WicOpkgPkgsList(self.d, self.target_rootfs, self.config_file).list(format)
> +
> + def handle_bad_recommendations(self):
> + if self.d.has_key("BAD_RECOMMENDATIONS"):
> + bad_recommendations = self.d["BAD_RECOMMENDATIONS"]
> + else:
> + bad_recommendations = ""
> +
> + if bad_recommendations.strip() == "":
> + return
> +
> + status_file = os.path.join(self.opkg_dir, "status")
> +
> + # If status file existed, it means the bad recommendations has already
> + # been handled
> + if os.path.exists(status_file):
> + return
> +
> + cmd = "%s %s info " % (self.opkg_cmd, self.opkg_args)
> +
> + with open(status_file, "w+") as status:
> + for pkg in bad_recommendations.split():
> + pkg_info = cmd + pkg
> +
> + try:
> + output = subprocess.check_output(pkg_info.split(), stderr=subprocess.STDOUT).strip()
> + except subprocess.CalledProcessError as e:
> + msger.error("Cannot get package info. Command '%s' "
> + "returned %d:\n%s" % (pkg_info, e.returncode, e.output))
> +
> + if output == "":
> + msger.info("Ignored bad recommendation: '%s' is "
> + "not a package" % pkg)
> + continue
> +
> + for line in output.split('\n'):
> + if line.startswith("Status:"):
> + status.write("Status: deinstall hold not-installed\n")
> + else:
> + status.write(line + "\n")
> +
> + '''
> + The following function dummy installs pkgs and returns the log of output.
> + '''
> + def dummy_install(self, pkgs):
> + if len(pkgs) == 0:
> + return
> +
> + # Create an temp dir as opkg root for dummy installation
> + if self.d.has_key("TMPDIR"):
> + tmp_dir = self.d["TMPDIR"]
> + else:
> + tmp_dir = "."
> + msger.warning("No TMPDIR provided!")
> +
> + temp_rootfs = '%s/opkg' % tmp_dir
> + temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg')
> + mkdirhier(temp_opkg_dir)
> +
> + opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
> + if self.d.has_key("OPKG_ARGS"):
> + opkg_args += self.d["OPKG_ARGS"]
> +
> + cmd = "%s %s update" % (self.opkg_cmd, opkg_args)
> + try:
> + subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
> + except subprocess.CalledProcessError as e:
> + msger.error("Unable to update. Command '%s' "
> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
> +
> + # Dummy installation
> + cmd = "%s %s --noaction install %s " % (self.opkg_cmd,
> + opkg_args,
> + ' '.join(pkgs))
> + try:
> + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
> + except subprocess.CalledProcessError as e:
> + msger.error("Unable to dummy install packages. Command '%s' "
> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
> +
> + remove(temp_rootfs, True)
> +
> + return output
> +
> + def backup_packaging_data(self):
> + # Save the opkglib for increment ipk image generation
> + if os.path.exists(self.saved_opkg_dir):
> + remove(self.saved_opkg_dir, True)
> + shutil.copytree(self.opkg_dir,
> + self.saved_opkg_dir,
> + symlinks=True)
> +
> + def recover_packaging_data(self):
> + # Move the opkglib back
> + if os.path.exists(self.saved_opkg_dir):
> + if os.path.exists(self.opkg_dir):
> + remove(self.opkg_dir, True)
> +
> + msger.info('Recover packaging data')
> + shutil.copytree(self.saved_opkg_dir,
> + self.opkg_dir,
> + symlinks=True)
> +
> +
> +def wic_generate_index_files(d):
> + if d.has_key('PACKAGE_CLASSES'):
> + classes = d['PACKAGE_CLASSES'].replace("package_", "").split()
> + else:
> + classes = ""
> + msger.warning("No PACKAGE_CLASSES provided!")
> +
> + if d.has_key('DEPLOY_DIR_IPK'):
> + deploy_dir_ipk = d['DEPLOY_DIR_IPK']
> + else:
> + deploy_dir_ipk = None
> + msger.warning("No DEPLOY_DIR_IPK provided!")
> +
> + indexer_map = {
> + "ipk": (WicOpkgIndexer, deploy_dir_ipk)
> + }
> +
> + result = None
> +
> + for pkg_class in classes:
> + if not pkg_class in indexer_map:
> + continue
> +
> + if os.path.exists(indexer_map[pkg_class][1]):
> + result = indexer_map[pkg_class][0](d, indexer_map[pkg_class][1]).write_index()
> +
> + if result is not None:
> + msger.error(result)
> diff --git a/scripts/wic b/scripts/wic
> index 2d3fd09..b9c8756 100755
> --- a/scripts/wic
> +++ b/scripts/wic
> @@ -99,6 +99,10 @@ def wic_create_subcommand(args, usage_str):
>
> (options, args) = parser.parse_args(args)
>
> + if options.debug:
> + loglevel = logging.DEBUG
> + start_logging(loglevel)
> +
> if len(args) != 1:
> logging.error("Wrong number of arguments, exiting\n")
> parser.print_help()
> @@ -107,9 +111,11 @@ def wic_create_subcommand(args, usage_str):
> if not options.image_name and not (options.rootfs_dir and
> options.bootimg_dir and
> options.kernel_dir and
> + options.native_sysroot or
> options.native_sysroot):
> print "Build artifacts not completely specified, exiting."
> - print " (Use 'wic -e' or 'wic -r -b -k -n' to specify artifacts)"
> + print " (Use 'wic -e' or 'wic -r -b -k -n' or 'wic -r -n' to specify artifacts)"
> + print options
> sys.exit(1)
>
> if not options.image_name:
> @@ -125,13 +131,16 @@ def wic_create_subcommand(args, usage_str):
>
> print "Creating image(s)...\n"
>
> - bitbake_env_lines = find_bitbake_env_lines(options.image_name)
> - if not bitbake_env_lines:
> - print "Couldn't get bitbake environment, exiting."
> - sys.exit(1)
> - set_bitbake_env_lines(bitbake_env_lines)
> + # If '-e' option is used the values are extracted from bitbake env.
> + if options.image_name:
> + bitbake_env_lines = find_bitbake_env_lines(options.image_name)
> + if not bitbake_env_lines:
> + print "Couldn't get bitbake environment, exiting."
> + sys.exit(1)
> + set_bitbake_env_lines(bitbake_env_lines)
>
> bootimg_dir = staging_data_dir = hdddir = ""
> + rootfs_dir = native_sysroot = kernel_dir = image_output_dir = ""
>
> if options.image_name:
> (rootfs_dir, kernel_dir, hdddir, staging_data_dir, native_sysroot) = \
> @@ -140,34 +149,65 @@ def wic_create_subcommand(args, usage_str):
> wks_file = args[0]
>
> if not wks_file.endswith(".wks"):
> + # Return full path of the .wks file
> wks_file = find_canned_image(scripts_path, wks_file)
> if not wks_file:
> - print "No image named %s found, exiting. (Use 'wic list images' to list available images, or specify a fully-qualified OE kickstart (.wks) filename)\n" % wks_file
> + print "No image named %s found, exiting.\n" % wks_file
> + print "(Use 'wic list images' to list available images, or specify a fully-qualified OE kickstart (.wks) filename)\n"
> sys.exit(1)
>
> - image_output_dir = ""
> if options.outdir:
> image_output_dir = options.outdir
>
> - if not options.image_name:
> - rootfs_dir = ''
> - if 'ROOTFS_DIR' in options.rootfs_dir:
> - rootfs_dir = options.rootfs_dir['ROOTFS_DIR']
> - bootimg_dir = options.bootimg_dir
> - kernel_dir = options.kernel_dir
> + if options.native_sysroot:
> native_sysroot = options.native_sysroot
> - if rootfs_dir and not os.path.isdir(rootfs_dir):
> - print "--roofs-dir (-r) not found, exiting\n"
> - sys.exit(1)
> - if not os.path.isdir(bootimg_dir):
> - print "--bootimg-dir (-b) not found, exiting\n"
> - sys.exit(1)
> - if not os.path.isdir(kernel_dir):
> - print "--kernel-dir (-k) not found, exiting\n"
> - sys.exit(1)
> + print "Using native_sysroot from user command: %s" % native_sysroot
> +
> if not os.path.isdir(native_sysroot):
> - print "--native-sysroot (-n) not found, exiting\n"
> + print "--native-sysroot (-n) not found, exiting"
> sys.exit(1)
> +
> + native_sysroot = os.path.abspath(native_sysroot)
> +
> + if not options.image_name:
> + if (options.bootimg_dir and options.kernel_dir and
> + options.rootfs_dir and options.native_sysroot):
> + rootfs_dir = ''
> + if 'ROOTFS_DIR' in options.rootfs_dir:
> + rootfs_dir = options.rootfs_dir['ROOTFS_DIR']
> + bootimg_dir = options.bootimg_dir
> + kernel_dir = options.kernel_dir
> + native_sysroot = options.native_sysroot
> +
> + if rootfs_dir and not os.path.isdir(rootfs_dir):
> + print "--roofs-dir (-r) not found, exiting\n"
> + sys.exit(1)
> + if not os.path.isdir(bootimg_dir):
> + print "--bootimg-dir (-b) not found, exiting\n"
> + sys.exit(1)
> + if not os.path.isdir(kernel_dir):
> + print "--kernel-dir (-k) not found, exiting\n"
> + sys.exit(1)
> + if not os.path.isdir(native_sysroot):
> + print "--native-sysroot (-n) not found, exiting\n"
> + sys.exit(1)
> + else:
> + print 'Build image from rootfs and a package list using native rootfs\n'
> + if options.rootfs_dir and 'ROOTFS_DIR' in options.rootfs_dir:
> + rootfs_dir = options.rootfs_dir['ROOTFS_DIR']
> + elif options.rootfs_dir:
> + rootfs_dir = options.rootfs_dir
> + else:
> + rootfs_dir = ""
> +
> + native_sysroot = options.native_sysroot
> +
> + if rootfs_dir and not os.path.isdir(rootfs_dir):
> + print "--roofs-dir (-r) not found, exiting\n"
> + sys.exit(1)
> + if not os.path.isdir(native_sysroot):
> + print "--native-sysroot (-n) not found, exiting\n"
> + sys.exit(1)
> else:
> not_found = not_found_dir = ""
> if not os.path.isdir(rootfs_dir):
>
More information about the Openembedded-core
mailing list