From: Alexander Smirnov <asmirnov@ilbers.de>
To: isar-users@googlegroups.com
Cc: Frank Lenormand <lenormf@gmail.com>,
Alexander Smirnov <asmirnov@ilbers.de>
Subject: [PATCH 1/6] meta-isar-bin: Enable caching of deb packages
Date: Sun, 27 Aug 2017 18:13:34 +0300 [thread overview]
Message-ID: <20170827151339.12806-2-asmirnov@ilbers.de> (raw)
In-Reply-To: <20170827151339.12806-1-asmirnov@ilbers.de>
From: Frank Lenormand <lenormf@gmail.com>
Adds the possibility to create an apt repository for newly built packages
and then use that repo for populating the target filesystem.
Signed-off-by: Frank Lenormand <lenormf@gmail.com>
Signed-off-by: Alexander Smirnov <asmirnov@ilbers.de>
---
meta-isar-bin/conf/layer.conf | 18 +++
meta-isar-bin/files/distributions.in | 3 +
meta-isar/conf/bblayers.conf.sample | 1 +
.../images/files/debian-configscript.sh | 8 ++
.../images/files/raspbian-configscript.sh | 8 ++
meta-isar/recipes-core/images/isar-image-base.bb | 8 +-
meta/classes/dpkg.bbclass | 126 +++++++++++++++++++--
meta/classes/image.bbclass | 30 +++--
8 files changed, 186 insertions(+), 16 deletions(-)
create mode 100644 meta-isar-bin/conf/layer.conf
create mode 100644 meta-isar-bin/files/distributions.in
diff --git a/meta-isar-bin/conf/layer.conf b/meta-isar-bin/conf/layer.conf
new file mode 100644
index 0000000..24534e1
--- /dev/null
+++ b/meta-isar-bin/conf/layer.conf
@@ -0,0 +1,18 @@
+# Enable package caching with '1'
+DEBCACHE_ENABLED ?= "0"
+
+# Codename of the repository created by the caching class
+DEBDISTRONAME = "isar"
+
+# Path to the caching repository
+DEBCACHEDIR ?= "${LAYERDIR}/apt"
+
+# Path to the mount point of the repository within the target rootfs, during
+# population
+DEBCACHEMNT ?= "/opt/cache/apt"
+
+# Path to the databases used by `reprepro`
+DEBDBDIR ?= "${LAYERDIR}/db"
+
+# Path to the configuration files templates used by `reprepro`
+DEBFILESDIR ?= "${LAYERDIR}/files"
diff --git a/meta-isar-bin/files/distributions.in b/meta-isar-bin/files/distributions.in
new file mode 100644
index 0000000..59f4429
--- /dev/null
+++ b/meta-isar-bin/files/distributions.in
@@ -0,0 +1,3 @@
+Codename: {DISTRO_NAME}
+Architectures: i386 armhf source
+Components: main
diff --git a/meta-isar/conf/bblayers.conf.sample b/meta-isar/conf/bblayers.conf.sample
index 80867e7..53a362b 100644
--- a/meta-isar/conf/bblayers.conf.sample
+++ b/meta-isar/conf/bblayers.conf.sample
@@ -8,6 +8,7 @@ BBFILES ?= ""
BBLAYERS ?= " \
##ISARROOT##/meta \
##ISARROOT##/meta-isar \
+ ##ISARROOT##/meta-isar-bin \
"
BBLAYERS_NON_REMOVABLE ?= " \
##ISARROOT##/meta \
diff --git a/meta-isar/recipes-core/images/files/debian-configscript.sh b/meta-isar/recipes-core/images/files/debian-configscript.sh
index 4ac37d0..b05babb 100644
--- a/meta-isar/recipes-core/images/files/debian-configscript.sh
+++ b/meta-isar/recipes-core/images/files/debian-configscript.sh
@@ -8,6 +8,8 @@ set -e
readonly MACHINE_SERIAL="$1"
readonly BAUDRATE_TTY="$2"
readonly ROOTFS_DEV="$3"
+readonly DEBCACHEMNT="$4"
+readonly DEBDISTRONAME="$5"
cat >> /etc/default/locale << EOF
LANG=en_US.UTF-8
@@ -83,3 +85,9 @@ fi
if [ -x "$TARGET/sbin/init" -a -x "$TARGET/usr/sbin/policy-rc.d" ]; then
rm -f $TARGET/usr/sbin/policy-rc.d
fi
+
+mkdir -p /etc/apt/sources.list.d/
+cat <<EOF >/etc/apt/sources.list.d/${DEBDISTRONAME}.list
+deb file:${DEBCACHEMNT}/ ${DEBDISTRONAME} main
+deb-src file:${DEBCACHEMNT}/ ${DEBDISTRONAME} main
+EOF
diff --git a/meta-isar/recipes-core/images/files/raspbian-configscript.sh b/meta-isar/recipes-core/images/files/raspbian-configscript.sh
index 2454481..f995f4d 100644
--- a/meta-isar/recipes-core/images/files/raspbian-configscript.sh
+++ b/meta-isar/recipes-core/images/files/raspbian-configscript.sh
@@ -8,6 +8,8 @@ set -e
readonly MACHINE_SERIAL="$1"
readonly BAUDRATE_TTY="$2"
readonly ROOTFS_DEV="$3"
+readonly DEBCACHEMNT="$4"
+readonly DEBDISTRONAME="$5"
cat >> /etc/default/locale << EOF
LANG=en_US.UTF-8
@@ -89,3 +91,9 @@ KERNEL_IMAGE=`ls /boot | grep vmlinuz`
cat > /boot/config.txt << EOF
kernel=$KERNEL_IMAGE
EOF
+
+mkdir -p /etc/apt/sources.list.d/
+cat <<EOF >/etc/apt/sources.list.d/${DEBDISTRONAME}.list
+deb file:${DEBCACHEMNT}/ ${DEBDISTRONAME} main
+deb-src file:${DEBCACHEMNT}/ ${DEBDISTRONAME} main
+EOF
diff --git a/meta-isar/recipes-core/images/isar-image-base.bb b/meta-isar/recipes-core/images/isar-image-base.bb
index b679d97..85e6b27 100644
--- a/meta-isar/recipes-core/images/isar-image-base.bb
+++ b/meta-isar/recipes-core/images/isar-image-base.bb
@@ -49,8 +49,12 @@ do_rootfs() {
sudo multistrap -a ${DISTRO_ARCH} -d "${S}" -f "${WORKDIR}/multistrap.conf" || true
# Configure root filesystem
- sudo chroot ${S} /configscript.sh ${MACHINE_SERIAL} ${BAUDRATE_TTY} \
- ${ROOTFS_DEV}
+ sudo chroot ${S} /configscript.sh \
+ ${MACHINE_SERIAL} \
+ ${BAUDRATE_TTY} \
+ ${ROOTFS_DEV} \
+ ${DEBCACHEMNT} \
+ ${DEBDISTRONAME}
sudo rm ${S}/configscript.sh
}
diff --git a/meta/classes/dpkg.bbclass b/meta/classes/dpkg.bbclass
index 360a95c..b1e201d 100644
--- a/meta/classes/dpkg.bbclass
+++ b/meta/classes/dpkg.bbclass
@@ -1,5 +1,5 @@
# This software is a part of ISAR.
-# Copyright (C) 2015-2016 ilbers GmbH
+# Copyright (C) 2015-2017 ilbers GmbH
# Add dependency from buildchroot creation
DEPENDS += "buildchroot"
@@ -55,12 +55,124 @@ do_build() {
sudo chroot ${BUILDCHROOT_DIR} /build.sh ${PP}/${SRC_DIR}
}
-
# Install package to dedicated deploy directory
-do_install() {
- install -m 644 ${BUILDROOT}/*.deb ${DEPLOY_DIR_DEB}/
+do_binary_deb_install() {
+ readonly DIR_CACHE="${DEBCACHEDIR}/${DISTRO}"
+ readonly DIR_DB="${DEBDBDIR}/${DISTRO}"
+
+ if [ "${DEBCACHE_ENABLED}" != "0" ]; then
+ # If `bitbake` is running for the first time, the cache doesn't exist
+ # yet and needs to be configured using a `distributions` file.
+ # A template stored in the layer directory is pre-processed to
+ # generate the configuration file, which is then placed in the
+ # appropriate directory.
+ if [ ! -e "${DIR_CACHE}/conf/distributions" ]; then
+ mkdir -p "${DIR_CACHE}/conf"
+ sed -e "s#{DISTRO_NAME}#${DEBDISTRONAME}#g" \
+ "${DEBFILESDIR}/distributions.in" \
+ > "${DIR_CACHE}/conf/distributions"
+ fi
+
+ # Add binary and source packages to the deb cache
+ # If the cache doesn't exist yet, it will be created using the
+ # `distributions` file generated above.
+ ls -1 "${BUILDROOT}"/*.deb "${BUILDROOT}"/*.dsc | while read -r p; do
+ reprepro --waitforlock 3 -b "${DIR_CACHE}" --dbdir "${DIR_DB}" \
+ -C main "include${p##*.}" "${DEBDISTRONAME}" "${p}"
+ done
+ else
+ # Deb caching is disabled, simply copy all binary packages to the
+ # deploy directory
+ mkdir -p "${DEPLOY_DIR_DEB}"
+ install -m 644 "${BUILDROOT}"/*.deb "${DEPLOY_DIR_DEB}/"
+ fi
}
-addtask install after do_build
-do_install[dirs] = "${DEPLOY_DIR_DEB}"
-do_install[stamp-extra-info] = "${MACHINE}"
+addtask binary_deb_install after do_build
+do_binary_deb_install[stamp-extra-info] = "${DISTRO}-${DISTRO_ARCH}"
+
+# Deb caching lambda run during the parsing phase that checks whether the
+# current package has to be rebuilt, or taken from the cache
+python __anonymous () {
+ if d.getVar("DEBCACHE_ENABLED", True) == "0":
+ # Deb caching is disabled, do nothing
+ return True
+
+ PN = d.getVar("PN", True)
+ PV = d.getVar("PV", True)
+ DISTRO_ARCH = d.getVar("DISTRO_ARCH", True)
+ DEBCACHEDIR = d.getVar("DEBCACHEDIR", True)
+ DEBDISTRONAME = d.getVar("DEBDISTRONAME", True)
+ DEBDBDIR = d.getVar("DEBDBDIR", True)
+ DISTRO = d.getVar("DISTRO", True)
+ path_cache = os.path.join(DEBCACHEDIR, DISTRO)
+ path_databases = os.path.join(DEBDBDIR, DISTRO)
+ path_distributions = os.path.join(path_cache, "conf", "distributions")
+
+ # The distributions file is needed by `reprepro` to know what types
+ # of packages are supported, what the distribution name is, etc.
+ # If it doesn't exist, we have nothing in the cache, do nothing.
+ if not os.path.exists(path_distributions):
+ return
+
+ # Anonymous functions are run several times under different contexts
+ # during the parsing phase, which would let the code that follows be run
+ # as many times for the same package.
+ # In order to guarantee that our subroutine only runs once per package, we
+ # use bitbake's "persist" API in order to have reliable persistent storage
+ # accross calls of the lambda (using a simple variable in the class won't
+ # work, as several contexts won't allow fetching its value).
+ pd = bb.persist_data.persist("DEBCACHE_PACKAGES", d)
+ if PN in pd and pd[PN] == PV:
+ return
+
+ import subprocess
+ try:
+ # The databases used by `reprepro` are not stored within the cache in
+ # order to make versioning of only the files needed to use the cache
+ # as an official Debian repository simpler.
+ # As such, if a developer uses a peer's cache to speed up their build
+ # time but have never run bitbake, the database will not have been
+ # created, so we regenerate them here.
+ if not os.path.exists(path_databases) and os.path.exists(path_cache):
+ bb.note("Regenerating the cache databases...")
+ subprocess.check_call([
+ "reprepro",
+ "--waitforlock", "3",
+ "-b", path_cache,
+ "--dbdir", path_databases,
+ "export", DEBDISTRONAME,
+ ])
+
+ # Get a list of the versions of all the packages named after the
+ # current bitbake package, and check whether the current package
+ # version is returned.
+ # As `reprepro` always returns zero with this particular operation, we
+ # have to use this workaround to check for a package in the cache.
+ package_version = subprocess.check_output([
+ "reprepro",
+ "--waitforlock", "3",
+ "-b", path_cache,
+ "--dbdir", path_databases,
+ "-C", "main",
+ "-A", DISTRO_ARCH,
+ "--list-format", "${version}",
+ "list", DEBDISTRONAME, PN,
+ ])
+ package_version = package_version.decode("utf-8")
+ if package_version == PV:
+ # The below list contains the names of all the tasks are in charge
+ # of building the package when the cache isn't enabled or if the
+ # package hasn't been placed in it already.
+ # As all tasks are enabled by default, we prevent their execution
+ # by setting the `noexec` flag, which will prevent a rebuild of
+ # the package when it's cached.
+ for task in ["fetch", "unpack", "build", "install"]:
+ d.setVarFlag("do_{}".format(task), "noexec", "1")
+
+ # Cache the results of this command so that subsequent executions
+ # of this anonymous functions don't run the same code again.
+ pd[PN] = PV
+ except subprocess.CalledProcessError as e:
+ bb.fatal("Unable to check for a candidate for package {0} (errorcode: {1})".format(PN, e.returncode))
+}
diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index a7f0d74..f42aa48 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass
@@ -11,18 +11,34 @@ inherit ${IMAGE_TYPE}
do_populate[stamp-extra-info] = "${MACHINE}-${DISTRO}"
-# Install Debian packages, that were built from sources
+# Install Debian packages from the cache
do_populate() {
+ readonly DIR_CACHE="${DEBCACHEDIR}/${DISTRO}"
+
if [ -n "${IMAGE_INSTALL}" ]; then
- sudo mkdir -p ${S}/deb
+ if [ "${DEBCACHE_ENABLED}" != "0" ]; then
+ sudo mkdir -p "${S}/${DEBCACHEMNT}"
+ sudo mount -o bind "${DIR_CACHE}" "${S}/${DEBCACHEMNT}"
+
+ sudo chroot "${S}" apt-get update -y
+ for package in ${IMAGE_INSTALL}; do
+ sudo chroot "${S}" apt-get install -t "${DEBDISTRONAME}" -y \
+ --allow-unauthenticated "${package}"
+ done
+
+ sudo umount "${S}/${DEBCACHEMNT}"
+ else
+ sudo mkdir -p ${S}/deb
- for p in ${IMAGE_INSTALL}; do
- sudo cp ${DEPLOY_DIR_DEB}/${p}_*.deb ${S}/deb
- done
+ for p in ${IMAGE_INSTALL}; do
+ find "${DEPLOY_DIR_DEB}" -type f -name '*.deb' -exec \
+ sudo cp '{}' "${S}/deb/" \;
+ done
- sudo chroot ${S} /usr/bin/dpkg -i -R /deb
+ sudo chroot ${S} /usr/bin/dpkg -i -R /deb
- sudo rm -rf ${S}/deb
+ sudo rm -rf ${S}/deb
+ fi
fi
}
--
2.1.4
next prev parent reply other threads:[~2017-08-27 15:14 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-27 15:13 [PATCH 0/6] Isar apt cache implementation Alexander Smirnov
2017-08-27 15:13 ` Alexander Smirnov [this message]
2017-08-28 15:18 ` [PATCH 1/6] meta-isar-bin: Enable caching of deb packages Henning Schild
2017-08-29 6:40 ` Alexander Smirnov
2017-08-29 7:51 ` Henning Schild
2017-08-29 8:20 ` Alexander Smirnov
2017-08-31 10:55 ` Claudius Heine
2017-08-31 11:20 ` Henning Schild
2017-08-31 12:08 ` Claudius Heine
2017-09-06 14:21 ` Henning Schild
2017-09-07 11:13 ` Claudius Heine
2017-08-27 15:13 ` [PATCH 2/6] classes/image: Provide /dev/null for Stretch apt Alexander Smirnov
2017-08-28 15:20 ` Henning Schild
2017-08-28 15:26 ` Henning Schild
2017-08-27 15:13 ` [PATCH 3/6] classes/dpkg: Split install for cache Alexander Smirnov
2017-08-28 8:00 ` Claudius Heine
2017-08-29 7:18 ` Alexander Smirnov
2017-08-30 8:54 ` Claudius Heine
2017-08-28 15:30 ` Henning Schild
2017-08-27 15:13 ` [PATCH 4/6] meta-isar-bin: Enable apt repo generation for amd64 Alexander Smirnov
2017-08-27 15:13 ` [PATCH 5/6] classes/dpkg: Properly update packages in the cache Alexander Smirnov
2017-08-28 15:32 ` Henning Schild
2017-08-29 7:20 ` Alexander Smirnov
2017-08-29 7:57 ` Henning Schild
2017-08-29 11:26 ` Jan Kiszka
2017-08-27 15:13 ` [PATCH 6/6] doc/technical_overview: Describe binary cache Alexander Smirnov
2017-08-28 15:36 ` Henning Schild
2017-08-29 7:29 ` Alexander Smirnov
2017-08-29 8:06 ` Henning Schild
2017-08-29 11:29 ` Jan Kiszka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170827151339.12806-2-asmirnov@ilbers.de \
--to=asmirnov@ilbers.de \
--cc=isar-users@googlegroups.com \
--cc=lenormf@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox