Lua
has a fairly small source code and few dependencies, then it's a good choice to make a first demo.
Archlinux Example
First, create a directory for our example, let's say /tmp/lua-archlinux
. And put the following content in the /tmp/lua-archlinux/PKGBUILD
file:
pkgname=lua-example
pkgver=5.3.6
pkgrel=1
pkgdesc='Lua is a powerful, efficient, lightweight, embeddable scripting language'
arch=('x86_64')
url='https://www.lua.org'
depends=('readline')
license=('MIT')
source=("https://www.lua.org/ftp/lua-${pkgver}.tar.gz")
md5sums=('83f23dbd5230140a3770d5f54076948d')
prepare() {
cd "$srcdir"
echo "Nothing to do..."
}
build() {
cd "$srcdir/lua-$pkgver"
make linux
}
package() {
cd "$srcdir/lua-$pkgver"
make INSTALL_TOP="$pkgdir/usr" install
}
## You can use this command to download the file:
# wget 'https://duriez.info/d/OoQoAS66' -O PKGBUILD
Then start the image we made earlier and mount the current directory inside the container to keep the result after the container will stop.
After this, you should find a lua-example-5.3.6-1-x86_64.pkg.tar.zst
file in the /tmp/lua-archlinux
directory which is the expected package.
Debian Example
Now our goal will be to do something narrowing this behavior. I propose this:
#!/bin/bash
set -e
MAINTAINER="Franck Duriez <franck@duriez.info>"
VERSION="5.3.6"
NAME="lua-example"
ARCHITECTURE="amd64"
DESCRIPTION="Lua is a powerful, efficient, lightweight, embeddable scripting language"
DEPENDENCIES=("libc6" "libedit2" "libreadline7")
BUILD_DEPENDENCIES=("libedit-dev" "libreadline-dev")
SOURCE="https://www.lua.org/ftp/lua-${VERSION}.tar.gz"
MD5SUM='83f23dbd5230140a3770d5f54076948d'
build() {
cd "$SOURCE_DIR/lua-$VERSION"
make linux
}
package() {
cd "$SOURCE_DIR/lua-$VERSION"
make INSTALL_TOP="$PACKAGE_DIR/usr" install
}
###############
###############
echo "Building version $VERSION"
CURRENT_DIRECTORY="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
cd "${CURRENT_DIRECTORY}"
echo "## Extract sources"
SOURCE_DIR="$PWD/tmp"
rm -fr "$SOURCE_DIR"
mkdir -p "$SOURCE_DIR"
cd "$SOURCE_DIR"
wget -O "archive.tar.gz" "$SOURCE"
echo "${MD5SUM} archive.tar.gz" > "archive.md5"
md5sum -c "archive.md5" # Check integrity
tar xzf "archive.tar.gz"
cd -
PACKAGE_DIR="${CURRENT_DIRECTORY}/pkg"
rm -fr "$PACKAGE_DIR"
mkdir -p "$PACKAGE_DIR"
apt update
apt install -y "${DEPENDENCIES[@]}" "${BUILD_DEPENDENCIES[@]}"
echo "## Build from sources"
build
echo "## Package built files"
package
mkdir -p "$PACKAGE_DIR/DEBIAN"
echo "Package: $NAME
Version: $VERSION
Architecture: $ARCHITECTURE
Depends: $({ IFS=","; echo "${DEPENDENCIES[*]}"; })
Maintainer: $MAINTAINER
Description: ${DESCRIPTION}" \
> "$PACKAGE_DIR/DEBIAN/control"
rm -fr "${CURRENT_DIRECTORY}/pkg.deb"
dpkg-deb --build "$PACKAGE_DIR"
mv "${CURRENT_DIRECTORY}/pkg.deb" "${CURRENT_DIRECTORY}/${NAME}_${VERSION}_${ARCHITECTURE}.deb"
rm -fr "$PACKAGE_DIR"
## You can use this command to download the file:
# wget 'https://duriez.info/d/kmQoHvN9' -O build.sh
As you can see, before the separator, the file is mostly equivalent to the archlinux one.
Now, let's run it in the debian container.
After this, you should find a lua-example_5.3.6_amd64.deb
file in the /tmp/lua-debian
directory which is the expected package.
Differences
There are few subtle differences between the two build.
Maybe you didn't notice but the two docker commands are slightly different:
# Here is the archlinux one:
docker run -v"$PWD:/repo" -u"$(id -u):$(id -g)" -it archlinux-package-demo
# Here is the debian one:
docker run -v"$PWD:/repo" -it debian-package-demo
As you can see the -u"$(id -u):$(id -g)"
part is absent for debian. It means than the user in the docker is root, unlike in the other which use a user with the same UID
(user id) and GID
(group id). This means each time a file is created in the debian environment, it's owned by root (and then requires root access to delete), and each time you create a file in the archlinux environment it's owned by you.
Archlinux packaging is performed inside a chroot
environment, removing the need to be root and avoiding to alter the host system.
As long as you stay in docker, not using a chroot is not a problem because docker itself is a chroot++. Therefore, this method is especially suitable in docker based continuous integration context.
Another difference is that archlinux packaging, add some post process to the built executables. For example, it strips all the binaries, removes garbage files... This can be seen after Tidying install
.
About deb
files
deb
files are ar
archives that contain the following content:
-
control.tar.xz
contains the content of the control
directory we made in the script data.tar.xz
contains the files it will add to your file system debian-binary
contains the version of the package format
To extract these file from a deb
file, you can use the following command:
ar x <path/to/file.deb>
In the control.tar.xz
, you can find a bunch of things, but the only mandatory is the control
file we made in the example:
control
the package metadata preinst
the package pre installation script postinst
the package post installation script prerm
the package pre uninstallation script postrm
the package post uninstallation script -
...
and other less useful scripts. You can find a complete list of available scripts here.