: ${TRACING=false}
: ${WITH=}
: ${WITHOUT=}
-: ${KEEP_CONTAINER=false}
+: ${KEEP_CONTAINER=true}
: ${TMPFS="4G"}
+: ${EXEC=false}
dir=$(pwd)
image=registry.gitlab.com/pld-linux/cleanbuild
topdir=$dir/rpm
home=/home/builder
+notice() {
+ echo >&2 "[cleanbuild:notice]: $*"
+}
+
die() {
- echo >&2 "$0: $*"
- exit 1
+ local rc=${2:-1}
+ echo >&2 "[cleanbuild:error]: $1"
+ exit $rc
}
is_no() {
esac
}
+is_bool() {
+ [ "$1" = "true" -o "$1" = "false" ] || die "Invalid boolean value: $1"
+}
+
tmpfs() {
if is_no "${TMPFS:-true}" || [ "$TMPFS" = "0" ]; then
return
echo "--tmpfs $home/rpm/BUILD:rw,exec,nosuid,size=$TMPFS"
}
+have_container() {
+ local name="$1" id
+
+ id=$(docker ps -a -f "label=cleanbuild=$name" --format '{{.ID}}')
+
+ test -n "$id"
+}
+
create_container() {
- # cleanup first
- docker kill $name >/dev/null 2>&1 || :
- docker rm $name >/dev/null 2>&1 || :
+ if ! $KEEP_CONTAINER; then
+ notice "Clean up old container: $name"
+ docker kill $name >/dev/null 2>&1 || :
+ docker rm $name >/dev/null 2>&1 || :
+ fi
install -d $topdir/logs
# start the container
- docker run --name=$name -d \
- -w $home \
- -v $topdir:$home/rpm \
- -v $dir:$home/cleanbuild \
- -v $dir/cache/poldek:/var/cache/poldek \
- -v $dir/cache/ccache/$PACKAGE_NAME:$home/.ccache \
- --label=cleanbuild=$name \
- $(tmpfs) \
- $image >/dev/null
-
- # set the homedir
+ if ! have_container "$PACKAGE_NAME"; then
+ TMPFS_SIZE=$TMPFS \
+ PACKAGE_NAME=$PACKAGE_NAME \
+ docker-compose run --rm -d \
+ --name=$name \
+ --workdir=$home/rpm/packages/$PACKAGE_NAME \
+ --label=cleanbuild=$PACKAGE_NAME \
+ cleanbuild
+ fi
+
+ UID=$(id -u)
+ GID=$(id -g)
+ notice "Setup builder user ($UID:$GID)"
+
docker exec --user=root -w / $name usermod -d $home builder
- # these paths need to be accessible for builder
- docker exec --user=root -w / $name sh -c "cd $home && chown builder:builder rpm rpm/logs rpm/BUILD .ccache"
+ if [ "$UID" -gt 0 ]; then
+ docker exec --user=root -w / $name usermod -u $UID builder
+ fi
+ if [ "$GID" -gt 0 ]; then
+ docker exec --user=root -w / $name groupmod -g $GID builder
+ fi
+
+ notice "Setup permissions"
+ docker exec --user=root -w / $name sh -c "cd $home && chown builder:builder . rpm rpm/logs rpm/BUILD rpm/RPMS rpm/packages .ccache"
if [ ! -d $topdir/rpm-build-tools ]; then
- docker exec $name builder --init-rpm-dir
+ notice "Initialize rpm-build-tools"
+ docker exec -w / $name builder --init-rpm-dir
fi
}
+enter_container() {
+ notice "Entering container for $PACKAGE_NAME"
+ docker exec --user=root -it $name bash
+}
+
package_prepare() {
- # fetch sources and install deps
+ notice "Fetch sources and install dependencies"
if [ -d $topdir/packages/$PACKAGE_NAME ]; then
# chown, as it might be different owner (root) modified outside container
+ notice "Fix ownership of existing package directory"
docker exec --user=root -w / $name chown -R builder:builder $home/rpm/packages/$PACKAGE_NAME
fi
- docker exec $name builder -g $PACKAGE_NAME
- # prevent network access like pld builders do
- $NETWORKING || docker exec --user=root -w / $name setfacl -m u:builder:--- /etc/resolv.conf
+ notice "Fetch package sources"
+ docker exec --user=root -w / $name setfacl -x u:builder /etc/resolv.conf
+ docker exec -w / $name builder -g $PACKAGE_NAME
+
+ if ! $NETWORKING; then
+ notice "Disable networking: Prevent network access for user builder like PLD Linux builders"
+ docker exec --user=root -w / $name setfacl -m u:builder:--- /etc/resolv.conf
+ fi
- git_tag=$(GIT_DIR=$topdir/packages/$PACKAGE_NAME/.git git describe --tags --always)
+ notice "Find latest tag on the branch"
+ git_tag=$(docker exec -w / -e GIT_DIR=$home/rpm/packages/$PACKAGE_NAME/.git $name git describe --tags --always)
buildlog=rpm/logs/${git_tag#auto/*/}.log
+ notice "Build log: $buildlog"
}
package_build() {
set -- -nn ${WITH:+--with "${WITH# }"} ${WITHOUT:+--without "${WITHOUT# }"} "$PACKAGE_NAME"
while true; do
- # install deps
- docker exec $name builder -g -R "$@"
- # remove .la dependencies
+ notice "Install dependencies"
+ docker exec -w / -t $name builder -g -R "$@"
+ notice "Remove .la dependencies"
docker exec --user=root -w / $name $home/cleanbuild/bin/cleanup-la
- # reset findunusedbr state after deps install
+ notice "Reset findunusedbr state after deps install"
docker exec --user=root -w / $name $home/cleanbuild/bin/findunusedbr -c / $home/rpm/packages/$PACKAGE_NAME/$PACKAGE_NAME.spec
- # actual build
- docker exec $name cleanbuild/bin/teeboth $buildlog builder -bb --define '__spec_clean_body %{nil}' "$@" && rc=$? || rc=$?
+ notice "Build package"
+ docker exec -w $home $name cleanbuild/bin/teeboth $buildlog builder -bb --define '__spec_clean_body %{nil}' "$@" && rc=$? || rc=$?
+ # Kill processes on Ctrl+C
+ if [ "$rc" = 255 ]; then
+ docker exec -w / $name pkill -e -u builder
+ die "Aborted" $rc
+ fi
findbr=$PACKAGE_NAME.findbr.log
- builddir=$(docker exec $name sh -c 'test ! -d rpm/BUILD/* || echo rpm/BUILD/*')
+ builddir=$(docker exec -w $home $name sh -c 'test ! -d rpm/BUILD/* || echo rpm/BUILD/*')
if [ -z "$builddir" ]; then
- echo >&2 "No build dir. Build failed?"
- exit 6
+ die "No build dir. Build failed?" 6
fi
- # need root to run poldek
+ notice "Execute findbr"
docker exec --user=root -w / $name sh -c "cd $home && cleanbuild/bin/findbr $builddir $buildlog" > $findbr
installed_something=false
while read pkg msg; do
- ./addbr rpm/packages/$PACKAGE_NAME/$PACKAGE_NAME.spec "$pkg" "$msg" || continue
+ bin/addbr rpm/packages/$PACKAGE_NAME/$PACKAGE_NAME.spec "$pkg" "$msg" || continue
installed_something=true
done < $findbr
rm -f $findbr
# go for another try
$installed_something && continue
+ notice "Execute findunusedbr"
docker exec --user=root -w / $name $home/cleanbuild/bin/findunusedbr -c / $home/rpm/packages/$PACKAGE_NAME/$PACKAGE_NAME.spec
if [ $rc -eq 0 ] && ! $KEEP_CONTAINER; then
- # finished ok, cleanup
+ notice "Finished ok, cleanup container"
docker kill $name >/dev/null && docker rm $name >/dev/null || :
fi
parse_options() {
local t
- t=$(getopt -o 'x' --long 'network,no-tmpfs,notmpfs,tmpfs:,keep-container,with:,without:' -n "$PROGRAM" -- "$@")
+ t=$(getopt -o 'x' --long 'network,exec,no-tmpfs,notmpfs,tmpfs:,keep-container:,with:,without:' -n "$PROGRAM" -- "$@")
[ $? != 0 ] && exit $?
eval set -- "$t"
--network)
NETWORKING=true
;;
+ --exec)
+ EXEC=true
+ ;;
--no-tmpfs|--notmpfs)
TMPFS=false
;;
TMPFS="$1"
;;
--keep-container)
- KEEP_CONTAINER=true
+ shift
+ is_bool "$1"
+ KEEP_CONTAINER=$1
;;
--with)
shift
- WITH="$WITH $1"
+ WITH="$WITH,$1"
;;
--without)
shift
- WITHOUT="$WITHOUT $1"
+ WITHOUT="$WITHOUT,$1"
;;
--)
shift
shift
done
- test "$#" -eq 1 || die "package not specified or excess arguments"
+ test "$#" -eq 1 || die "Package not specified or excess arguments"
PACKAGE_NAME="${1%.spec}"
}
$TRACING && set -x
local name="cleanbuild-$PACKAGE_NAME"
+ if $EXEC; then
+ enter_container
+ return
+ fi
create_container
package_prepare
package_build