Index > Literate source for docker files Edit on GitHub

Literate source for docker files

Table of Contents

Setup

Server

docker config

Docker files in this repo use buildkit features. To enable it include the following in file:///etc/docker/daemon.json.

{"experimental": true,
 "features": {"buildkit": true}}

portage ssh keys

Make sure that /var/lib/portage/home/.ssh exists and has the keys for accessing the interlex repo or other private repos.

distcc hosts

Even if you are not using distcc be sure to run

touch /etc/distcc/hosts.docker

on the host os otherwise the builder functions will produce cryptic errors for some packages because they can handle an absent /etc/distcc/hosts file but not one that is a directory. Note that docker has what might be considered a reasonable default which is that it will create a directory if it does not exist when it is the source of a mount rather than fail … but in our case this is annoying, and the cleanup is a pita, have to unmount and rmdir in the image, or just resnap the image because wow what a pain.

Client

Building the precursor images in gentoo/stage3 for this repo from scratch requires the buildx extension which requires experimental features to be enabled in the client.

If you want to push the images to a remote docker repository add the auths section as well (and fill it in with your credentials).

{"experimental": "enabled",
 "auths": {
   "https://index.docker.io/v1/": {
     "auth": "XXX NOT A REAL KEY FILL ME IN XXX"}}}

Package host

Prepare package host folders. The server will be started automatically below if it is not already up.

mkdir -p ~/files/binpkgs/multi

prepare all binpkg repos

We have to prepare all the binpkg repos so that during a first build they have some basic metadata, otherwise trying to emerge binpkgs will fail with strange errors in strange ways.

for stage3 in {hardened,amd64-musl-hardened}; do
    docker pull gentoo/stage3:${stage3}
    docker run \
    -v ~/files/binpkgs/multi:/var/cache/binpkgs \
    -e FEATURES=binpkg-multi-instance \
    -e QUICKPKG_DEFAULT_OPTS="--include-unmodified-config=y --umask=022" \
    --rm \
    gentoo/stage3:${stage3} \
    quickpkg "virtual/ssh";
done

Portage git ssh access

Needed for live ebuilds that point to private git repos. Eventually this should be baked into the docker in docker top level image.

You will need to generate ssh keys for the host system if they do not already exist, and you will need to register them with the git remote.

This is similar to what we do for portage-maven.

The default location for the portage home directory is now /var/lib/portage/home/.ssh which means that the ssh config and private keys can be stored there persistently and safely without violating the sandbox during package fetch.

In the even that you have to deal with some strange legacy case you may want to symlink a path outside the sandbox to a path inside the sandbox due to the change in home directory from /var/tmp/portage -> /var/lib/portage/home. Inside the images we have to run ln -s /var/tmp/portage/.ssh /var/lib/portage/home/.ssh.

If /var/tmp/portage is still the portage home folder and it is a ramdisk that is wiped on reboot you will want the following.

# relink .ssh across restarts
ln -s /mnt/str/portage/.ssh /var/tmp/portage/
chown -h portage:portage /var/tmp/portage/.ssh

git ignore

This takes care of itself.

.gitignore
docker-profile/*
repos/*
musl/*
gnu/*
other/*
sckan/*

Ops

CLI

The standard way to use this file to build is to run the following block WARNING: never run this command from inside the org-session screen, input will be severely broken

./source.org build --refresh --repos --resnap --live-rebuild

Build

If you are bootstrapping this file from scratch you will need to build dependent images in order.

To prepare a fresh cycle of images.

unset _refresh _repos _sync_gentoo _resnap _live_rebuild _nopkgbldr
_refresh=       # pull base images
_repos=         # pull ebuild repo images
_sync_gentoo=   # run emaint sync for gentoo repo
_resnap=        # snap package build containers set this if you changed the profile or you will have a bad time
_live_rebuild=  # rebuild 9999 ebuilds e.g. from git
_nopkgbldr=     # do not run package building steps

# XXX NOTE that these are embedded in the docker files right now
_img_stage3=${_img_stage3:-gentoo/stage3:amd64-musl-hardened}

__is3_0=${_img_stage3/\//-}
__is3_1=${__is3_0/:/-}
__src_from_img=${__is3_1/gentoo/latest}
_src_stage3=${__src_stage3:-${__src_from_img}}

_img_portage=${_img_portage:-gentoo/portage:latest}
# we web these in at the top since some of the vars are used in functions
# outside the builders (e.g. package-server)

export \
_path_binpkgs_root=${_path_root_binpkgs:-~/files/binpkgs}
_binpkgs_repo_name=${_binpkgs_repo_name:-multi}
_path_binpkgs=${_path_binpkgs:-${_path_binpkgs_root}/${_binpkgs_repo_name}}
_path_distfiles=${_path_distfiles:-/mnt/str/portage/distfiles}
_path_distcc_hosts=${_path_distcc_hosts:-/etc/distcc/hosts.docker}
_path_ssh=${_path_ssh:-/var/lib/portage/home/.ssh}

export \
_tm_pb=${_tm_pb:-tgbugs/musl:package-builder}
_tm_s_pb=${_tm_s_pb:-tgbugs/musl:static-package-builder}

_tm_pbs=${_tm_pbs:-${_tm_pb}-snap}
_tm_s_pbs=${_tm_s_pbs:-${_tm_s_pb}-snap}

export \
_tg_pb=${_tg_pb:-tgbugs/gnu:package-builder}

_tg_pbs=${_tg_pbs:-${_tg_pb}-snap}


function package-server () {
# FIXME needs to run in another terminal, container, or daemon
# but for now it blocks other commands which is ok
curl --fail --head http://localhost:8089/${_binpkgs_repo_name}/Packages || {
    pushd ${_path_binpkgs_root}
    python -m http.server 8089 --bind 127.0.0.1
    popd
}
}

function pull () {
if [ -n "${_refresh}" ]; then
    # even when refresh is set avoid spurious pulls where the underlying stage3 has not changed
    local DIST="https://distfiles.gentoo.org/releases/amd64/autobuilds"
    local STAGE3_LATEST="$(curl --fail --silent "${DIST}/${_src_stage3}.txt" |\
        tail -n 1 | cut -f 1 -d'/' | sed -r 's/(....)(..)(..)T(..)(..)(..)/\1-\2-\3T\4:\5:\6/')"
    local LOCDOC_LATEST="$(docker image inspect ${_img_stage3} --format '{{.Created}}')"
    local S3_DATE=$(date -In --utc --date "${STAGE3_LATEST}")
    local LD_DATE=$(date -In --utc --date "${LOCDOC_LATEST}")
    # XXX there is technically a narrow window between the release of
    # a stage3 and the building of a docker image where this might fail
    # have to use double square brackets for this to work correctly
    [[ ${S3_DATE} < ${LD_DATE} ]] || \
    docker pull ${_img_stage3}
fi

if [ -n "${_refresh}" ] || [ -n "${_repos}" ]; then
    # these are updated more or less in sync with the upstream snapshot source
    docker pull ${_img_portage}
    docker rm local-portage-snap
    docker create -v /var/db/repos/gentoo --name local-portage-snap ${_img_portage} /bin/true
fi
}

function tangle () {
[ -d ./bin ] && rm -r ./bin
[ -d ./docker-profile ] && rm -r ./docker-profile
[ -d ./gnu ] && rm -r ./gnu
[ -d ./musl ] && rm -r ./musl
[ -d ./repos ] && rm -r ./repos
[ -d ./other ] && rm -r ./other
./source.org tangle
return $?
}

function container-check () {
docker container inspect local-repos-snap > /dev/null || \
docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true

# FIXME need to check that the cross image exists sigh make
docker container inspect cross-sbcl > /dev/null || \
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true
}

function builder-resnap () {
docker run ${_tm_pb}
docker commit $(docker ps -lqf ancestor=${_tm_pb}) ${_tm_pbs}
}
# FIXME SIGH SIGH SIGH why is this easier than doing the right thing
function static-builder-resnap () {
docker run ${_tm_s_pb}
docker commit $(docker ps -lqf ancestor=${_tm_s_pb}) ${_tm_s_pbs}
}
function gnu-builder-resnap () {
docker run ${_tg_pb}
docker commit $(docker ps -lqf ancestor=${_tg_pb}) ${_tg_pbs}
}

function builder-bootstrap () {
container-check

docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
done

}

# FIXME SIGH copy paste
function gnu-builder-bootstrap () {
container-check

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
done

}

function builder-world () {
container-check
cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN
local OUT=$?

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
return $OUT
}

# FIXME SIGH code dupe
function static-builder-world () {
container-check
cat ./musl/static-package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-smart-live-rebuild () {
container-check
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-smart-live-rebuild () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# FIXME code dupe
function static-builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_s_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
# SIGH
function gnu-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tg_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
}

function run-gnu () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
docker build \
--tag tgbugs/gnu:profile \
--file gnu/profile/Dockerfile .
docker build \
--tag tgbugs/gnu:eselect-repo \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/eselect-repo/Dockerfile gnu/eselect-repo
docker build \
--tag tgbugs/gnu:package-builder \
--file gnu/package-builder/Dockerfile gnu/package-builder
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/gnu:package-builder \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
[ -z $RESNAP ] || gnu-builder-resnap
[ ! -z $NOBUILD ] || gnu-builder-bootstrap
}

function run-musl () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
echo start bootstrap
docker build \
--tag tgbugs/musl:user \
--file musl/user/Dockerfile musl/user || return $?;
docker build \
--tag tgbugs/musl:portage-maven \
--file musl/portage-maven/Dockerfile musl/portage-maven || return $?;
docker build \
--tag tgbugs/musl:profile \
--file musl/profile/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-x \
--file musl/profile-x/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-nox \
--file docker-profile/nox/Dockerfile docker-profile/nox || return $?;
docker build \
--tag tgbugs/musl:profile-static-x \
--file musl/profile-x/static.Dockerfile . || return $?;
  docker build \
  --network host \
  --add-host local.binhost:127.0.0.1 \
  --tag tgbugs/musl:eselect-repo \
  --file musl/eselect-repo/Dockerfile musl/eselect-repo || return $?;
    [ -z $REPOS ] || {
    docker build \
    --no-cache \
    --build-arg SYNC_GENTOO=$SYNC_GENTOO \
    --tag tgbugs/repos:latest \
    --file repos/Dockerfile repos || return $?;
    docker container inspect local-repos-snap > /dev/null &&
    docker rm local-repos-snap;
    docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true || return $?;
    echo repos done;
    }
    container-check
    docker build \
    --tag tgbugs/musl:updated \
    --network host \
    --add-host local.binhost:127.0.0.1 \
    --file musl/updated/Dockerfile musl/updated || return $?; echo mbu;
      docker build \
      --tag tgbugs/musl:updated-user \
      --build-arg UID=${UID} \
      --file musl/updated-user/Dockerfile musl/updated-user || return $?; echo mbuu;
      docker run \
      --volumes-from local-repos-snap \
      -v ${_path_binpkgs}:/var/cache/binpkgs \
      -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
      --rm \
      tgbugs/musl:updated \
      /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mruq;

      docker build \
      --network host \
      --add-host local.binhost:127.0.0.1 \
      --tag tgbugs/musl:pypy3 \
      --file musl/pypy3/Dockerfile musl/pypy3 || return $?; echo mbpypy3;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:pypy3 \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrpypy3q;

        docker build \
        --tag tgbugs/musl:package-builder-nox \
        --file musl/package-builder/nox.Dockerfile musl/package-builder || return $?; echo mbpbn;
        docker build \
        --tag tgbugs/musl:binpkg-only-nox \
        --file musl/binpkg-only/nox.Dockerfile musl/binpkg-only || return $?; echo mbbon;

        # XXX this is the point at which things split into musl and musl/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:xorg \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrxq;

        docker build \
        --tag tgbugs/musl:package-builder \
        --file musl/package-builder/Dockerfile musl/package-builder || return $?; echo mbpb;
        docker build \
        --tag tgbugs/musl:binpkg-only \
        --file musl/binpkg-only/Dockerfile musl/binpkg-only || return $?; echo mbpo;

        # XXX split to musl/static/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:static-xorg \
        --build-arg PROFILE='docker-profile:tgbugs/musl/static/x' \
        --build-arg PROFILE_IMAGE='tgbugs/musl:profile-static-x' \
        --build-arg START_IMAGE='tgbugs/musl:updated' \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbsx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:static-xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrsxp;

        docker build \
        --tag tgbugs/musl:static-package-builder \
        --file musl/package-builder/static.Dockerfile musl/package-builder || return $?; echo mbspb;
        docker build \
        --tag tgbugs/musl:static-binpkg-only \
        --file musl/binpkg-only/static.Dockerfile musl/binpkg-only || return $?; echo mbsbo;


# TODO build any new packages
echo musl builder start
[ -z $RESNAP ] || builder-resnap
[ ! -z $NOBUILD ] || builder-bootstrap
# FIXME this needs to run with --getbinpkg
[ ! -z $NOBUILD ] || \
builder-arb-priv -1 -uN --getbinpkg \
dev-lang/go \
dev-go/go-md2man \
app-containers/runc \
app-containers/containerd \
app-containers/docker-cli
[ ! -z $NOBUILD ] || builder-world || return $?
# TODO smart-live-rebuild
[ -z $LIVE_REBUILD ] || builder-smart-live-rebuild || return $?

echo musl static builder start
[ -z $RESNAP ] || static-builder-resnap
# TODO static-builder-bootstrap
[ ! -z $NOBUILD ] || static-builder-world || return $?  # FIXME if this is not run once at the start then something fails above
# [ -z $LIVE_REBUILD ] || static-builder-smart-live-rebuild || return $?  # no live builds right now

# TODO consider whether we need to rebuild baselayout openrc sgml-common due to config issues with quickpkg

# image builds

echo start image builds

## emacs
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:emacs \
--file musl/emacs/Dockerfile musl/emacs || return $?; echo mbe;  # XXX fail on stale profile is very confusing

## kg
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-release \
--file musl/kg-release/Dockerfile musl/kg-release || return $?; echo mbkgr;
unset _devel _docd _sckand _docsfsc
_devel=
_docd=(queries.org)
_docsf="https://raw.githubusercontent.com/SciCrunch/sparc-curation/master/docs/"
_sckand=(welcome.org tutorial.org overview.org examples.org scratch.org README.org)
_docsfsc="${_docsf}sckan/"
pushd ./musl/kg-release-user
  [ -d sckan ] && rm -r sckan
  mkdir sckan
  pushd sckan
    mkdir images
    mkdir reports
    if [ -n "${_devel}" ]; then
      cp -aL ~/git/sparc-curation/docs/sckan/*.org . ;
    else
      for fn in ${_docd[@]};   do curl -O ${_docsf}${fn}  ; done
      for fn in ${_sckand[@]}; do curl -O ${_docsfsc}${fn}; done
    fi
    chmod +x ./queries.org
  popd
popd

docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user || return $?; echo mbkgru;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-dev \
--build-arg UID=${UID} \
--file musl/kg-dev/Dockerfile musl/kg-dev || return $?; echo mbkgd;
docker build \
--tag tgbugs/musl:kg-dev-user \
--build-arg UID=${UID} \
--file musl/kg-dev-user/Dockerfile musl/kg-dev-user || return $?; echo mbkgdu;

## sbcl
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sbcl \
--file musl/sbcl/Dockerfile musl/sbcl || return $?; echo mbsbcl;
docker build \
--tag tgbugs/musl:sbcl-user \
--build-arg UID=${UID} \
--file musl/sbcl-user/Dockerfile musl/sbcl-user || return $?; echo mbsbclu;

## racket
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:racket \
--file musl/racket/Dockerfile musl/racket || return $?; echo mbrac;
docker build \
--tag tgbugs/musl:racket-user \
--build-arg UID=${UID} \
--file musl/racket-user/Dockerfile musl/racket-user || return $?; echo mbracu;

## dynapad
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:dynapad-base \
--file musl/dynapad-base/Dockerfile musl/dynapad-base || return $?; echo mbdb;
docker build \
--tag tgbugs/musl:dynapad-user \
--build-arg UID=${UID} \
--file musl/dynapad-user/Dockerfile musl/dynapad-user || return $?; echo mbdbu;
# || return $?; # needs to be done by hand

## NIF-ontology
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:icedtea \
--file musl/icedtea/Dockerfile musl/icedtea || return $?; echo mbicdt;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:protege \
--build-arg UID=${UID} \
--file musl/protege/Dockerfile musl/protege || return $?; echo mbp;
docker build \
--tag tgbugs/musl:NIF-Ontology \
--file musl/NIF-Ontology/Dockerfile musl/NIF-Ontology || return $?; echo mbno;

## interlex
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:interlex \
--file musl/interlex/Dockerfile musl/interlex || return $?; echo mbilx;

## sparcur
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sparcur \
--file musl/sparcur/Dockerfile musl/sparcur || return $?; echo mbsp;
docker build \
--tag tgbugs/musl:sparcur-user \
--file musl/sparcur-user/Dockerfile musl/sparcur-user || return $?; echo mbspu;

}

package-server
pull
pushd ~/git/dockerfiles
tangle &&
run-musl
# package host
# build a bunch of packages
popd
# XXX NOTE that these are embedded in the docker files right now
_img_stage3=${_img_stage3:-gentoo/stage3:amd64-musl-hardened}

__is3_0=${_img_stage3/\//-}
__is3_1=${__is3_0/:/-}
__src_from_img=${__is3_1/gentoo/latest}
_src_stage3=${__src_stage3:-${__src_from_img}}

_img_portage=${_img_portage:-gentoo/portage:latest}
HISTFILE=~/.org_session_history
nil
# XXX NOTE that these are embedded in the docker files right now
_img_stage3=${_img_stage3:-gentoo/stage3:amd64-musl-hardened}

__is3_0=${_img_stage3/\//-}
__is3_1=${__is3_0/:/-}
__src_from_img=${__is3_1/gentoo/latest}
_src_stage3=${__src_stage3:-${__src_from_img}}

_img_portage=${_img_portage:-gentoo/portage:latest}
# we web these in at the top since some of the vars are used in functions
# outside the builders (e.g. package-server)

export \
_path_binpkgs_root=${_path_root_binpkgs:-~/files/binpkgs}
_binpkgs_repo_name=${_binpkgs_repo_name:-multi}
_path_binpkgs=${_path_binpkgs:-${_path_binpkgs_root}/${_binpkgs_repo_name}}
_path_distfiles=${_path_distfiles:-/mnt/str/portage/distfiles}
_path_distcc_hosts=${_path_distcc_hosts:-/etc/distcc/hosts.docker}
_path_ssh=${_path_ssh:-/var/lib/portage/home/.ssh}

export \
_tm_pb=${_tm_pb:-tgbugs/musl:package-builder}
_tm_s_pb=${_tm_s_pb:-tgbugs/musl:static-package-builder}

_tm_pbs=${_tm_pbs:-${_tm_pb}-snap}
_tm_s_pbs=${_tm_s_pbs:-${_tm_s_pb}-snap}

export \
_tg_pb=${_tg_pb:-tgbugs/gnu:package-builder}

_tg_pbs=${_tg_pbs:-${_tg_pb}-snap}


function package-server () {
# FIXME needs to run in another terminal, container, or daemon
# but for now it blocks other commands which is ok
curl --fail --head http://localhost:8089/${_binpkgs_repo_name}/Packages || {
    pushd ${_path_binpkgs_root}
    python -m http.server 8089 --bind 127.0.0.1
    popd
}
}

function pull () {
if [ -n "${_refresh}" ]; then
    # even when refresh is set avoid spurious pulls where the underlying stage3 has not changed
    local DIST="https://distfiles.gentoo.org/releases/amd64/autobuilds"
    local STAGE3_LATEST="$(curl --fail --silent "${DIST}/${_src_stage3}.txt" |\
        tail -n 1 | cut -f 1 -d'/' | sed -r 's/(....)(..)(..)T(..)(..)(..)/\1-\2-\3T\4:\5:\6/')"
    local LOCDOC_LATEST="$(docker image inspect ${_img_stage3} --format '{{.Created}}')"
    local S3_DATE=$(date -In --utc --date "${STAGE3_LATEST}")
    local LD_DATE=$(date -In --utc --date "${LOCDOC_LATEST}")
    # XXX there is technically a narrow window between the release of
    # a stage3 and the building of a docker image where this might fail
    # have to use double square brackets for this to work correctly
    [[ ${S3_DATE} < ${LD_DATE} ]] || \
    docker pull ${_img_stage3}
fi

if [ -n "${_refresh}" ] || [ -n "${_repos}" ]; then
    # these are updated more or less in sync with the upstream snapshot source
    docker pull ${_img_portage}
    docker rm local-portage-snap
    docker create -v /var/db/repos/gentoo --name local-portage-snap ${_img_portage} /bin/true
fi
}

function tangle () {
[ -d ./bin ] && rm -r ./bin
[ -d ./docker-profile ] && rm -r ./docker-profile
[ -d ./gnu ] && rm -r ./gnu
[ -d ./musl ] && rm -r ./musl
[ -d ./repos ] && rm -r ./repos
[ -d ./other ] && rm -r ./other
./source.org tangle
return $?
}

function container-check () {
docker container inspect local-repos-snap > /dev/null || \
docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true

# FIXME need to check that the cross image exists sigh make
docker container inspect cross-sbcl > /dev/null || \
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true
}

function builder-resnap () {
docker run ${_tm_pb}
docker commit $(docker ps -lqf ancestor=${_tm_pb}) ${_tm_pbs}
}
# FIXME SIGH SIGH SIGH why is this easier than doing the right thing
function static-builder-resnap () {
docker run ${_tm_s_pb}
docker commit $(docker ps -lqf ancestor=${_tm_s_pb}) ${_tm_s_pbs}
}
function gnu-builder-resnap () {
docker run ${_tg_pb}
docker commit $(docker ps -lqf ancestor=${_tg_pb}) ${_tg_pbs}
}

function builder-bootstrap () {
container-check

docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
done

}

# FIXME SIGH copy paste
function gnu-builder-bootstrap () {
container-check

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
done

}

function builder-world () {
container-check
cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN
local OUT=$?

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
return $OUT
}

# FIXME SIGH code dupe
function static-builder-world () {
container-check
cat ./musl/static-package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-smart-live-rebuild () {
container-check
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-smart-live-rebuild () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# FIXME code dupe
function static-builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_s_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
# SIGH
function gnu-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tg_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
}

function run-gnu () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
docker build \
--tag tgbugs/gnu:profile \
--file gnu/profile/Dockerfile .
docker build \
--tag tgbugs/gnu:eselect-repo \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/eselect-repo/Dockerfile gnu/eselect-repo
docker build \
--tag tgbugs/gnu:package-builder \
--file gnu/package-builder/Dockerfile gnu/package-builder
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/gnu:package-builder \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
[ -z $RESNAP ] || gnu-builder-resnap
[ ! -z $NOBUILD ] || gnu-builder-bootstrap
}

function run-musl () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
echo start bootstrap
docker build \
--tag tgbugs/musl:user \
--file musl/user/Dockerfile musl/user || return $?;
docker build \
--tag tgbugs/musl:portage-maven \
--file musl/portage-maven/Dockerfile musl/portage-maven || return $?;
docker build \
--tag tgbugs/musl:profile \
--file musl/profile/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-x \
--file musl/profile-x/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-nox \
--file docker-profile/nox/Dockerfile docker-profile/nox || return $?;
docker build \
--tag tgbugs/musl:profile-static-x \
--file musl/profile-x/static.Dockerfile . || return $?;
  docker build \
  --network host \
  --add-host local.binhost:127.0.0.1 \
  --tag tgbugs/musl:eselect-repo \
  --file musl/eselect-repo/Dockerfile musl/eselect-repo || return $?;
    [ -z $REPOS ] || {
    docker build \
    --no-cache \
    --build-arg SYNC_GENTOO=$SYNC_GENTOO \
    --tag tgbugs/repos:latest \
    --file repos/Dockerfile repos || return $?;
    docker container inspect local-repos-snap > /dev/null &&
    docker rm local-repos-snap;
    docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true || return $?;
    echo repos done;
    }
    container-check
    docker build \
    --tag tgbugs/musl:updated \
    --network host \
    --add-host local.binhost:127.0.0.1 \
    --file musl/updated/Dockerfile musl/updated || return $?; echo mbu;
      docker build \
      --tag tgbugs/musl:updated-user \
      --build-arg UID=${UID} \
      --file musl/updated-user/Dockerfile musl/updated-user || return $?; echo mbuu;
      docker run \
      --volumes-from local-repos-snap \
      -v ${_path_binpkgs}:/var/cache/binpkgs \
      -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
      --rm \
      tgbugs/musl:updated \
      /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mruq;

      docker build \
      --network host \
      --add-host local.binhost:127.0.0.1 \
      --tag tgbugs/musl:pypy3 \
      --file musl/pypy3/Dockerfile musl/pypy3 || return $?; echo mbpypy3;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:pypy3 \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrpypy3q;

        docker build \
        --tag tgbugs/musl:package-builder-nox \
        --file musl/package-builder/nox.Dockerfile musl/package-builder || return $?; echo mbpbn;
        docker build \
        --tag tgbugs/musl:binpkg-only-nox \
        --file musl/binpkg-only/nox.Dockerfile musl/binpkg-only || return $?; echo mbbon;

        # XXX this is the point at which things split into musl and musl/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:xorg \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrxq;

        docker build \
        --tag tgbugs/musl:package-builder \
        --file musl/package-builder/Dockerfile musl/package-builder || return $?; echo mbpb;
        docker build \
        --tag tgbugs/musl:binpkg-only \
        --file musl/binpkg-only/Dockerfile musl/binpkg-only || return $?; echo mbpo;

        # XXX split to musl/static/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:static-xorg \
        --build-arg PROFILE='docker-profile:tgbugs/musl/static/x' \
        --build-arg PROFILE_IMAGE='tgbugs/musl:profile-static-x' \
        --build-arg START_IMAGE='tgbugs/musl:updated' \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbsx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:static-xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrsxp;

        docker build \
        --tag tgbugs/musl:static-package-builder \
        --file musl/package-builder/static.Dockerfile musl/package-builder || return $?; echo mbspb;
        docker build \
        --tag tgbugs/musl:static-binpkg-only \
        --file musl/binpkg-only/static.Dockerfile musl/binpkg-only || return $?; echo mbsbo;


# TODO build any new packages
echo musl builder start
[ -z $RESNAP ] || builder-resnap
[ ! -z $NOBUILD ] || builder-bootstrap
# FIXME this needs to run with --getbinpkg
[ ! -z $NOBUILD ] || \
builder-arb-priv -1 -uN --getbinpkg \
dev-lang/go \
dev-go/go-md2man \
app-containers/runc \
app-containers/containerd \
app-containers/docker-cli
[ ! -z $NOBUILD ] || builder-world || return $?
# TODO smart-live-rebuild
[ -z $LIVE_REBUILD ] || builder-smart-live-rebuild || return $?

echo musl static builder start
[ -z $RESNAP ] || static-builder-resnap
# TODO static-builder-bootstrap
[ ! -z $NOBUILD ] || static-builder-world || return $?  # FIXME if this is not run once at the start then something fails above
# [ -z $LIVE_REBUILD ] || static-builder-smart-live-rebuild || return $?  # no live builds right now

# TODO consider whether we need to rebuild baselayout openrc sgml-common due to config issues with quickpkg

# image builds

echo start image builds

## emacs
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:emacs \
--file musl/emacs/Dockerfile musl/emacs || return $?; echo mbe;  # XXX fail on stale profile is very confusing

## kg
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-release \
--file musl/kg-release/Dockerfile musl/kg-release || return $?; echo mbkgr;
unset _devel _docd _sckand _docsfsc
_devel=
_docd=(queries.org)
_docsf="https://raw.githubusercontent.com/SciCrunch/sparc-curation/master/docs/"
_sckand=(welcome.org tutorial.org overview.org examples.org scratch.org README.org)
_docsfsc="${_docsf}sckan/"
pushd ./musl/kg-release-user
  [ -d sckan ] && rm -r sckan
  mkdir sckan
  pushd sckan
    mkdir images
    mkdir reports
    if [ -n "${_devel}" ]; then
      cp -aL ~/git/sparc-curation/docs/sckan/*.org . ;
    else
      for fn in ${_docd[@]};   do curl -O ${_docsf}${fn}  ; done
      for fn in ${_sckand[@]}; do curl -O ${_docsfsc}${fn}; done
    fi
    chmod +x ./queries.org
  popd
popd

docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user || return $?; echo mbkgru;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-dev \
--build-arg UID=${UID} \
--file musl/kg-dev/Dockerfile musl/kg-dev || return $?; echo mbkgd;
docker build \
--tag tgbugs/musl:kg-dev-user \
--build-arg UID=${UID} \
--file musl/kg-dev-user/Dockerfile musl/kg-dev-user || return $?; echo mbkgdu;

## sbcl
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sbcl \
--file musl/sbcl/Dockerfile musl/sbcl || return $?; echo mbsbcl;
docker build \
--tag tgbugs/musl:sbcl-user \
--build-arg UID=${UID} \
--file musl/sbcl-user/Dockerfile musl/sbcl-user || return $?; echo mbsbclu;

## racket
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:racket \
--file musl/racket/Dockerfile musl/racket || return $?; echo mbrac;
docker build \
--tag tgbugs/musl:racket-user \
--build-arg UID=${UID} \
--file musl/racket-user/Dockerfile musl/racket-user || return $?; echo mbracu;

## dynapad
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:dynapad-base \
--file musl/dynapad-base/Dockerfile musl/dynapad-base || return $?; echo mbdb;
docker build \
--tag tgbugs/musl:dynapad-user \
--build-arg UID=${UID} \
--file musl/dynapad-user/Dockerfile musl/dynapad-user || return $?; echo mbdbu;
# || return $?; # needs to be done by hand

## NIF-ontology
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:icedtea \
--file musl/icedtea/Dockerfile musl/icedtea || return $?; echo mbicdt;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:protege \
--build-arg UID=${UID} \
--file musl/protege/Dockerfile musl/protege || return $?; echo mbp;
docker build \
--tag tgbugs/musl:NIF-Ontology \
--file musl/NIF-Ontology/Dockerfile musl/NIF-Ontology || return $?; echo mbno;

## interlex
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:interlex \
--file musl/interlex/Dockerfile musl/interlex || return $?; echo mbilx;

## sparcur
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sparcur \
--file musl/sparcur/Dockerfile musl/sparcur || return $?; echo mbsp;
docker build \
--tag tgbugs/musl:sparcur-user \
--file musl/sparcur-user/Dockerfile musl/sparcur-user || return $?; echo mbspu;

}

package-server
pull
pushd ~/git/dockerfiles
tangle &&
run-musl
# package host
# build a bunch of packages
popd
# we web these in at the top since some of the vars are used in functions
# outside the builders (e.g. package-server)

export \
_path_binpkgs_root=${_path_root_binpkgs:-~/files/binpkgs}
_binpkgs_repo_name=${_binpkgs_repo_name:-multi}
_path_binpkgs=${_path_binpkgs:-${_path_binpkgs_root}/${_binpkgs_repo_name}}
_path_distfiles=${_path_distfiles:-/mnt/str/portage/distfiles}
_path_distcc_hosts=${_path_distcc_hosts:-/etc/distcc/hosts.docker}
_path_ssh=${_path_ssh:-/var/lib/portage/home/.ssh}

export \
_tm_pb=${_tm_pb:-tgbugs/musl:package-builder}
_tm_s_pb=${_tm_s_pb:-tgbugs/musl:static-package-builder}

_tm_pbs=${_tm_pbs:-${_tm_pb}-snap}
_tm_s_pbs=${_tm_s_pbs:-${_tm_s_pb}-snap}

export \
_tg_pb=${_tg_pb:-tgbugs/gnu:package-builder}

_tg_pbs=${_tg_pbs:-${_tg_pb}-snap}


function package-server () {
# FIXME needs to run in another terminal, container, or daemon
# but for now it blocks other commands which is ok
curl --fail --head http://localhost:8089/${_binpkgs_repo_name}/Packages || {
    pushd ${_path_binpkgs_root}
    python -m http.server 8089 --bind 127.0.0.1
    popd
}
}

function pull () {
if [ -n "${_refresh}" ]; then
    # even when refresh is set avoid spurious pulls where the underlying stage3 has not changed
    local DIST="https://distfiles.gentoo.org/releases/amd64/autobuilds"
    local STAGE3_LATEST="$(curl --fail --silent "${DIST}/${_src_stage3}.txt" |\
        tail -n 1 | cut -f 1 -d'/' | sed -r 's/(....)(..)(..)T(..)(..)(..)/\1-\2-\3T\4:\5:\6/')"
    local LOCDOC_LATEST="$(docker image inspect ${_img_stage3} --format '{{.Created}}')"
    local S3_DATE=$(date -In --utc --date "${STAGE3_LATEST}")
    local LD_DATE=$(date -In --utc --date "${LOCDOC_LATEST}")
    # XXX there is technically a narrow window between the release of
    # a stage3 and the building of a docker image where this might fail
    # have to use double square brackets for this to work correctly
    [[ ${S3_DATE} < ${LD_DATE} ]] || \
    docker pull ${_img_stage3}
fi

if [ -n "${_refresh}" ] || [ -n "${_repos}" ]; then
    # these are updated more or less in sync with the upstream snapshot source
    docker pull ${_img_portage}
    docker rm local-portage-snap
    docker create -v /var/db/repos/gentoo --name local-portage-snap ${_img_portage} /bin/true
fi
}

function tangle () {
[ -d ./bin ] && rm -r ./bin
[ -d ./docker-profile ] && rm -r ./docker-profile
[ -d ./gnu ] && rm -r ./gnu
[ -d ./musl ] && rm -r ./musl
[ -d ./repos ] && rm -r ./repos
[ -d ./other ] && rm -r ./other
./source.org tangle
return $?
}

function container-check () {
docker container inspect local-repos-snap > /dev/null || \
docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true

# FIXME need to check that the cross image exists sigh make
docker container inspect cross-sbcl > /dev/null || \
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true
}

function builder-resnap () {
docker run ${_tm_pb}
docker commit $(docker ps -lqf ancestor=${_tm_pb}) ${_tm_pbs}
}
# FIXME SIGH SIGH SIGH why is this easier than doing the right thing
function static-builder-resnap () {
docker run ${_tm_s_pb}
docker commit $(docker ps -lqf ancestor=${_tm_s_pb}) ${_tm_s_pbs}
}
function gnu-builder-resnap () {
docker run ${_tg_pb}
docker commit $(docker ps -lqf ancestor=${_tg_pb}) ${_tg_pbs}
}

function builder-bootstrap () {
container-check

docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
done

}

# FIXME SIGH copy paste
function gnu-builder-bootstrap () {
container-check

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
done

}

function builder-world () {
container-check
cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN
local OUT=$?

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
return $OUT
}

# FIXME SIGH code dupe
function static-builder-world () {
container-check
cat ./musl/static-package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-smart-live-rebuild () {
container-check
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-smart-live-rebuild () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# FIXME code dupe
function static-builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_s_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
# SIGH
function gnu-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tg_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
}

function run-gnu () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
docker build \
--tag tgbugs/gnu:profile \
--file gnu/profile/Dockerfile .
docker build \
--tag tgbugs/gnu:eselect-repo \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/eselect-repo/Dockerfile gnu/eselect-repo
docker build \
--tag tgbugs/gnu:package-builder \
--file gnu/package-builder/Dockerfile gnu/package-builder
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/gnu:package-builder \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
[ -z $RESNAP ] || gnu-builder-resnap
[ ! -z $NOBUILD ] || gnu-builder-bootstrap
}

function run-musl () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
echo start bootstrap
docker build \
--tag tgbugs/musl:user \
--file musl/user/Dockerfile musl/user || return $?;
docker build \
--tag tgbugs/musl:portage-maven \
--file musl/portage-maven/Dockerfile musl/portage-maven || return $?;
docker build \
--tag tgbugs/musl:profile \
--file musl/profile/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-x \
--file musl/profile-x/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-nox \
--file docker-profile/nox/Dockerfile docker-profile/nox || return $?;
docker build \
--tag tgbugs/musl:profile-static-x \
--file musl/profile-x/static.Dockerfile . || return $?;
  docker build \
  --network host \
  --add-host local.binhost:127.0.0.1 \
  --tag tgbugs/musl:eselect-repo \
  --file musl/eselect-repo/Dockerfile musl/eselect-repo || return $?;
    [ -z $REPOS ] || {
    docker build \
    --no-cache \
    --build-arg SYNC_GENTOO=$SYNC_GENTOO \
    --tag tgbugs/repos:latest \
    --file repos/Dockerfile repos || return $?;
    docker container inspect local-repos-snap > /dev/null &&
    docker rm local-repos-snap;
    docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true || return $?;
    echo repos done;
    }
    container-check
    docker build \
    --tag tgbugs/musl:updated \
    --network host \
    --add-host local.binhost:127.0.0.1 \
    --file musl/updated/Dockerfile musl/updated || return $?; echo mbu;
      docker build \
      --tag tgbugs/musl:updated-user \
      --build-arg UID=${UID} \
      --file musl/updated-user/Dockerfile musl/updated-user || return $?; echo mbuu;
      docker run \
      --volumes-from local-repos-snap \
      -v ${_path_binpkgs}:/var/cache/binpkgs \
      -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
      --rm \
      tgbugs/musl:updated \
      /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mruq;

      docker build \
      --network host \
      --add-host local.binhost:127.0.0.1 \
      --tag tgbugs/musl:pypy3 \
      --file musl/pypy3/Dockerfile musl/pypy3 || return $?; echo mbpypy3;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:pypy3 \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrpypy3q;

        docker build \
        --tag tgbugs/musl:package-builder-nox \
        --file musl/package-builder/nox.Dockerfile musl/package-builder || return $?; echo mbpbn;
        docker build \
        --tag tgbugs/musl:binpkg-only-nox \
        --file musl/binpkg-only/nox.Dockerfile musl/binpkg-only || return $?; echo mbbon;

        # XXX this is the point at which things split into musl and musl/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:xorg \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrxq;

        docker build \
        --tag tgbugs/musl:package-builder \
        --file musl/package-builder/Dockerfile musl/package-builder || return $?; echo mbpb;
        docker build \
        --tag tgbugs/musl:binpkg-only \
        --file musl/binpkg-only/Dockerfile musl/binpkg-only || return $?; echo mbpo;

        # XXX split to musl/static/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:static-xorg \
        --build-arg PROFILE='docker-profile:tgbugs/musl/static/x' \
        --build-arg PROFILE_IMAGE='tgbugs/musl:profile-static-x' \
        --build-arg START_IMAGE='tgbugs/musl:updated' \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbsx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:static-xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrsxp;

        docker build \
        --tag tgbugs/musl:static-package-builder \
        --file musl/package-builder/static.Dockerfile musl/package-builder || return $?; echo mbspb;
        docker build \
        --tag tgbugs/musl:static-binpkg-only \
        --file musl/binpkg-only/static.Dockerfile musl/binpkg-only || return $?; echo mbsbo;


# TODO build any new packages
echo musl builder start
[ -z $RESNAP ] || builder-resnap
[ ! -z $NOBUILD ] || builder-bootstrap
# FIXME this needs to run with --getbinpkg
[ ! -z $NOBUILD ] || \
builder-arb-priv -1 -uN --getbinpkg \
dev-lang/go \
dev-go/go-md2man \
app-containers/runc \
app-containers/containerd \
app-containers/docker-cli
[ ! -z $NOBUILD ] || builder-world || return $?
# TODO smart-live-rebuild
[ -z $LIVE_REBUILD ] || builder-smart-live-rebuild || return $?

echo musl static builder start
[ -z $RESNAP ] || static-builder-resnap
# TODO static-builder-bootstrap
[ ! -z $NOBUILD ] || static-builder-world || return $?  # FIXME if this is not run once at the start then something fails above
# [ -z $LIVE_REBUILD ] || static-builder-smart-live-rebuild || return $?  # no live builds right now

# TODO consider whether we need to rebuild baselayout openrc sgml-common due to config issues with quickpkg

# image builds

echo start image builds

## emacs
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:emacs \
--file musl/emacs/Dockerfile musl/emacs || return $?; echo mbe;  # XXX fail on stale profile is very confusing

## kg
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-release \
--file musl/kg-release/Dockerfile musl/kg-release || return $?; echo mbkgr;
unset _devel _docd _sckand _docsfsc
_devel=
_docd=(queries.org)
_docsf="https://raw.githubusercontent.com/SciCrunch/sparc-curation/master/docs/"
_sckand=(welcome.org tutorial.org overview.org examples.org scratch.org README.org)
_docsfsc="${_docsf}sckan/"
pushd ./musl/kg-release-user
  [ -d sckan ] && rm -r sckan
  mkdir sckan
  pushd sckan
    mkdir images
    mkdir reports
    if [ -n "${_devel}" ]; then
      cp -aL ~/git/sparc-curation/docs/sckan/*.org . ;
    else
      for fn in ${_docd[@]};   do curl -O ${_docsf}${fn}  ; done
      for fn in ${_sckand[@]}; do curl -O ${_docsfsc}${fn}; done
    fi
    chmod +x ./queries.org
  popd
popd

docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user || return $?; echo mbkgru;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-dev \
--build-arg UID=${UID} \
--file musl/kg-dev/Dockerfile musl/kg-dev || return $?; echo mbkgd;
docker build \
--tag tgbugs/musl:kg-dev-user \
--build-arg UID=${UID} \
--file musl/kg-dev-user/Dockerfile musl/kg-dev-user || return $?; echo mbkgdu;

## sbcl
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sbcl \
--file musl/sbcl/Dockerfile musl/sbcl || return $?; echo mbsbcl;
docker build \
--tag tgbugs/musl:sbcl-user \
--build-arg UID=${UID} \
--file musl/sbcl-user/Dockerfile musl/sbcl-user || return $?; echo mbsbclu;

## racket
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:racket \
--file musl/racket/Dockerfile musl/racket || return $?; echo mbrac;
docker build \
--tag tgbugs/musl:racket-user \
--build-arg UID=${UID} \
--file musl/racket-user/Dockerfile musl/racket-user || return $?; echo mbracu;

## dynapad
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:dynapad-base \
--file musl/dynapad-base/Dockerfile musl/dynapad-base || return $?; echo mbdb;
docker build \
--tag tgbugs/musl:dynapad-user \
--build-arg UID=${UID} \
--file musl/dynapad-user/Dockerfile musl/dynapad-user || return $?; echo mbdbu;
# || return $?; # needs to be done by hand

## NIF-ontology
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:icedtea \
--file musl/icedtea/Dockerfile musl/icedtea || return $?; echo mbicdt;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:protege \
--build-arg UID=${UID} \
--file musl/protege/Dockerfile musl/protege || return $?; echo mbp;
docker build \
--tag tgbugs/musl:NIF-Ontology \
--file musl/NIF-Ontology/Dockerfile musl/NIF-Ontology || return $?; echo mbno;

## interlex
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:interlex \
--file musl/interlex/Dockerfile musl/interlex || return $?; echo mbilx;

## sparcur
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sparcur \
--file musl/sparcur/Dockerfile musl/sparcur || return $?; echo mbsp;
docker build \
--tag tgbugs/musl:sparcur-user \
--file musl/sparcur-user/Dockerfile musl/sparcur-user || return $?; echo mbspu;

}

package-server
pull
pushd ~/git/dockerfiles
tangle &&
run-musl
# package host
# build a bunch of packages
popd
# we web these in at the top since some of the vars are used in functions
# outside the builders (e.g. package-server)

export \
_path_binpkgs_root=${_path_root_binpkgs:-~/files/binpkgs}
_binpkgs_repo_name=${_binpkgs_repo_name:-multi}
_path_binpkgs=${_path_binpkgs:-${_path_binpkgs_root}/${_binpkgs_repo_name}}
_path_distfiles=${_path_distfiles:-/mnt/str/portage/distfiles}
_path_distcc_hosts=${_path_distcc_hosts:-/etc/distcc/hosts.docker}
_path_ssh=${_path_ssh:-/var/lib/portage/home/.ssh}

export \
_tm_pb=${_tm_pb:-tgbugs/musl:package-builder}
_tm_s_pb=${_tm_s_pb:-tgbugs/musl:static-package-builder}

_tm_pbs=${_tm_pbs:-${_tm_pb}-snap}
_tm_s_pbs=${_tm_s_pbs:-${_tm_s_pb}-snap}

export \
_tg_pb=${_tg_pb:-tgbugs/gnu:package-builder}

_tg_pbs=${_tg_pbs:-${_tg_pb}-snap}


function package-server () {
# FIXME needs to run in another terminal, container, or daemon
# but for now it blocks other commands which is ok
curl --fail --head http://localhost:8089/${_binpkgs_repo_name}/Packages || {
    pushd ${_path_binpkgs_root}
    python -m http.server 8089 --bind 127.0.0.1
    popd
}
}

function pull () {
if [ -n "${_refresh}" ]; then
    # even when refresh is set avoid spurious pulls where the underlying stage3 has not changed
    local DIST="https://distfiles.gentoo.org/releases/amd64/autobuilds"
    local STAGE3_LATEST="$(curl --fail --silent "${DIST}/${_src_stage3}.txt" |\
        tail -n 1 | cut -f 1 -d'/' | sed -r 's/(....)(..)(..)T(..)(..)(..)/\1-\2-\3T\4:\5:\6/')"
    local LOCDOC_LATEST="$(docker image inspect ${_img_stage3} --format '{{.Created}}')"
    local S3_DATE=$(date -In --utc --date "${STAGE3_LATEST}")
    local LD_DATE=$(date -In --utc --date "${LOCDOC_LATEST}")
    # XXX there is technically a narrow window between the release of
    # a stage3 and the building of a docker image where this might fail
    # have to use double square brackets for this to work correctly
    [[ ${S3_DATE} < ${LD_DATE} ]] || \
    docker pull ${_img_stage3}
fi

if [ -n "${_refresh}" ] || [ -n "${_repos}" ]; then
    # these are updated more or less in sync with the upstream snapshot source
    docker pull ${_img_portage}
    docker rm local-portage-snap
    docker create -v /var/db/repos/gentoo --name local-portage-snap ${_img_portage} /bin/true
fi
}

function tangle () {
[ -d ./bin ] && rm -r ./bin
[ -d ./docker-profile ] && rm -r ./docker-profile
[ -d ./gnu ] && rm -r ./gnu
[ -d ./musl ] && rm -r ./musl
[ -d ./repos ] && rm -r ./repos
[ -d ./other ] && rm -r ./other
./source.org tangle
return $?
}

function container-check () {
docker container inspect local-repos-snap > /dev/null || \
docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true

# FIXME need to check that the cross image exists sigh make
docker container inspect cross-sbcl > /dev/null || \
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true
}

function builder-resnap () {
docker run ${_tm_pb}
docker commit $(docker ps -lqf ancestor=${_tm_pb}) ${_tm_pbs}
}
# FIXME SIGH SIGH SIGH why is this easier than doing the right thing
function static-builder-resnap () {
docker run ${_tm_s_pb}
docker commit $(docker ps -lqf ancestor=${_tm_s_pb}) ${_tm_s_pbs}
}
function gnu-builder-resnap () {
docker run ${_tg_pb}
docker commit $(docker ps -lqf ancestor=${_tg_pb}) ${_tg_pbs}
}

function builder-bootstrap () {
container-check

docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
done

}

# FIXME SIGH copy paste
function gnu-builder-bootstrap () {
container-check

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
done

}

function builder-world () {
container-check
cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN
local OUT=$?

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
return $OUT
}

# FIXME SIGH code dupe
function static-builder-world () {
container-check
cat ./musl/static-package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-smart-live-rebuild () {
container-check
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-smart-live-rebuild () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# FIXME code dupe
function static-builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_s_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
# SIGH
function gnu-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tg_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
}

function run-gnu () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
docker build \
--tag tgbugs/gnu:profile \
--file gnu/profile/Dockerfile .
docker build \
--tag tgbugs/gnu:eselect-repo \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/eselect-repo/Dockerfile gnu/eselect-repo
docker build \
--tag tgbugs/gnu:package-builder \
--file gnu/package-builder/Dockerfile gnu/package-builder
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/gnu:package-builder \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
[ -z $RESNAP ] || gnu-builder-resnap
[ ! -z $NOBUILD ] || gnu-builder-bootstrap
}

function run-musl () {
local REPOS="${_repos}"
local SYNC_GENTOO="${_sync_gentoo}"
local RESNAP="${_resnap}"
local LIVE_REBUILD="${_live_rebuild}"
local NOBUILD="${_nopkgbldr}"
echo start bootstrap
docker build \
--tag tgbugs/musl:user \
--file musl/user/Dockerfile musl/user || return $?;
docker build \
--tag tgbugs/musl:portage-maven \
--file musl/portage-maven/Dockerfile musl/portage-maven || return $?;
docker build \
--tag tgbugs/musl:profile \
--file musl/profile/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-x \
--file musl/profile-x/Dockerfile . || return $?;
docker build \
--tag tgbugs/musl:profile-nox \
--file docker-profile/nox/Dockerfile docker-profile/nox || return $?;
docker build \
--tag tgbugs/musl:profile-static-x \
--file musl/profile-x/static.Dockerfile . || return $?;
  docker build \
  --network host \
  --add-host local.binhost:127.0.0.1 \
  --tag tgbugs/musl:eselect-repo \
  --file musl/eselect-repo/Dockerfile musl/eselect-repo || return $?;
    [ -z $REPOS ] || {
    docker build \
    --no-cache \
    --build-arg SYNC_GENTOO=$SYNC_GENTOO \
    --tag tgbugs/repos:latest \
    --file repos/Dockerfile repos || return $?;
    docker container inspect local-repos-snap > /dev/null &&
    docker rm local-repos-snap;
    docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true || return $?;
    echo repos done;
    }
    container-check
    docker build \
    --tag tgbugs/musl:updated \
    --network host \
    --add-host local.binhost:127.0.0.1 \
    --file musl/updated/Dockerfile musl/updated || return $?; echo mbu;
      docker build \
      --tag tgbugs/musl:updated-user \
      --build-arg UID=${UID} \
      --file musl/updated-user/Dockerfile musl/updated-user || return $?; echo mbuu;
      docker run \
      --volumes-from local-repos-snap \
      -v ${_path_binpkgs}:/var/cache/binpkgs \
      -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
      --rm \
      tgbugs/musl:updated \
      /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mruq;

      docker build \
      --network host \
      --add-host local.binhost:127.0.0.1 \
      --tag tgbugs/musl:pypy3 \
      --file musl/pypy3/Dockerfile musl/pypy3 || return $?; echo mbpypy3;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:pypy3 \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrpypy3q;

        docker build \
        --tag tgbugs/musl:package-builder-nox \
        --file musl/package-builder/nox.Dockerfile musl/package-builder || return $?; echo mbpbn;
        docker build \
        --tag tgbugs/musl:binpkg-only-nox \
        --file musl/binpkg-only/nox.Dockerfile musl/binpkg-only || return $?; echo mbbon;

        # XXX this is the point at which things split into musl and musl/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:xorg \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrxq;

        docker build \
        --tag tgbugs/musl:package-builder \
        --file musl/package-builder/Dockerfile musl/package-builder || return $?; echo mbpb;
        docker build \
        --tag tgbugs/musl:binpkg-only \
        --file musl/binpkg-only/Dockerfile musl/binpkg-only || return $?; echo mbpo;

        # XXX split to musl/static/x
        docker build \
        --network host \
        --add-host local.binhost:127.0.0.1 \
        --tag tgbugs/musl:static-xorg \
        --build-arg PROFILE='docker-profile:tgbugs/musl/static/x' \
        --build-arg PROFILE_IMAGE='tgbugs/musl:profile-static-x' \
        --build-arg START_IMAGE='tgbugs/musl:updated' \
        --file musl/xorg/Dockerfile musl/xorg || return $?; echo mbsx;
        docker run \
        --volumes-from local-repos-snap \
        -v ${_path_binpkgs}:/var/cache/binpkgs \
        -v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
        --rm \
        tgbugs/musl:static-xorg \
        /bin/sh -c 'quickpkg $(/tmp/quickpkg-new)' || return $?; echo mrsxp;

        docker build \
        --tag tgbugs/musl:static-package-builder \
        --file musl/package-builder/static.Dockerfile musl/package-builder || return $?; echo mbspb;
        docker build \
        --tag tgbugs/musl:static-binpkg-only \
        --file musl/binpkg-only/static.Dockerfile musl/binpkg-only || return $?; echo mbsbo;


# TODO build any new packages
echo musl builder start
[ -z $RESNAP ] || builder-resnap
[ ! -z $NOBUILD ] || builder-bootstrap
# FIXME this needs to run with --getbinpkg
[ ! -z $NOBUILD ] || \
builder-arb-priv -1 -uN --getbinpkg \
dev-lang/go \
dev-go/go-md2man \
app-containers/runc \
app-containers/containerd \
app-containers/docker-cli
[ ! -z $NOBUILD ] || builder-world || return $?
# TODO smart-live-rebuild
[ -z $LIVE_REBUILD ] || builder-smart-live-rebuild || return $?

echo musl static builder start
[ -z $RESNAP ] || static-builder-resnap
# TODO static-builder-bootstrap
[ ! -z $NOBUILD ] || static-builder-world || return $?  # FIXME if this is not run once at the start then something fails above
# [ -z $LIVE_REBUILD ] || static-builder-smart-live-rebuild || return $?  # no live builds right now

# TODO consider whether we need to rebuild baselayout openrc sgml-common due to config issues with quickpkg

# image builds

echo start image builds

## emacs
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:emacs \
--file musl/emacs/Dockerfile musl/emacs || return $?; echo mbe;  # XXX fail on stale profile is very confusing

## kg
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-release \
--file musl/kg-release/Dockerfile musl/kg-release || return $?; echo mbkgr;
unset _devel _docd _sckand _docsfsc
_devel=
_docd=(queries.org)
_docsf="https://raw.githubusercontent.com/SciCrunch/sparc-curation/master/docs/"
_sckand=(welcome.org tutorial.org overview.org examples.org scratch.org README.org)
_docsfsc="${_docsf}sckan/"
pushd ./musl/kg-release-user
  [ -d sckan ] && rm -r sckan
  mkdir sckan
  pushd sckan
    mkdir images
    mkdir reports
    if [ -n "${_devel}" ]; then
      cp -aL ~/git/sparc-curation/docs/sckan/*.org . ;
    else
      for fn in ${_docd[@]};   do curl -O ${_docsf}${fn}  ; done
      for fn in ${_sckand[@]}; do curl -O ${_docsfsc}${fn}; done
    fi
    chmod +x ./queries.org
  popd
popd

docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user || return $?; echo mbkgru;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-dev \
--build-arg UID=${UID} \
--file musl/kg-dev/Dockerfile musl/kg-dev || return $?; echo mbkgd;
docker build \
--tag tgbugs/musl:kg-dev-user \
--build-arg UID=${UID} \
--file musl/kg-dev-user/Dockerfile musl/kg-dev-user || return $?; echo mbkgdu;

## sbcl
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sbcl \
--file musl/sbcl/Dockerfile musl/sbcl || return $?; echo mbsbcl;
docker build \
--tag tgbugs/musl:sbcl-user \
--build-arg UID=${UID} \
--file musl/sbcl-user/Dockerfile musl/sbcl-user || return $?; echo mbsbclu;

## racket
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:racket \
--file musl/racket/Dockerfile musl/racket || return $?; echo mbrac;
docker build \
--tag tgbugs/musl:racket-user \
--build-arg UID=${UID} \
--file musl/racket-user/Dockerfile musl/racket-user || return $?; echo mbracu;

## dynapad
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:dynapad-base \
--file musl/dynapad-base/Dockerfile musl/dynapad-base || return $?; echo mbdb;
docker build \
--tag tgbugs/musl:dynapad-user \
--build-arg UID=${UID} \
--file musl/dynapad-user/Dockerfile musl/dynapad-user || return $?; echo mbdbu;
# || return $?; # needs to be done by hand

## NIF-ontology
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:icedtea \
--file musl/icedtea/Dockerfile musl/icedtea || return $?; echo mbicdt;
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:protege \
--build-arg UID=${UID} \
--file musl/protege/Dockerfile musl/protege || return $?; echo mbp;
docker build \
--tag tgbugs/musl:NIF-Ontology \
--file musl/NIF-Ontology/Dockerfile musl/NIF-Ontology || return $?; echo mbno;

## interlex
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:interlex \
--file musl/interlex/Dockerfile musl/interlex || return $?; echo mbilx;

## sparcur
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sparcur \
--file musl/sparcur/Dockerfile musl/sparcur || return $?; echo mbsp;
docker build \
--tag tgbugs/musl:sparcur-user \
--file musl/sparcur-user/Dockerfile musl/sparcur-user || return $?; echo mbspu;

}

Debug build

Sometimes a build will fail. As long as you aren't using buildkit features such as mount you can rerun a build command with DOCKER_BUILDKIT=0 prepended which will keep the intermediate containers around so you can attach to the last known good layer and try to run things yourself.

Alternately, it may be a better approach to simply truncate the docker file directly after the last known good step

Push

To push the latest cycle of images to the default remote run the following after checking that they work as expected.

for _image in $(docker images --filter=reference="tgbugs/musl:*" --filter=reference="tgbugs/repos:*" --filter=since='tgbugs/musl:eselect-repo' --format "{{.Repository}}:{{.Tag}}" | grep -v snap); do
    docker push "${_image}"
done

Emergency quickpkg

Sometimes you don't want to wait to get to the package builder step because there is some bug in between.

function docker-quickpkg () {
# FIXME TODO pass the image to package
docker run \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-e FEATURES=binpkg-multi-instance \
-e QUICKPKG_DEFAULT_OPTS="--include-unmodified-config=y --umask=022" \
--rm \
tgbugs/musl:static-xorg \
quickpkg \
${@}
}

Cleanup

docker container prune --force
docker volume    prune --force
docker image     prune --force
docker builder   prune --force

Default variables

Default variable values that will eventually have cli overrides.

~/files/binpkgs

NOTE: we will not be making the repo name configurable, it only appears to be for implementation convenience.

multi
/mnt/str/portage/distfiles
/etc/distcc/hosts.docker
/var/lib/portage/home/.ssh
helper-repos

Next

TODO ebuilds changing behind the scenes

so it turns out that it is possible to change an ebuild, rebuild the package and .. install the newest version of that package, all while using the old ebuild, so it is possible to change ebuilds without revbumps build a matching package and the system can't detect the difference, this is probably a good thing because it allows for some wiggle room when things go wrong, but it is a reminder that packages are not 1:1 with ebuild versions

TODO update package builder image setup to accommodate /etc/portage/patches

pypy3 is an example of one case where we need a fix, but in general /etc/portage/patches is a way to rapidly build and deploy fixes without having to wait for e.g. a full pull request cycle to finish.

DONE catch errors in profile early

TODO dind or similar for top level ops

Docker is not homogeneous with regard to nesting containers since the way that we use it is a bit outside the usual use case (and because docker is a hack and true nesting reveals this by violating a whole bunch of assumptions that are baked into the implementation).

As a result, a hack is required to be able to fake nesting. In this case the simplest approach seems to be to make the ur-host's docker process accessible to the top level ops container. Not truly homogeneous, but better than nothing. This is done by mounting the socket for the docker daemon when you run the top level build image.

Since this is a build process security considerations are identical for the true host and the top level image. If we weren't running in the top level image we would be running on the true host directly so sandboxing is irrelevant.

An example approach would be to run something like the following.

docker run -v /var/run/docker.sock:/var/run/docker.sock tgbugs/musl:docker

DONE a better way

The primary issue here is that it really is not safe to compose after merge because the power and flexibility of portage happen before merge, and are quite state dependent after the fact. The key then is to be able to create images that do compose well, and the only at the very end materialize them by installing all the packages at once.

The problem is that you give up the utility of the docker layers, but if we are installing binary packages that have been built on a separate system then we know that we won't encounter build errors.

The final obstacle to full composability in this way is the issue of incompatible use flags, but I think it is safe to say that it is not really possible to solve that problem.

This consideration suggests that the layers of docker images, while useful, are fundamentally at odds with composability when there are files inside images that track state (e.g. /var/lib/portage/world).

DONE condense use flags

At the moment we keep use flags with packages and try to keep them mostly orthogonal to each other. However, at a certain point it is going to be easier to maintain a single shared use flag image that will be synchronized across all images. Granular control is nice from a learning and minimal specification point of view, but from an engineering an maintenance point of view it is vastly easier easier to maintain a single shared use flag image that will be synchronized across all images. Granular control is nice from a learning and minimal specification point of view, but from an engineering an maintenance point of view it is simpler to unify the individual image environments into a single file.

DONE create an image to build packages

Rebuilding images is wasteful when nothing has changed, and packages and install properly to maintain the correct state of the image. While COPY --from works, it mangles things like /var/lib/portage/world, and if use flags were changed on a dependency by another source image then unusual and unexpected errors could occur. This is another reason to move to manage use flags one or two images, one image for cases where X11 is not needed, and another where it is.

In fact, I'm fairly certain that having a shared use flag environment is necessary for it to be possible to safely compose packages and images. Composition across environments requires something like nix where each package carries around its own environment. It might be possible to do better than this by allowing composition in cases where the environments are compatible, but that would still require computation at composition time, you can't just layer images an expect things to work.

alternately mount /var/cache/binpkgs and then run quickpkg or something devious like that

TODO separate user image

Should be able to COPY --from=tgbugs/musl:user across all images. build the user image from a base that has next to nothing in it add the user and group to the system and then copy that minimal user stuff in, most of the time there isn't any fancy installation that needed to be done, and we could just copy the user directory when building from scratch

docker-profile

base

The right way to do this is to create two custom profiles on top of musl-hardened.

https://wiki.gentoo.org/wiki/Profile_(Portage)#custom

Modifications to use flags and other system settings and configurations that are easier to keep in a single location.

build

docker build \
--tag tgbugs/docker-profile:base \
--file docker-profile/base/Dockerfile docker-profile/base

file

# we don't put this in var/db/repos because repos is managed via tgbugs/repos:latest
ARG bp=docker-profile/base/

ADD ${bp}docker-profile                          var/db/docker-profile
ADD ${bp}docker-profile.conf                     etc/portage/repos.conf/docker-profile.conf
ADD ${bp}binrepos-multi.conf                     etc/portage/binrepos.conf/multi.conf
ADD ${bp}package.accept_keywords                 etc/portage/package.accept_keywords/profile
ADD ${bp}package.mask                            etc/portage/package.mask/profile
ADD ${bp}package.unmask                          etc/portage/package.unmask/profile
ADD ${bp}emacs.env                               etc/portage/env/app-editors/emacs
ADD ${bp}erlang.env                              etc/portage/env/dev-lang/erlang
ADD ${bp}rabbitmq.env                            etc/portage/env/net-misc/rabbitmq-server
ADD ${bp}no-distcc.env                           etc/portage/env/no-distcc
ADD ${bp}package.env                             etc/portage/package.env/profile
ADD ${bp}musl-find_library.patch                 etc/portage/patches/dev-lang/python:2.7/musl-find_library.patch
ADD ${bp}musl-include-sys-time.patch             etc/portage/patches/dev-python/pypy3-exe/musl-include-sys-time.patch
ADD ${bp}musl-fix-stdio-defs.patch               etc/portage/patches/dev-python/pypy3-exe/musl-fix-stdio-defs.patch
ADD ${bp}pypy3-json-str-subclass-safety.patch    etc/portage/patches/dev-python/pypy3/json-str-subclass-safety.patch
FROM busybox:latest as builder

WORKDIR /build

# we don't put this in var/db/repos because repos is managed via tgbugs/repos:latest
ARG bp=docker-profile/base/

ADD ${bp}docker-profile                          var/db/docker-profile
ADD ${bp}docker-profile.conf                     etc/portage/repos.conf/docker-profile.conf
ADD ${bp}binrepos-multi.conf                     etc/portage/binrepos.conf/multi.conf
ADD ${bp}package.accept_keywords                 etc/portage/package.accept_keywords/profile
ADD ${bp}package.mask                            etc/portage/package.mask/profile
ADD ${bp}package.unmask                          etc/portage/package.unmask/profile
ADD ${bp}emacs.env                               etc/portage/env/app-editors/emacs
ADD ${bp}erlang.env                              etc/portage/env/dev-lang/erlang
ADD ${bp}rabbitmq.env                            etc/portage/env/net-misc/rabbitmq-server
ADD ${bp}no-distcc.env                           etc/portage/env/no-distcc
ADD ${bp}package.env                             etc/portage/package.env/profile
ADD ${bp}musl-find_library.patch                 etc/portage/patches/dev-lang/python:2.7/musl-find_library.patch
ADD ${bp}musl-include-sys-time.patch             etc/portage/patches/dev-python/pypy3-exe/musl-include-sys-time.patch
ADD ${bp}musl-fix-stdio-defs.patch               etc/portage/patches/dev-python/pypy3-exe/musl-fix-stdio-defs.patch
ADD ${bp}pypy3-json-str-subclass-safety.patch    etc/portage/patches/dev-python/pypy3/json-str-subclass-safety.patch

FROM scratch

WORKDIR /
COPY --from=builder /build /

etc

  • repos.conf
    [docker-profile]
    location = /var/db/docker-profile
    
  • binrepos.conf
    [tgbugs-multi]
    priority = 100
    sync-uri = http://local.binhost:8089/multi
    
  • package.acceptkeywords
    dev-python/*::tgbugs-overlay
    dev-scheme/racket::tgbugs-overlay
    dev-haskell/*::tgbugs-overlay **
    dev-haskell/*::haskell
    dev-haskell/*::gentoo
    dev-lang/ghc::gentoo
    app-admin/haskell-updater::gentoo
    
  • package.mask
    dev-java/icedtea-bin::gentoo
    dev-scheme/racket::gentoo
    dev-haskell/*::haskell
    
  • package.unmask
    dev-haskell/fgl::haskell
    dev-haskell/graphviz::haskell
    dev-haskell/hxt-charproperties::haskell
    dev-haskell/hxt-regex-xmlschema::haskell
    dev-haskell/hxt-unicode::haskell
    dev-haskell/hxt::haskell
    dev-haskell/polyparse::haskell
    dev-haskell/wl-pprint-text::haskell
    
  • env
    • no distcc
      FEATURES="-distcc"
      
    • app-editors/emacs
      NATIVE_FULL_AOT=1
      
    • dev-lang/erlang
    • net-misc/rabbitmq-server

      It seems that a some point epmd started working correctly in docker images between 12.3.1 and 12.3.2.2, therefore rabbitmq can't start its own empd and fails to connect. This removes the depend statement in the init file that pulls in system epmd, which if started will cause rabbitmq to fail to start. The correct solution is to figure out how to correctly configure rabbitmq, but for now this should restore the old behavior.

      post_src_install() { sed -i '/need/d' "${D}"/etc/init.d/rabbitmq; }
      
  • package.env
    dev-python/pypy3 no-distcc
    dev-util/cmake no-distcc
    dev-util/colm no-distcc
    

profiles

masters = gentoo
profile-formats = portage-2
docker-profile
amd64 tgbugs               dev
amd64 tgbugs/x             dev
amd64 tgbugs/gnu           dev
amd64 tgbugs/gnu/x         dev
amd64 tgbugs/musl          dev
amd64 tgbugs/musl/x        dev
amd64 tgbugs/musl/static   dev
amd64 tgbugs/musl/static/x dev
  • packages

    Useful to keep these out of file:///var/lib/portage/world so that individual docker files can just ADD their world file and then emerge @world. It also makes it much easier for the package builder to operate based on world files.

    *dev-vcs/git
    *app-eselect/eselect-repository
    
  • make.defaults

    Normally we don't set USE= in make.conf, however there is no way to set global use flags in a profile without doing so.

    INSTALL_MASK="${INSTALL_MASK}
    /usr/share/locale
    -/usr/share/locale/en
    -/usr/share/locale/en@boldquot
    -/usr/share/locale/en@quot
    -/usr/share/locale/en@shaw
    -/usr/share/locale/en_US"
    
    FEATURES="${FEATURES} binpkg-multi-instance"
    
    EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --binpkg-respect-use=y"  # FIXME portageq shows bru opt twice ??
    
    # icu is needed due to musl collation issues
    # jemalloc can improve performance re issues with musl allocator
    USE="${USE} icu jemalloc"
    
    USE="${USE} -gstreamer"
    
    VIDEO_CARDS="-*"
    
    # ensure that packages are readable by other users via umask 022
    # use unmodified config in case a config file is modified, configs
    # should never wind up modified when using package builder images
    # see https://bugs.gentoo.org/307455 for more
    # FIXME XXX current issues include
    # /etc/hosts -> sys-apps/baselayout
    # /etc/rc.conf -> sys-apps/openrc
    # /etc/sgml/catalog -> app-text/sgml-common
    # which seem to have been modified by other merges
    QUICKPKG_DEFAULT_OPTS="--include-unmodified-config=y --umask=022"
    
    ACCT_GROUP_BLAZEGRAPH_ID=834
    ACCT_USER_BLAZEGRAPH_ID="${ACCT_GROUP_BLAZEGRAPH_ID}"
    
    ACCT_GROUP_SCIGRAPH_ID=835
    ACCT_USER_SCIGRAPH_ID="${ACCT_GROUP_SCIGRAPH_ID}"
    
    ACCT_GROUP_SPARC_ID=836
    ACCT_USER_SPARC_ID="${ACCT_GROUP_SPARC_ID}"
    
    ACCT_GROUP_PROTCUR_ID=837
    ACCT_USER_PROTCUR_ID="${ACCT_GROUP_PROTCUR_ID}"
    
    ACCT_GROUP_SCIBOT_ID=838
    ACCT_USER_SCIBOT_ID="${ACCT_GROUP_SCIBOT_ID}"
    
    ACCT_GROUP_INTERLEX_ID=839
    ACCT_USER_INTERLEX_ID="${ACCT_GROUP_INTERLEX_ID}"
    
    ACCT_GROUP_NIFSTD_TOOLS_ID=840
    ACCT_USER_NIFSTD_TOOLS_ID="${ACCT_GROUP_NIFSTD_TOOLS_ID}"
    
    ACCT_GROUP_METABASE_ID=841
    ACCT_USER_METABASE_ID="${ACCT_GROUP_METABASE_ID}"
    
    EGIT_OVERRIDE_REPO_SCIGRAPH_SCIGRAPH=https://github.com/SciCrunch/SciGraph.git
    EGIT_OVERRIDE_BRANCH_SCIGRAPH_SCIGRAPH=cypher-execute-fix
    
    # temporary commit override until the converter fixes are merged
    EGIT_OVERRIDE_BRANCH_OPEN_PHYSIOLOGY_OPEN_PHYSIOLOGY_VIEWER=fix-wrapper
    
  • mask
    # dynapad
    >=media-gfx/imagemagick-7
    
  • unmask
    # gtknor
    <gnome-base/librsvg-2.41
    dev-python/dicttoxml
    
  • acceptkeywords
    dev-python/pipenv ~amd64
    app-misc/yq ~amd64
    
    # harfbuzz 3.1.2 needs freetype-2.11.1 otherwise build fails
    =media-libs/freetype-2.11.1 ~amd64
    
    # tgbugs-overlay
    dev-db/blazegraph-bin ~amd64
    dev-db/pguri **
    dev-java/icedtea-bin ~amd64  # hacked to avoid musl blocking on gnu systems
    dev-java/robot-bin ~amd64
    dev-java/scigraph-bin ~amd64
    dev-node/apinat-converter **
    #dev-scheme/racket ~amd64  # profile can't restrict by repo :(
    
    # tgbugs-overlay python
    dev-python/interlex **
    dev-python/sparcur **
    
    # sparcur
    app-text/xlsx2csv ~amd64
    dev-python/semver ~amd64
    
    # gtknor
    <gnome-base/librsvg-2.41 **
    
    # emacs
    app-emacs/vterm ~amd64
    
    # sbcl
    dev-lisp/asdf ~amd64
    dev-lisp/uiop ~amd64
    dev-lisp/sbcl ~amd64
    
    # pypy3
    dev-python/pypy3-exe ~amd64
    dev-python/pypy3 ~amd64
    
  • package.use
    # setpriv command
    sys-apps/util-linux caps
    
    # font rendering
    media-libs/freetype -cleartype-hinting -cleartype_hinting
    
    # reduce deps
    dev-libs/uriparser -doc
    
    # needed to ensure that -egl doesn't introduce conflicts
    x11-base/xorg-server minimal
    
    app-editors/emacs dynamic-loading gmp json threads
    
    # gdb don't pull in the world
    sys-devel/gdb -nls -python
    
    # pyzmq
    net-libs/zeromq drafts
    
    dev-scheme/racket cs bc cgc jit
    
    # graphviz
    media-libs/gd truetype fontconfig
    
    # pypy3
    dev-python/pypy3-exe jit
    dev-python/pypy3 sqlite
    
    # uwsgi needs at least one backend enabled
    www-servers/uwsgi python
    
    # keep ipykernel deps minimal for emacs-jupyter
    dev-python/ipython -smp
    
    # tgbugs-overlay python
    dev-python/interlex alt database
    dev-python/orthauth yaml
    dev-python/pint babel uncertainties
    dev-python/sparcur cron  # XXX FIXME not all images want to pull in the cron deps, or the dashboard deps
    dev-python/sxpyr -cli  # XXX FIXME avoid circular dep on clifun
    
  • use.mask
    # reduce deps
    perl
    gtk
    cups
    postscript
    
    # reduce xorg deps
    llvm
    egl
    gles2
    gallium
    dbus
    vala
    introspection
    elogind
    
    # allow pypy3 as a python target
    -python_targets_pypy3
    
  • x/

    intentionally empty

    • parent
      ..
      
  • nox/

    intentionally empty

    • parent
      ..
      
  • gnu/
    • parent
      gentoo:default/linux/amd64/17.1/hardened
      ..
      
  • gnu/x/
    • parent
      ..
      ../../x
      
  • gnu/nox/
    • parent
      ..
      ../../nox
      
  • musl/
    • parent
      gentoo:default/linux/amd64/17.0/musl/hardened
      ..
      
    • package.use
      dev-lang/ghc ghcbootstrap
      
    • package.unmask
      dev-lisp/sbcl
      
  • musl/x/
    • parent
      ..
      ../../x
      
  • musl/nox/
    • parent
      ..
      ../../nox
      
  • musl/static
    • parent
      ..
      
  • musl/static/x
    • parent
      ..
      ../../../x
      
  • musl/static/nox
    • parent
      ..
      ../../../nox
      

static

file

ARG bp=docker-profile/static/
ARG hr=helper-repos/

# ADD ${bp}sbcl.env etc/portage/env/dev-lisp/sbcl  # gets klobbered when we make the profile so have to do it differently
ADD ${hr}sbcl/patches/dev-lisp etc/portage/patches/dev-lisp

profiles

  • make.defaults

    We only set static-libs not static because static statically links the executable which we rarely want, in which case a positive static use flag should be added below, rather than turning off nearly every instance of static that we encounter.

    USE="${USE} static-libs"
    
  • package.use   ARCHIVE

x

profiles

  • parent
    ..
    
  • packages
    *media-fonts/dejavu
    *media-libs/fontconfig
    *media-libs/freetype
    
  • make.defaults
    USE="${USE} X"
    VIDEO_CARDS="-*"
    
  • package.use
    # ,*/* X # FIXME it seems that wildcards are not allowed in here so for now has to be done later
    
    media-libs/freetype harfbuzz
    
    # the mesa ebuilds in the main tree are missing the fact that
    # gbm expects egl to be enabled, if it is not build errors
    media-libs/mesa -gbm
    
    app-editors/emacs gui jpeg png Xaw3d xft # XXX note that latest reccomendations are to use harfbuzz + cairo for text shaping (or something like that)
    app-emacs/emacs-common gui
    
    # avoid extra deps
    dev-util/cmake -ncurses
    
    # scigraph
    x11-base/xorg-server xvfb
    
    # xdg-utils build time dep pulled in by cups somehow
    app-text/xmlto text
    
  • mask
    
    
  • acceptkeywords
    
    

nox

Explicit nox profile.

build

docker build \
--tag tgbugs/musl:profile-nox \
--file docker-profile/nox/Dockerfile docker-profile/nox

file

FROM busybox:latest as builder

WORKDIR /build

ADD docker-profile var/db/docker-profile

FROM scratch

WORKDIR /
COPY --from=builder /build /

profiles

  • parent
    ..
    
  • package.use
    dev-java/icedtea headless-awt
    

repos

Overlays can take up quite a bit of space so it is better to mount them the same way we mount the gentoo repo during build so that we can keep the images a bit slimmer. We can publish the build images independently, and it is also worth noting that from a reproducibility perspective the exact ebuilds are stored in file:///var/db/pkg/.

debug

docker run \
--entrypoint /bin/sh \
-it tgbugs/repos:latest

build

docker build \
--no-cache \
--build-arg SYNC_GENTOO=$SYNC_GENTOO \
--tag tgbugs/repos:latest \
--file repos/Dockerfile repos

file

FROM tgbugs/musl:eselect-repo as builder

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
   emaint sync --repo musl \
&& emaint sync --repo lisp \
&& emaint sync --repo haskell \
&& emaint sync --repo tgbugs-overlay

# manual sync in cases where there is a showstopper blocking progress
ARG SYNC_GENTOO

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
   test -z $SYNC_GENTOO || emaint sync --repo gentoo

# emergency backup
ARG BASE="https://github.com/tgbugs/musl/releases/download/icedtea-bin-3.18.0-alpine-helper-0/"
ARG TMCH=34581ad0f14b5898abfb8d0a7ad89d560270a2e5
RUN \
mkdir -p /usr/local/portage/dev-java/icedtea-bin \
&& pushd /usr/local/portage/dev-java/icedtea-bin \
&& ln -s /var/db/repos/musl/dev-java/icedtea-bin/files \
&& curl -L -O "https://raw.githubusercontent.com/tgbugs/musl/${TMCH}/dev-java/icedtea-bin/icedtea-bin-3.18.0.ebuild" \
&& curl -L -O "https://raw.githubusercontent.com/tgbugs/musl/${TMCH}/dev-java/icedtea-bin/Manifest"

FROM busybox:latest

WORKDIR /
COPY --from=builder /var/db/repos /var/db/repos
COPY --from=gentoo/portage:latest /var/db/repos/gentoo /var/db/repos/gentoo
COPY --from=builder /usr/local/portage /usr/local/portage
CMD /bin/true
VOLUME /var/db/repos

musl

profile

TODO use static-libs?

build

docker build \
--tag tgbugs/musl:profile \
--file musl/profile/Dockerfile .

file

FROM busybox:latest as builder

WORKDIR /build

# we don't put this in var/db/repos because repos is managed via tgbugs/repos:latest
ARG bp=docker-profile/base/

ADD ${bp}docker-profile                          var/db/docker-profile
ADD ${bp}docker-profile.conf                     etc/portage/repos.conf/docker-profile.conf
ADD ${bp}binrepos-multi.conf                     etc/portage/binrepos.conf/multi.conf
ADD ${bp}package.accept_keywords                 etc/portage/package.accept_keywords/profile
ADD ${bp}package.mask                            etc/portage/package.mask/profile
ADD ${bp}package.unmask                          etc/portage/package.unmask/profile
ADD ${bp}emacs.env                               etc/portage/env/app-editors/emacs
ADD ${bp}erlang.env                              etc/portage/env/dev-lang/erlang
ADD ${bp}rabbitmq.env                            etc/portage/env/net-misc/rabbitmq-server
ADD ${bp}no-distcc.env                           etc/portage/env/no-distcc
ADD ${bp}package.env                             etc/portage/package.env/profile
ADD ${bp}musl-find_library.patch                 etc/portage/patches/dev-lang/python:2.7/musl-find_library.patch
ADD ${bp}musl-include-sys-time.patch             etc/portage/patches/dev-python/pypy3-exe/musl-include-sys-time.patch
ADD ${bp}musl-fix-stdio-defs.patch               etc/portage/patches/dev-python/pypy3-exe/musl-fix-stdio-defs.patch
ADD ${bp}pypy3-json-str-subclass-safety.patch    etc/portage/patches/dev-python/pypy3/json-str-subclass-safety.patch

FROM scratch

WORKDIR /
COPY --from=builder /build /

profile-x

build

docker build \
--tag tgbugs/musl:profile-x \
--file musl/profile-x/Dockerfile .

file

We do not need to include any of the files from the base profile here because they are already in musl:updated which this profile should be combined on top of.

FROM busybox:latest as builder

WORKDIR /build

ADD docker-profile/x/docker-profile var/db/docker-profile
ADD docker-profile/base/binrepos-multi.conf etc/portage/binrepos.conf/multi.conf

FROM scratch

WORKDIR /
COPY --from=builder /build /

user

docker build \
--tag tgbugs/musl:user \
--file musl/user/Dockerfile musl/user
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

Block to be nowebbed for the user creation portion of the images. Should be followed preceded? by a COPY --from that was built by layering on top of the image we build below.

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"
ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -m -k /etc/skel -u ${UID} -g ${UID} -d $(pwd)/home/${USER_NAME} ${USER_NAME}

RUN \
mkdir -p home/${USER_NAME}/.local/bin

RUN \
chown -R ${UID}:${UID} home/${USER_NAME}
FROM gentoo/stage3:amd64-musl-hardened as builder

WORKDIR /build

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -m -k /etc/skel -u ${UID} -g ${UID} -d $(pwd)/home/${USER_NAME} ${USER_NAME}

RUN \
mkdir -p home/${USER_NAME}/.local/bin

RUN \
chown -R ${UID}:${UID} home/${USER_NAME}

FROM scratch

WORKDIR /
COPY --from=builder /build /

portage-maven

Hack to make it possible to install from maven using portage.

build

docker build \
--tag tgbugs/musl:portage-maven \
--file musl/portage-maven/Dockerfile musl/portage-maven

file

The UID for portage is static so it is ok to hard code it 1.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository>/var/tmp/portage/.m2/repository</localRepository>
</settings>
# mkdir -p var/lib/portage/home/.m2 \
chown -R 250:250 var/lib/portage \
&& mkdir -p var/tmp/portage/.m2/repository \
&& chown -R 250:250 var/tmp/portage
FROM busybox:latest as builder

WORKDIR /build

ADD settings.xml var/lib/portage/home/.m2/settings.xml

RUN \
# mkdir -p var/lib/portage/home/.m2 \
chown -R 250:250 var/lib/portage \
&& mkdir -p var/tmp/portage/.m2/repository \
&& chown -R 250:250 var/tmp/portage

FROM scratch

WORKDIR /
COPY --from=builder /build /

eselect-repo

This is where everything starts. The profile has to be set here etc.

run

docker run \
--volumes-from local-portage-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-it tgbugs/musl:eselect-repo
docker run \
--volumes-from local-repos-snap \
-it tgbugs/musl:eselect-repo

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:eselect-repo \
--file musl/eselect-repo/Dockerfile musl/eselect-repo

file

FROM gentoo/stage3:amd64-musl-hardened

ARG ARCHIVE

COPY --from=tgbugs/musl:profile / /

RUN \
# FIXME tgbugs-overlay symlinks
ln -s /var/db/repos/gentoo /usr/portage

RUN \
eselect news read all \
&& eselect news purge

# XXX these are retained to avoid crossdev and other issues where
# portage needs these to be folders and are expected to error if
# the profile in question creates a ./profile file in these folders
RUN \
   mkdir /etc/portage/package.accept_keywords > /dev/null 2>&1 \
;  mkdir /etc/portage/package.env             > /dev/null 2>&1 \
;  mkdir /etc/portage/package.mask            > /dev/null 2>&1 \
;  mkdir /etc/portage/package.unmask          > /dev/null 2>&1 \
;  mkdir /etc/portage/package.use             > /dev/null 2>&1 \
;  mkdir /etc/portage/repos.conf              > /dev/null 2>&1 \
|| true

RUN \
eselect profile set docker-profile:tgbugs/musl

# FIXME MAKEOPTS_LOCAL
RUN \
echo "MAKEOPTS=\"-j$(nproc)\"" >> /etc/portage/make.conf
# XXX setting PORTAGE_BINHOSTS has to come later? maybe as an envar?

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge --info 2>&1 | { grep Invalid\ atom && exit 1; exit 0; }

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge -j4 -q \
   --getbinpkg \
   dev-vcs/git \
   app-eselect/eselect-repository \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
eselect repository add tgbugs-overlay git https://github.com/tgbugs/tgbugs-overlay.git \
&& eselect repository enable lisp \
&& eselect repository enable haskell

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
eselect repository enable musl
ARG ARCHIVE
RUN \
# FIXME tgbugs-overlay symlinks
ln -s /var/db/repos/gentoo /usr/portage

RUN \
eselect news read all \
&& eselect news purge

# XXX these are retained to avoid crossdev and other issues where
# portage needs these to be folders and are expected to error if
# the profile in question creates a ./profile file in these folders
RUN \
   mkdir /etc/portage/package.accept_keywords > /dev/null 2>&1 \
;  mkdir /etc/portage/package.env             > /dev/null 2>&1 \
;  mkdir /etc/portage/package.mask            > /dev/null 2>&1 \
;  mkdir /etc/portage/package.unmask          > /dev/null 2>&1 \
;  mkdir /etc/portage/package.use             > /dev/null 2>&1 \
;  mkdir /etc/portage/repos.conf              > /dev/null 2>&1 \
|| true
# FIXME MAKEOPTS_LOCAL
RUN \
echo "MAKEOPTS=\"-j$(nproc)\"" >> /etc/portage/make.conf
# XXX setting PORTAGE_BINHOSTS has to come later? maybe as an envar?

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge --info 2>&1 | { grep Invalid\ atom && exit 1; exit 0; }

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge -j4 -q \
   --getbinpkg \
   dev-vcs/git \
   app-eselect/eselect-repository \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
eselect repository add tgbugs-overlay git https://github.com/tgbugs/tgbugs-overlay.git \
&& eselect repository enable lisp \
&& eselect repository enable haskell

updated

file

Produce an up-to-date base image for amd64-hardened-musl from the latest stage3 image including the musl overlay as noted on the wiki.

At the moment the docker images are generated far more frequently than the underlying stage3 tarballs are updated, so there are two docker files, one for building the first time and another for running routine emerge updates until a new stage3 is released.

Alternately, one way to avoid rebuilds is to build packages and store them across rebuilds. This will take more work, but ultimately might be a bit more reproducible since we would avoid the issues with having an image building FROM a prior version of itself.

FROM tgbugs/musl:eselect-repo

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -q -uDN @system @world \
   --getbinpkg \
   --keep-going \
   --exclude sys-process/procps \
|| echo $? > /emerge-fail \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

# fail if emerge fails but for buildkit ensure that we do it in such a
# way that we can truncate further steps and create a debug image
RUN \
test ! -e /emerge-fail

RUN \
eselect gcc set $(eselect gcc list | tail -n 1 | awk '{ print $2 }')

build

docker build \
--tag tgbugs/musl:updated \
--network host \
--add-host local.binhost:127.0.0.1 \
--file musl/updated/Dockerfile musl/updated

rebuild

docker build \
--tag tgbugs/musl:updated-remerge \
--file musl/updated/remerge.Dockerfile musl/updated

# check that everything works as expected (and that there were changes at all)
docker run -it tgbugs/musl:updated-remerge

# rename the image
docker image tag tgbugs/musl:updated-remerge tgbugs/musl:updated

run

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
-it tgbugs/musl:updated

updated-user

An example of how to compose user images to minimize size.

run

docker run -it tgbugs/musl:updated-user

build

docker build \
--tag tgbugs/musl:updated-user \
--build-arg UID=${UID} \
--file musl/updated-user/Dockerfile musl/updated-user

file

FROM tgbugs/musl:updated

# change this line to copy from whatever user image you need
COPY --from=tgbugs/musl:user / /

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

pypy3

run

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
-it tgbugs/musl:pypy3

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:pypy3 \
--file musl/pypy3/Dockerfile musl/pypy3

file

ARG USE_PYTHON_TARGETS  # use if there are issues with mismatched python targets
# can't use PYTHON_TARGETS directly because ARG PYTHON_TARGETS is the same
# as export PYTHON_TARGETS= which means that portageq results will be affected

# we defer changing python targets until after eselect-repo to avoid
# issues bootstrapping pypy3
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
USE_PYTHON_TARGETS=${USE_PYTHON_TARGETS:-"$(portageq envvar PYTHON_TARGETS) pypy3"} \
&& [[ -z ${USE_PYTHON_TARGETS} ]] || \
   echo "*/* PYTHON_TARGETS: -* ${USE_PYTHON_TARGETS}" >> /etc/portage/package.use/00-base
FROM tgbugs/musl:updated
# FIXME python targets to include pypy3 needs to be in its own derived environment
# starting from package builder or something like that
ARG USE_PYTHON_TARGETS  # use if there are issues with mismatched python targets
# can't use PYTHON_TARGETS directly because ARG PYTHON_TARGETS is the same
# as export PYTHON_TARGETS= which means that portageq results will be affected

# we defer changing python targets until after eselect-repo to avoid
# issues bootstrapping pypy3
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
USE_PYTHON_TARGETS=${USE_PYTHON_TARGETS:-"$(portageq envvar PYTHON_TARGETS) pypy3"} \
&& [[ -z ${USE_PYTHON_TARGETS} ]] || \
   echo "*/* PYTHON_TARGETS: -* ${USE_PYTHON_TARGETS}" >> /etc/portage/package.use/00-base

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -q -uDN @system @world eselect-python \
   --getbinpkg \
   --keep-going \
   --exclude sys-process/procps \
|| echo $? > /emerge-fail \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

# fail if emerge fails but for buildkit ensure that we do it in such a
# way that we can truncate further steps and create a debug image
RUN \
test ! -e /emerge-fail

patches

If you load up builder-debug you can emerge pypy3 by adding patches manually, the right thing to do is to update the musl overlay build, but for now, if you can manage to manually build in the builder you will wind up with a binpkg that can be reused.

A number of relevant issues

  • cpython 2.7 patch

    Sourced from https://git.alpinelinux.org/aports/plain/main/python3/musl-find_library.patch If in builder-debug rebuild the python:2.7 binpkg emerge -g n -k n python:2.7.

    diff -ru Python-2.7.12.orig/Lib/ctypes/util.py Python-2.7.12/Lib/ctypes/util.py
    --- Python-2.7.12.orig/Lib/ctypes/util.py       2016-06-26 00:49:30.000000000 +0300
    +++ Python-2.7.12/Lib/ctypes/util.py    2016-11-03 16:05:46.954665040 +0200
    @@ -204,6 +204,41 @@
             def find_library(name, is64 = False):
                 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
    
    +    elif True:
    +
    +        # Patched for Alpine Linux / musl - search manually system paths
    +        def _is_elf(filepath):
    +            try:
    +                with open(filepath, 'rb') as fh:
    +                    return fh.read(4) == b'\x7fELF'
    +            except:
    +                return False
    +
    +        def find_library(name):
    +            from glob import glob
    +            # absolute name?
    +            if os.path.isabs(name):
    +                return name
    +            # special case for libm, libcrypt and libpthread and musl
    +            if name in ['m', 'crypt', 'pthread']:
    +                name = 'c'
    +            elif name in ['libm.so', 'libcrypt.so', 'libpthread.so']:
    +                name = 'libc.so'
    +            # search in standard locations (musl order)
    +            paths = ['/lib', '/usr/local/lib', '/usr/lib']
    +            if 'LD_LIBRARY_PATH' in os.environ:
    +                paths = os.environ['LD_LIBRARY_PATH'].split(':') + paths
    +            for d in paths:
    +                f = os.path.join(d, name)
    +                if _is_elf(f):
    +                    return os.path.basename(f)
    +
    +                prefix = os.path.join(d, 'lib'+name)
    +                for suffix in ['.so', '.so.*']:
    +                    for f in glob('{0}{1}'.format(prefix, suffix)):
    +                        if _is_elf(f):
    +                            return os.path.basename(f)
    +
         else:
    
             def _findSoname_ldconfig(name):
    
  • pypy3-exe sys time patch

    The patch is a version of the below patch that will apply correctly to later versions of pypy3. https://raw.githubusercontent.com/gentoo/musl/master/dev-python/pypy3-exe/files/pypy3-exe-7.3.0-musl-compat-include-sys-time.patch

    diff -r 9ef55f6fc369 pypy/module/cpyext/include/pytime.h
    --- a/pypy/module/cpyext/include/pytime.h
    +++ b/pypy/module/cpyext/include/pytime.h
    @@ -2,6 +2,10 @@
     #ifndef Py_PYTIME_H
     #define Py_PYTIME_H
    
    +#ifndef MS_WINDOWS
    +#include <sys/time.h>
    +#endif
    +
     #include <pyconfig.h> /* include for defines */
     #include "object.h"
    
    
  • pypy3-exe stdio patch

    The patch is a version of the below patch that will apply correctly to later versions of pypy3. https://raw.githubusercontent.com/gentoo/musl/master/dev-python/pypy3-exe/files/pypy3-exe-7.3.0-musl-compat-fix-stdio-defs.patch

    --- a/rpython/rlib/rfile.py
    +++ b/rpython/rlib/rfile.py
    @@ -123,11 +123,11 @@
     c_ferror = llexternal('ferror', [FILEP], rffi.INT)
     c_clearerr = llexternal('clearerr', [FILEP], lltype.Void)
    
    -c_stdin = rffi.CExternVariable(FILEP, 'stdin', eci, c_type='FILE*',
    +c_stdin = rffi.CExternVariable(FILEP, 'stdin', eci, c_type='FILE* const',
                                    getter_only=True, declare_as_extern=False)
    -c_stdout = rffi.CExternVariable(FILEP, 'stdout', eci, c_type='FILE*',
    +c_stdout = rffi.CExternVariable(FILEP, 'stdout', eci, c_type='FILE* const',
                                     getter_only=True, declare_as_extern=False)
    -c_stderr = rffi.CExternVariable(FILEP, 'stderr', eci, c_type='FILE*',
    +c_stderr = rffi.CExternVariable(FILEP, 'stderr', eci, c_type='FILE* const',
                                     getter_only=True, declare_as_extern=False)
    
    
    
  • pypy3 json string patch

    Not all instance of string have __radd__ methods that make uncasted string concatenation safe. This results in divergent behavior compared to the cypthon json implementation.

    diff -r 05fbe3aa5b08 lib-python/3/json/encoder.py
    --- a/lib-python/3/json/encoder.py      Tue Mar 29 08:15:20 2022 +0300
    +++ b/lib-python/3/json/encoder.py      Fri Apr 29 15:19:41 2022 -0700
    @@ -371,8 +371,10 @@
                     first = False
                 else:
                     buf = separator
    -            if isinstance(value, str):
    +            if type(value) == str:
                     yield buf + '"' + self.__encoder(value) + '"'
    +            elif isinstance(value, str):
    +                yield buf + '"' + str(self.__encoder(value)) + '"'
                 elif value is None:
                     yield buf + 'null'
                 elif value is True:
    @@ -448,8 +450,10 @@
                     yield item_separator
                 yield '"' + self.__encoder(key) + '"'
                 yield self.key_separator
    -            if isinstance(value, str):
    +            if type(value) == str:
                     yield '"' + self.__encoder(value) + '"'
    +            elif isinstance(value, str):
    +                yield '"' + str(self.__encoder(value)) + '"'
                 elif value is None:
                     yield 'null'
                 elif value is True:
    

xorg

run

# -v ~/files/binpkgs/musl:/var/cache/binpkgs \
docker run \
--volumes-from local-repos-snap \
-v /mnt/str/portage/distfiles:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
-it tgbugs/musl:xorg

debug

docker run \
--net host \
--add-host local.binhost:127.0.0.1 \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
--rm \
-it \
tgbugs/musl:xorg

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:xorg \
--file musl/xorg/Dockerfile musl/xorg

file

The really good news here is that portage ignores packages that were built with mismatched use flags, so at the end of the day what we will wind up with is a case where only packages with mismatched flags will be built and deposited into musl-x. The less good news is that this is not fully implemented yet as noted in https://wiki.gentoo.org/wiki/Binary_package_guide#Pulling_packages_from_a_binary_package_host.

ARG PROFILE_IMAGE=tgbugs/musl:profile-x
ARG START_IMAGE=tgbugs/musl:pypy3

FROM ${PROFILE_IMAGE} as profile_image

FROM ${START_IMAGE}

COPY --from=profile_image / /

ARG PROFILE=docker-profile:tgbugs/musl/x

RUN \
eselect profile set $PROFILE

# FIXME I think we have to update binhosts here

# FIXME this rebuild is bad because it results in duplication of
# rebuilt packages between layers, probably need updated-x
# XXX install freetype without harfbuzz first to avoid the circular dependency (sigh)
# also have to install harfbuzz -freetype as well https://bugs.gentoo.org/830966#c5
# XXX NOTE when harfbuzz and freetype are installed from binpkgs sometimes fontconfig
# will scream about missing libs, this is because the good harfbuzz is installed after
# fontconfig, confusing and scary, but apparently not fatal
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -1q \
   --getbinpkgonly \
   media-libs/freetype \
   media-libs/harfbuzz \
# FIXME these do not get repackaged correctly
|| USE="-harfbuzz -truetype" emerge -j4 -1q \
   --getbinpkg \
   media-libs/freetype \
   media-libs/harfbuzz \
# remind me again why were we using -j1 here? old gcc issues?
&& emerge -j4 -q -uDN @world \
   --getbinpkg \
   --exclude sys-process/procps \
   --keep-going \
|| echo $? > /emerge-fail \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN \
test ! -e /emerge-fail

RUN \
eselect fontconfig disable 10-hinting-slight.conf \
&& eselect fontconfig enable \
   10-no-sub-pixel.conf \
   57-dejavu-sans.conf \
   57-dejavu-sans-mono.conf

The issues with freetype hinting are partially dealt with in the profile because so many packages pull in freetype, we have to deal with the issue globally. We deal with some lingering issues here.

Only enabling dejavu sans and disabling any and all hinting matters. There isn't a way to disable antialiasing using the gentoo fontconfig and even if you do the disabled hinting engine has different and ugly behavior compared to -cleartype-hinting so not sure what is going on for even further insanity if you enable 10-hinting-none.conf OR 10-unhinted.conf YOU WILL GET HINTING !?!?!??! WAT!? or at least maybe AA is enabled which does not maybe ANY sense. Probably there is some logic which is that in order to disable some feature there is some default that is enabled so there winds up being a difference between there being no reference to a feature and a reference to it to explicitly disable it. Sigh.

package-builder

populate 0

Yes it is kind of annoying to fully split the packages here when many of them don't actually change, but I don't have an easy way to detect when it is safe to symlink a nox build into the X build, though I think we can create a processes that would check the packages and to see whether they have identical metadata and then remove one and symlink the other ….

A brief note on various bindist warnings that may appear during this step.

For openssh and openssl, the issue is related to various patents on ECC and RC5. As far as I can tell from https://en.wikipedia.org/wiki/ECC_patents and the reference in https://en.wikipedia.org/wiki/RC5, these patents have all expired, so redistribution of packages compiled with -bindist is not an issue.

For freetype it seems that most of the patents https://freetype.org/patents.html have expired as well. The latest ebuild in the tree has removed bindist entirely.

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/musl:xorg \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
  • quickpkg dedupe

    This more or less works to avoid duplicate packages in a binhost multi instance setup.

    import portage
    from portage.versions import _pkg_str
    
    def atoms_to_package():
        eroot = portage.settings['EROOT']
        trees = portage.db[eroot]
        bintree = trees['bintree']
        vartree = trees['vartree']
        vardb = vartree.dbapi
    
        installed = vartree.dbapi.cpv_all()
        packaged, not_packaged, misses = [], [], {}
        for i in installed:
            bt, bi, use = vardb.aux_get(i, ['BUILD_TIME', 'BUILD_ID', 'USE'])
            bt = int(bt) if bt else -1
            bi = int(bi) if bi else -1
            # yes build id has issues for some reason that I don't entirely understand
            matches = [a for a in bintree.dbapi.match(i) if
                       (a.build_time == bt and
                        #a.build_id == bi and
                        a._metadata['USE'] == use)]
            if matches:
                packaged.append(i)
            else:
                misses[i] = [a for a in bintree.dbapi.match(i) if not
                             (a.build_time == bt and
                              #a.build_id == bi and
                              a._metadata['USE'] == use)]
                not_packaged.append(i)
                #[[l.build_id for l in [k] + v] for k, v in misses.items()]
                #[[l.build_time for l in [k] + v] for k, v in misses.items()]
                #[[l._metadata['USE'] if hasattr(l, '_metadata') else None
                  #for l in [k] + v] for k, v in misses.items()]
    
        return sorted([f'={a}' for a in not_packaged])
    
    if __name__ == '__main__':
        atp = atoms_to_package()
        if atp:
            print(*atoms_to_package())
        else:
            print('-h')  # keep quickpkg happy since it doesn't like no args
    

run

function build_package () {
echo docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
--rm \
tgbugs/musl:package-builder \
$@
}
build_package sh -c "USE=-harfbuzz emerge -1q freetype"
# and here we see why I keep harfbuzz out of the nox profile
build_package sh -c "emerge -1q freetype"

I suggest adding all the _path_ variables below (and the repo name) to your shell rc file if you use any of the docker run commands during development so that you can do so in a new shell. These values are usually stable per system.

export \
_path_binpkgs_root=${_path_root_binpkgs:-~/files/binpkgs}
_binpkgs_repo_name=${_binpkgs_repo_name:-multi}
_path_binpkgs=${_path_binpkgs:-${_path_binpkgs_root}/${_binpkgs_repo_name}}
_path_distfiles=${_path_distfiles:-/mnt/str/portage/distfiles}
_path_distcc_hosts=${_path_distcc_hosts:-/etc/distcc/hosts.docker}
_path_ssh=${_path_ssh:-/var/lib/portage/home/.ssh}

export \
_tm_pb=${_tm_pb:-tgbugs/musl:package-builder}
_tm_s_pb=${_tm_s_pb:-tgbugs/musl:static-package-builder}

_tm_pbs=${_tm_pbs:-${_tm_pb}-snap}
_tm_s_pbs=${_tm_s_pbs:-${_tm_s_pb}-snap}

export \
_tg_pb=${_tg_pb:-tgbugs/gnu:package-builder}

_tg_pbs=${_tg_pbs:-${_tg_pb}-snap}

function builder-resnap () {
docker run ${_tm_pb}
docker commit $(docker ps -lqf ancestor=${_tm_pb}) ${_tm_pbs}
}
# FIXME SIGH SIGH SIGH why is this easier than doing the right thing
function static-builder-resnap () {
docker run ${_tm_s_pb}
docker commit $(docker ps -lqf ancestor=${_tm_s_pb}) ${_tm_s_pbs}
}
function gnu-builder-resnap () {
docker run ${_tg_pb}
docker commit $(docker ps -lqf ancestor=${_tg_pb}) ${_tg_pbs}
}
function container-check () {
docker container inspect local-repos-snap > /dev/null || \
docker create -v /var/db/repos --name local-repos-snap tgbugs/repos:latest /bin/true

# FIXME need to check that the cross image exists sigh make
docker container inspect cross-sbcl > /dev/null || \
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true
}
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
function builder-bootstrap () {
container-check

docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
done

}

# FIXME SIGH copy paste
function gnu-builder-bootstrap () {
container-check

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
emerge  --color=y --with-bdeps=y -j4 -q --keep-going --getbinpkg \
sys-devel/distcc \
sys-devel/crossdev

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}

for target in {x86_64-pc-linux-gnu,x86_64-pc-linux-musl,x86_64-gentoo-linux-musl}; do
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tg_pbs} \
crossdev --stage4 --stable --portage --getbinpkg --target ${target}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
done

}
function test_distcc () {
local test_host
for test_host in $(distcc --show-hosts); do
echo ${test_host}
DISTCC_HOSTS=${test_host} distcc x86_64-gentoo-linux-musl-gcc -c test.c -o test.o -v
echo
done
}
#include <stdio.h>
int main(void)
{
        printf("Hello world\n");
        return 0;
}
function builder-world () {
container-check
cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN
local OUT=$?

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
return $OUT
}

# FIXME SIGH code dupe
function static-builder-world () {
container-check
cat ./musl/static-package-builder/world | xargs \
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going -uDN

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
function builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-run () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-smart-live-rebuild () {
container-check
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}

function static-builder-smart-live-rebuild () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
smart-live-rebuild -- --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}

function builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
function cross-aarch64-gnu-builder-arb () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
--env USE='-*' \
--env ACCEPT_KEYWORDS='**' \
${_tm_pbs} \
aarch64-unknown-linux-gnu-emerge --color=y --with-bdeps=y -j4 -q --keep-going \
--usepkg=n --nodeps --buildpkgonly \
${@}

}

There are some packages such as dev-lang/go and some cross compiles that require elevated privs in order to build otherwise they try to call process_vm_readv then die.

See https://github.com/gentoo/gentoo-docker-images/issues/98 and https://github.com/moby/moby/issues/1916.

function builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# FIXME code dupe
function static-builder-arb-priv () {
container-check
# rebuild packages modified without revbump e.g. due to changing /etc/portage/patches
docker run \
--security-opt seccomp=unconfined \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
${_tm_s_pbs} \
emerge --color=y --with-bdeps=y -j4 -q --keep-going --usepkg=n \
${@}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
builder-arb-priv -1 -uN --getbinpkg \
dev-lang/go \
dev-go/go-md2man \
app-containers/runc \
app-containers/containerd \
app-containers/docker-cli
function builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_pbs}) ${_tm_pbs}
}
# XXX FIXME code dupe
function static-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from cross-sbcl \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tm_s_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tm_s_pbs}) ${_tm_s_pbs}
}
# SIGH
function gnu-builder-debug () {
container-check
docker run \
--privileged \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v ${_path_ssh}:/var/lib/portage/home/.ssh \
-v ${_path_distcc_hosts}:/etc/distcc/hosts \
--env FEATURES="$(portageq envvar FEATURES | grep -o distcc)" \
--env MAKEOPTS="$(portageq envvar MAKEOPTS)" \
-it ${_tg_pbs}

docker commit --change='CMD ["/bin/bash"]' $(docker ps -lqf ancestor=${_tg_pbs}) ${_tg_pbs}
}
# --nodeps # potentially useful

@live-rebuild

app-misc/screen
dev-lisp/sbcl


# to debug issues
docker run \
--volumes-from local-repos-snap \
--rm \
-it \
tgbugs/musl:package-builder-snap

# too many issues, just merge and get on with it
# the lack of separation between build time dependencies and runtime is quite annoying
# that or the dependency trees are even worse than I thought
# emerge --color=y -j4 -q --keep-going --onlydeps
# emerge --color=y -j4 -q --keep-going --buildpkgonly

build

docker build \
--tag tgbugs/musl:package-builder \
--file musl/package-builder/Dockerfile musl/package-builder

file

COPY --from=tgbugs/musl:portage-maven / /

ADD repo_name /var/db/crossdev/profiles/repo_name
ADD layout.conf /var/db/crossdev/metadata/layout.conf
ADD crossdev.conf /etc/portage/repos.conf/crossdev.conf
ADD sbcl.env /etc/portage/env/dev-lisp/sbcl

RUN \
echo 'FEATURES="${FEATURES} buildpkg"' >> /etc/portage/make.conf \
&& echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkg"' >> /etc/portage/make.conf

We don't add distcc until we get to the builder here to avoid issues during bootstrap. Usually we don't have too many packages to rebuild to get to a sane world state.

FROM tgbugs/musl:xorg

COPY --from=tgbugs/musl:portage-maven / /

ADD repo_name /var/db/crossdev/profiles/repo_name
ADD layout.conf /var/db/crossdev/metadata/layout.conf
ADD crossdev.conf /etc/portage/repos.conf/crossdev.conf
ADD sbcl.env /etc/portage/env/dev-lisp/sbcl

RUN \
echo 'FEATURES="${FEATURES} buildpkg"' >> /etc/portage/make.conf \
&& echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkg"' >> /etc/portage/make.conf

ghc bootstrap

pushd /tmp
curl -L -o ghc-9.0.2-r1.tar.bz http://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/ghc-9.0.2-r1.apk
pushd /
tar xvzf ghc-9.0.2-r1.tar.bz  # yes this is crazy, throw the container away when when are done

and then we have to modify all the top level entry point scripts to adjust their install location give up and for the bootstrap just extract the alpine build straight into the existing file system because we can't set the prefix

but even here the Winline errors are showing up during the build maybe they aren't fatal in non-crossbuild settings?

haha! this works! we are good to go, lots of file collisions of course, but at least we have the binpkg now this means we aren't going to try to get ghc-cross working for the time being because kicking off from alpline seems to be working well enough for one auxillary package

  • old

    https://github.com/redneb/ghc-alt-libc/releases/download/ghc-9.0.2-musl/ghc-9.0.2-x86_64-unknown-linux-musl.tar.xz Have to roll with USE=ghcbootstrap but mercifully this makes it extremely easy to just plob the binaries on the system and get to work. also no distcc TODO follow sbcl pattern here and stick the stuff we need in /ghc probably and provide as a separate image?

    pushd /tmp/
    PV=9.0.2
    curl -OL https://github.com/redneb/ghc-alt-libc/releases/download/ghc-${PV}-musl/ghc-${PV}-x86_64-unknown-linux-musl.tar.xz
    tar xvJf ghc-${PV}-x86_64-unknown-linux-musl.tar.xz
    pushd ghc-${PV}
    ./configure --prefix=/ghc
    make install
    popd
    popd
    
    pre_pkg_setup() { export PATH="${PATH}:/ghc/bin"; }
    

    using this on musl fails because ghc-cabal is segfaulting for some reason https://github.com/NixOS/nixpkgs/issues/118731, the solution is to use a version of ghc that can target musl 1.2.3, i.e. the one from alpine

sbcl bootstrap

The gentoo ebuilds for sbcl retrieve an existing binary for bootstrapping. Due to the fact that the current EAPI (?) is not libc aware for precompiled binaries we would have to create and maintain a binary for the musl overlay. Modifying src_unpack is a more expedient solution.

src_unpack() {
        unpack ${A}
        [ -d /sbcl ] && {
                einfo "Using /sbcl for bootstrap"
                cp -r /sbcl sbcl-binary || die;
                cp -a ${S}/run-sbcl.sh sbcl-binary/ || die;
        } || {
        command -v sbcl && {
                einfo "Using local sbcl found at $(command -v sbcl) for bootstrap"
                local bin_core_home;
                IFS=',' read -r -a bin_core_home <<< $(sbcl --noinform --no-sysinit --no-userinit --eval \
                '(progn (format t "~a,~a,~a" sb-ext:*runtime-pathname* sb-ext:*core-pathname* (sb-int:sbcl-homedir-pathname)))' --quit) || die;
                mkdir -p sbcl-binary/src/runtime || die;
                mkdir -p sbcl-binary/output || die;
                mkdir -p sbcl-binary/obj/sbcl-home || die;
                cp -a ${bin_core_home[0]} sbcl-binary/src/runtime/ || die;
                cp -a ${bin_core_home[1]} sbcl-binary/output/ || die;
                cp -a ${bin_core_home[2]}/contrib sbcl-binary/obj/sbcl-home/contrib || die;
                cp -a ${S}/run-sbcl.sh sbcl-binary/ || die;
        } } ||
        mv sbcl-*-* sbcl-binary || die
        cd "${S}"
}

crossdev

In order to fix

* Missing digest for '/var/db/docker-profile/cross-x86_64-pc-linux-gnu/binutils/binutils-2.34-r2.ebuild'
* Missing digest for '/var/db/docker-profile/cross-x86_64-pc-linux-gnu/binutils/binutils-2.33.1-r1.ebuild'

This works around the fact that musl uses thin manifests. See https://wiki.gentoo.org/wiki/Custom_ebuild_repository#Crossdev.

crossdev
masters = gentoo
thin-manifests = true
[crossdev]
location = /var/db/crossdev
priority = 10
masters = gentoo
auto-sync = no

But even with that fix there is an issue with linking the core runtime libs.

/usr/libexec/gcc/x86_64-pc-linux-gnu/ld: cannot find crti.o: No such file or directory

For reasons I do not fully understand we have to use the gentoo repo as the source for the gcc ebuild, the two are virtually identical, so maybe the toolchain eclass is silently different? Unknown.

crossdev --stage4 --stable --target x86_64-pc-linux-gnu --ov-gcc /var/db/repos/gentoo

At this point we can attempt to emerge sbcl, but src_config will fail.

x86_64-pc-linux-gnu-emerge -q -j4 sbcl

As a result, I reworked the profile so that it can support whatever libc we want and do the cross build from gnu to musl since there are distributed sbcl-binaries for gnu but not for musl. The way that multiple libcs are implemented in gentoo right now seems to add significant maintenance overhead due to ebuild duplication.

world

nil
app-editors/vim
app-portage/eix
sys-devel/gdb::musl
app-emacs/vterm
app-editors/emacs
app-emacs/vterm
app-editors/emacs
dev-scheme/racket
dev-libs/libconfig
sys-libs/db
dev-lang/tk
media-gfx/imagemagick
app-text/poppler
dev-lang/python:3.7
dev-lang/python:3.8
dev-lang/python:3.9
dev-lang/python:3.10
dev-lang/python:3.11
dev-python/pypy3
dev-python/pip
dev-python/pipenv
dev-scheme/chicken
dev-scheme/guile
dev-scheme/gambit
app-portage/smart-live-rebuild
app-editors/gvim
dev-lisp/sbcl
app-emacs/vterm
app-editors/emacs
dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-db/blazegraph-bin
dev-java/scigraph-bin
media-gfx/feh
media-gfx/graphviz
dev-python/ipykernel
dev-python/pip
dev-haskell/dot2graphml
app-emacs/vterm
app-editors/emacs
dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-db/blazegraph-bin
dev-java/scigraph-bin
media-gfx/feh
media-gfx/graphviz
dev-python/ipykernel
dev-python/pip
dev-haskell/dot2graphml
app-misc/screen
dev-scheme/racket
net-libs/nodejs
app-arch/zip
app-misc/yq
dev-java/robot-bin
dev-node/apinat-converter
dev-python/nifstd-tools
dev-python/sparcur
app-editors/emacs
app-containers/docker
app-containers/docker-cli
dev-python/interlex
dev-libs/redland
dev-db/redis
net-misc/rabbitmq-server
dev-python/pip
dev-python/sparcur
www-servers/uwsgi
app-portage/smart-live-rebuild
app-editors/gvim
x11-base/xorg-server
x11-libs/gtk+
app-portage/smart-live-rebuild
app-editors/gvim
media-libs/freetype
media-libs/fontconfig
media-fonts/dejavu

package-builder-nox

populate 0

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/musl:updated \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/musl:pypy3 \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'

run

cat ./musl/package-builder/nox.world | xargs \
docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
--rm \
tgbugs/musl:package-builder-nox \
emerge --color=y -j4 -q --keep-going

world

If there is a new package that one of your images needs add it here. Yes, there are going to be issues with keywording that are likely going to require updates to the profile followed by a rebuild here. I can't quite remember whether binpkgs check use flags.

app-editors/vim
app-portage/eix
sys-devel/gdb::musl
app-emacs/vterm
app-editors/emacs
app-emacs/vterm
app-editors/emacs
dev-scheme/racket
dev-libs/libconfig
sys-libs/db
dev-lang/tk
media-gfx/imagemagick
app-text/poppler
dev-lang/python:3.7
dev-lang/python:3.8
dev-lang/python:3.9
dev-lang/python:3.10
dev-lang/python:3.11
dev-python/pypy3
dev-python/pip
dev-python/pipenv
dev-scheme/chicken
dev-scheme/guile
dev-scheme/gambit
app-portage/smart-live-rebuild
app-editors/gvim
dev-lisp/sbcl
dev-lisp/sbcl
dev-lisp/clozurecl
dev-lisp/clisp
dev-scheme/chicken
dev-scheme/guile
dev-scheme/gambit
app-editors/xemacs
app-xemacs/xemacs-packages-all

build

docker build \
--tag tgbugs/musl:package-builder-nox \
--file musl/package-builder/nox.Dockerfile musl/package-builder

file

FROM tgbugs/musl:pypy3

COPY --from=tgbugs/musl:portage-maven / /

ADD repo_name /var/db/crossdev/profiles/repo_name
ADD layout.conf /var/db/crossdev/metadata/layout.conf
ADD crossdev.conf /etc/portage/repos.conf/crossdev.conf
ADD sbcl.env /etc/portage/env/dev-lisp/sbcl

RUN \
echo 'FEATURES="${FEATURES} buildpkg"' >> /etc/portage/make.conf \
&& echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkg"' >> /etc/portage/make.conf

package-binhost

binpkg-only

run

debug

docker run \
--net host \
--add-host local.binhost:127.0.0.1 \
--volumes-from local-repos-snap \
-v /mnt/str/portage/distfiles:/var/cache/distfiles \
--rm \
-it tgbugs/musl:binpkg-only

build

docker build \
--tag tgbugs/musl:binpkg-only \
--file musl/binpkg-only/Dockerfile musl/binpkg-only

file

RUN \
echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkgonly --getbinpkgonly"' >> /etc/portage/make.conf \
&& echo 'FEATURES="${FEATURES} parallel-install -ebuild-locks"' >> /etc/portage/make.conf
FROM tgbugs/musl:xorg

RUN \
echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkgonly --getbinpkgonly"' >> /etc/portage/make.conf \
&& echo 'FEATURES="${FEATURES} parallel-install -ebuild-locks"' >> /etc/portage/make.conf

binpkg-only-nox

build

docker build \
--tag tgbugs/musl:binpkg-only-nox \
--file musl/binpkg-only/nox.Dockerfile musl/binpkg-only

file

FROM tgbugs/musl:pypy3

RUN \
echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkgonly --getbinpkgonly"' >> /etc/portage/make.conf \
&& echo 'FEATURES="${FEATURES} parallel-install -ebuild-locks"' >> /etc/portage/make.conf

debug

world

app-editors/vim
app-portage/eix
sys-devel/gdb::musl

docker   bootstrap

This image provides one route to bootstrap an environment that can execute this file. Other routes also exist.

This route requires the following dependencies.

  1. This source.org file.
  2. Emacs 27 or later (earlier might work but not tested)
  3. A posix shell
  4. docker version 20 or later
  5. Access to a gentoo stage 3 musl image.

It does not require git to be installed on the host so source.org could be retrieved via curl or from a backup or similar.

With a bit of wrangling the bootstrap might also be able to drop the Emacs dependency.

A second phase bootstrap is used to provide a stable starting point for the rest of the process. This second phase does use git.

run

Reminder that this gives access to the host docker system.

docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-it tgbugs/musl:docker

Version that works with existing package host folders.

docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/files/binpkgs:/binpkgs \
-it tgbugs/musl:docker

After quite a bit of exploration it seems that passing docker.sock is the sanest way to achieve what we want, though it does create a strange warping of perspective because all containers run on the host docker server. This is unfortunate because it causes the semantics to differ between running the bootstrap outside of docker or trying to run it "inside" of docker. See the dind heading above for more.

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:docker \
--file musl/docker/Dockerfile musl/docker

entrypoints

0th

pushd dockerfiles
./source.org ${@}

1st

git clone https://github.com/tgbugs/dockerfiles.git
pushd dockerfiles
./source.org ${@}

file

FROM tgbugs/musl:binpkg-only

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE
ADD source.org /dockerfiles/source.org
ADD entrypoint-0.sh /etc/entrypoint-0.sh
ENTRYPOINT /etc/entrypoint-0.sh
FROM tgbugs/musl:binpkg-only-nox

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE
ADD entrypoint.sh /etc/entrypoint.sh
ENTRYPOINT /etc/entrypoint.sh

world

NOTE dev-lang/go is pulled in by app-emulation/docker and must be built using ref:&builder-arb-priv to avoid process_vm_readv being blocked by the container.

app-editors/emacs
app-containers/docker
app-containers/docker-cli

testing-python

Python testing.

world

dev-lang/python:3.7
dev-lang/python:3.8
dev-lang/python:3.9
dev-lang/python:3.10
dev-lang/python:3.11
dev-python/pypy3
dev-python/pip
dev-python/pipenv

testing-emacs

Emacs testing.

world

app-editors/emacs:18
app-editors/emacs:23
app-editors/emacs:24
app-editors/emacs:25
app-editors/emacs:26
app-editors/emacs:27
app-editors/emacs:28
app-editors/emacs:29-vcs

emacs

Emacs using the athena 3d toolkit to avoid pulling in gtk.

bugs

If you quickpkg emacs and then try to install it you can encounter

mv: cannot stat '/var/tmp/portage/app-editors/emacs-27.2-r5/image/usr/share/info/emacs-27/dir.orig': No such file or directory

This is somewhat concerning since the failure is during preinst and it definitely should not be looking in /var/tmp/portage for that orig file. It seems that forcing a rebuild with builder-arb fixes the issue.

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:emacs

debug run

docker run \
--net host \
--add-host local.binhost:127.0.0.1 \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
--rm \
-it \
tgbugs/musl:emacs

If you see the following error you somehow forgot/are missing the musl overlay.

Error loading shared library libbsd.so.0: No such file or directory (needed by /usr/lib/libICE.so.6)
Error loading shared library libbsd.so.0: No such file or directory (needed by /usr/lib/libXdmcp.so.6)
Error relocating /usr/lib/libICE.so.6: arc4random_buf: symbol not found
Error relocating /usr/lib/libXdmcp.so.6: arc4random_buf: symbol not found

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:emacs \
--file musl/emacs/Dockerfile musl/emacs

file

FROM tgbugs/musl:binpkg-only

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE
FROM tgbugs/musl:binpkg-only-nox

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

app-emacs/vterm
app-editors/emacs

icedtea

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:icedtea \
--file musl/icedtea/Dockerfile musl/icedtea

file

FROM tgbugs/musl:binpkg-only

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

dev-java/icedtea-bin::musl

Backup.

dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-libs/nss
dev-java/icedtea-bin::local

legacy

The musl overlay installs icedtea-bin correctly now so this is thankfully no longer needed only needed periodically.

FROM tgbugs/musl:xorg

ARG ARCHIVE

ARG BASE="https://github.com/tgbugs/musl/releases/download/icedtea-bin-3.18.0-alpine-helper-0/"

ARG TMCH=34581ad0f14b5898abfb8d0a7ad89d560270a2e5

RUN \
eselect repository create local /usr/local/portage

# FIXME this is an evil hack that WILL expire
RUN \
mkdir -p /usr/local/portage/dev-java/icedtea-bin \
&& pushd /usr/local/portage/dev-java/icedtea-bin \
&& ln -s /var/db/repos/musl/dev-java/icedtea-bin/files \
&& curl -L -O "https://raw.githubusercontent.com/tgbugs/musl/${TMCH}/dev-java/icedtea-bin/icedtea-bin-3.18.0.ebuild" \
&& curl -L -O "https://raw.githubusercontent.com/tgbugs/musl/${TMCH}/dev-java/icedtea-bin/Manifest"

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge -j4 -q nss \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge -j4 -q dev-java/icedtea-bin::local --onlydeps \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

ARG SIGH="icedtea-bin-3.18.0-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-dbg-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-doc-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-jre-base-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-jre-lib-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-jre-x86_64-musl.tar.gz \
icedtea-bin-3.18.0-libjpeg-x86_64-musl.tar.gz"

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
pushd /var/cache/distfiles \
&& for SI in ${SIGH}; do curl -L -o "${SI}" "${BASE}${SI/-musl/}"; done \
&& popd \
&& emerge -j4 -q dev-java/icedtea-bin::local \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

protege

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:protege

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:protege \
--build-arg UID=${UID} \
--file musl/protege/Dockerfile musl/protege

Due to the fact that protege needs X11 running in order to create config files. Run the following command, change the default reasoner to ELK, make any other changes that are needed, and then quit protege. The second command will run automatically and commit the changes.

NOTE you must run the protege command manually to prevent the commit from changing the default behavior of the container from changing its entry point to run protege.

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:protege && \
docker commit $(docker ps -lq) tgbugs/musl:protege

world

dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-python/pip

file

We install pip during this step because any builds that FROM tgbugs/musl:protege default to protegeuser.

FROM tgbugs/musl:icedtea as builder

ARG ARCHIVE
ARG PROTEGE_VERSION="5.5.0"

WORKDIR /build

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -m -k /etc/skel -u ${UID} -g ${UID} -d $(pwd)/home/${USER_NAME} ${USER_NAME}

RUN \
mkdir -p home/${USER_NAME}/.local/bin

RUN \
chown -R ${UID}:${UID} home/${USER_NAME}

USER ${USER_NAME}

ARG HOME=/build/home/${USER_NAME}

WORKDIR $HOME

# phase two protege and reasoners
ARG URL_PROTEGE="https://github.com/protegeproject/protege-distribution/releases/download/v5.5.0/Protege-5.5.0-linux.tar.gz"
ARG URL_ELK="https://github.com/liveontologies/elk-reasoner/releases/download/v0.4.3/elk-distribution-0.4.3-protege-plugin.zip"
ARG URL_FACT="https://bitbucket.org/dtsarkov/factplusplus/downloads/uk.ac.manchester.cs.owl.factplusplus-P5.x-v1.6.5.jar"

RUN \
cd ~/ \
&& curl -L -O ${URL_PROTEGE} \
&& tar xvzf Protege-${PROTEGE_VERSION}-linux.tar.gz \
&& pushd Protege-${PROTEGE_VERSION} \
&& rm jre/ -r \
&& sed -i 's/^jre\/bin\/java/\/usr\/bin\/java/' run.sh \
&& sed -i 's/500M/12G/' run.sh \
&& sed -i 's/200M/5G/' run.sh \
&& sed -i 's/16M/160M/' run.sh \
&& pushd plugins \
&& curl -L -O ${URL_FACT} \
&& curl -L -O ${URL_ELK} \
&& unzip -p elk-distribution-0.4.3-protege-plugin.zip \
   elk-distribution-0.4.3-protege-plugin/org.semanticweb.elk.jar \
   > org.semanticweb.elk-0.4.3.jar \
&& rm elk-distribution-0.4.3-protege-plugin.zip \
&& popd; popd \
&& mkdir -p ~/.local/share ~/.local/bin \
&& mv Protege-${PROTEGE_VERSION} ~/.local/share/ \
&& pushd ~/.local/bin \
&& ln -s ../share/Protege-${PROTEGE_VERSION}/run.sh protege \
&& popd \
&& rm Protege-${PROTEGE_VERSION}-linux.tar.gz

# paths to preferences files
ARG PATH_CFU_1=_\!\&\!\!\`g\"\>\!\&@\!\[@\"\(\!%\`\!\|w\"@\!\&\)\!\[@\"\'\!%\`\!\`g\"\&\!%4\!@w\"\&\!\&:=
ARG PATH_CFU_2=_\!\'%\!c\!\"w\!\'w\!a@\"j\!\'%\!d\!\"p\!\'8\!bg\"f\!\(\!\!cg\"l\!\'\}\!~@\"y\!\'\`\!bg\"j\!\'\`\!cw==
ARG PATH_CFU_3=_\!\'8\!cg\"n\!#4\!c\!\"y\!\'8\!d\!\"l\!\'c\!~@\!u\!\'\`\!~\!\"p\!\(@\!bw\"y\!#4\!\}w\"v\!\(\)\!~@\!u\!\(\`\!c\!\"k\!\'%\!d\!\"l\!#4\!\`\!\"s\!\(\`\!~w\"p\!\'4\!\^@\"h\!\'4\!\}@\"n\!\'\`\!cg==
ARG PATH_CFU="${PATH_CFU_1}/${PATH_CFU_2}/${PATH_CFU_3}"

# set preferences so that protege starts in the right state the first time
# protege doesn't create this prefs file by default so we would have to do this regardless
# this helps because it prevents the search for plugins on first run so that goes faster
RUN \
pushd ~/ \
&& mkdir -p ".java/.userPrefs/${PATH_DRI_1}" \
&& chmod 0700 ".java/.userPrefs" \
&& mkdir -p ".java/.userPrefs/${PATH_CFU}" \
&& echo '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' > ".java/.userPrefs/${PATH_CFU}/prefs.xml" \
&& echo '<!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">' >> ".java/.userPrefs/${PATH_CFU}/prefs.xml" \
&& echo '<map MAP_XML_VERSION="1.0">' >> ".java/.userPrefs/${PATH_CFU}/prefs.xml" \
&& echo '  <entry key="CheckForUpdates" value="false"/>' >> ".java/.userPrefs/${PATH_CFU}/prefs.xml" \
&& echo '</map>' >> ".java/.userPrefs/${PATH_CFU}/prefs.xml" \
&& popd

FROM tgbugs/musl:icedtea


ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

COPY --from=builder /build /

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

Sadly this approach does not work because protege dies before the reasoner prefs file is written. Therefore we have to run the image manually and commit before release. Sigh.

# start protege to generate settings files, have to sleep becuase the
# protege sh wrapper breaks $!
RUN \
protege \
& sleep 6 \
&& kill $(ps | grep java | awk '{ printf $1 }')

# on first run protege doesn't check to see if there is already
# something in this prefs.xml file and appends to it automatically
RUN \
find ~/.java/.userPrefs -name 'prefs.xml' -exec grep -q DEFAULT_REASONER_ID {} \; \
-exec sed -i 's/org.protege.editor.owl.NoOpReasoner/org.semanticweb.elk.elk.reasoner.factory/' {} \;

# must use absolute path otherwise command form won't work
WORKDIR /home/${USER_NAME}

In order to get paths that point to the prefs.xml files that we can embed in the docker file you need the following commands.

printf '%q' $(find ~/.java/.userPrefs -name 'prefs.xml' -exec grep -q CheckForUpdates {} \; -print0)

A useful find command for debugging whether the correct reasoner has been set.

find ~/.java/.userPrefs -name 'prefs.xml' -exec grep -q DEFAULT_REASONER_ID {} \; -exec cat {} \;

NIF-Ontology

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:NIF-Ontology

build

docker build \
--tag tgbugs/musl:NIF-Ontology \
--file musl/NIF-Ontology/Dockerfile musl/NIF-Ontology

file

FROM tgbugs/musl:protege

# phase three ontology
RUN \
pushd ~/ \
;   mkdir git \
;   pushd git \
;       git clone https://github.com/SciCrunch/NIF-Ontology.git \
;       pushd NIF-Ontology \
;           pushd ttl \
;           cp catalog-v001.xml.example catalog-v001.xml \
;       popd \
;   popd

neurondm

run

# to allow the container access to the local x session you have to run the following
xhost local:docker
# use xhost -local:docker to remove

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:neurondm

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--workdir /home/protegeuser/git/NIF-Ontology/ttl \
tgbugs/musl:neurondm \
protege

build

docker build \
--tag tgbugs/musl:neurondm \
--build-arg ONTOLOGY_GITREF=neurons \
--file musl/neurondm/Dockerfile musl/neurondm

file

FROM tgbugs/musl:NIF-Ontology

ARG ONTOLOGY_GITREF=neurons

# phase three ontology
RUN \
pushd ~/git/NIF-Ontology \
;   git checkout ${ONTOLOGY_GITREF} \
;   popd

# phase four python tools
RUN \
pushd ~/ \
;   pushd git \
;       git clone https://github.com/tgbugs/pyontutils.git \
;       pushd pyontutils \
;           pip install --user -e . \
;           pushd neurondm \
;               pip install --user -e . \
;           popd \
;       popd \
;   popd

npo-1.0

run

xhost local:docker

docker pull tgbugs/musl:npo-1.0

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--workdir /home/protegeuser/git/NIF-Ontology/ttl \
tgbugs/musl:npo-1.0 \
sh -c 'protege ~/git/NIF-Ontology/ttl/npo.ttl'
  • macos notes
    brew install virtualbox  # there are some system level persmissions that you will need to set
    brew install --cask docker
    open -a Docker\ Desktop
    # You will need to go to Docker Desktop > Preferences > Resources
    # and increase the memory limit to 8 gigs
    # otherwise oom killer will end Protege while trying to load npo.ttl
    
    brew install xquartz
    open -a XQuartz
    # You will need to go to XQuartz > Preferences > Security
    # and enable Allow connections from network clients
    xhost +localhost
    export DISPLAY=:0
    # test to make sure everything still works e.g. by running xeyes
    
    docker pull tgbugs/musl:npo-1.0
    docker run \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -e DISPLAY=host.docker.internal$DISPLAY \
    --workdir /home/protegeuser/git/NIF-Ontology/ttl \
    tgbugs/musl:npo-1.0 \
    sh -c 'protege ~/git/NIF-Ontology/ttl/npo.ttl'
    

    Run the block above and once protege starts type Control R to run the reasoner. The docker image is running the Linux version of Protege so the key bindings use Control instead of Command. You can then run OWL DL queries in the tab. Note that if you are using the ELK reasoner (enabled by default in the image) then you will have to click through a number of warning dialogues, this is normal.

build

docker build \
--tag tgbugs/musl:npo-1.0 \
--build-arg ONTOLOGY_GITREF=npo-1.0 \
--file musl/neurondm/Dockerfile musl/neurondm

npo-1.0-neurondm-build

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--workdir /home/protegeuser/git/NIF-Ontology/ttl \
tgbugs/musl:npo-1.0-neurondm-build \
sh -c 'git stash && protege ~/git/NIF-Ontology/ttl/npo.ttl'

build

Build using the SciCrunch SciGraph API endpoint.

# XXX note that NUID does nothing right now
docker build \
--tag tgbugs/musl:npo-1.0-neurondm-build \
--build-arg NEURONS_BRANCH=npo-1.0 \
--build-arg NUID=${UID} \
--secret id=scigraph-api-key,src=<(echo export SCIGRAPH_API_KEY=$(python -c 'from pyontutils.config import auth; print(auth.get("scigraph-api-key"))')) \
--file musl/npo-1.0-neurondm-build/Dockerfile musl/npo-1.0-neurondm-build

Build using an alternate SciGraph API endpoint.

# XXX note that NUID does nothing right now
docker build \
--tag tgbugs/musl:npo-1.0-neurondm-build \
--build-arg NEURONS_BRANCH=npo-1.0 \
--build-arg NUID=${UID} \
--build-arg SCIGRAPH_API=$(python -c 'from pyontutils.config import auth; print(auth.get("scigraph-api"))') \
--secret id=scigraph-api-key,src=<(echo) \
--file musl/npo-1.0-neurondm-build/Dockerfile musl/npo-1.0-neurondm-build

file

FROM tgbugs/musl:npo-1.0
# phase five build
# XXX FIXME we can't run this for the demonstrator because the lack of
# npokb identifiers causes the queries to fail we probably want two
# separate images for this
ARG SCIGRAPH_API
ARG NEURONS_BRANCH
ARG NUID=11741
# FIXME waiting on https://github.com/moby/buildkit/issues/815
#RUN --mount=type=secret,id=scigraph-api-key,uid=${NUID} \
RUN --mount=type=secret,id=scigraph-api-key,uid=1000 source /run/secrets/scigraph-api-key \
; python -m neurondm.models.allen_cell_types \
; python -m neurondm.models.huang2017 \
; python -m neurondm.models.ma2015 \
; git -C ~/git/NIF-Ontology status

save

This is the image that will be archived to Zenodo for the paper. Note that the dl queries will not run as expected on this unless you first stash the changes in ~/git/NIF-Ontology.

docker save tgbugs/musl:npo-1.0-neurondm-build | gzip > /tmp/npo-1.0-neurondm-build.tar.gz

To restore from the archive run

docker load --input npo-1.0-neurondm-build.tar.gz

The sha256 checksum for npo-1.0-neurondm-build.tar.gz on Zenodo at https://doi.org/10.5281/zenodo.5033493 is 8e0bb1c684ca8a28f1abeb01ef7aa2597388b8011244f097a92bdd2a523db102.

neurondm-build

This image runs the neurondm build process.

run

build

# XXX note that NUID does nothing right now
docker build \
--tag tgbugs/musl:neurondm-build \
--build-arg NUID=${UID} \
--secret id=scigraph-api-key,src=<(echo export SCIGRAPH_API_KEY=$(python -c 'from pyontutils.config import auth; print(auth.get("scigraph-api-key"))')) \
--file musl/neurondm-build/Dockerfile musl/neurondm-build

Build using an alternate SciGraph API endpoint.

# XXX note that NUID does nothing right now
docker build \
--tag tgbugs/musl:neurondm-build \
--build-arg NUID=${UID} \
--build-arg SCIGRAPH_API=$(python -c 'from pyontutils.config import auth; print(auth.get("scigraph-api"))') \
--secret id=scigraph-api-key,src=<(echo) \
--file musl/neurondm-build/Dockerfile musl/neurondm-build

file

FROM tgbugs/musl:neurondm
# phase five build
# XXX FIXME we can't run this for the demonstrator because the lack of
# npokb identifiers causes the queries to fail we probably want two
# separate images for this
ARG SCIGRAPH_API
ARG NEURONS_BRANCH
ARG NUID=11741
# FIXME waiting on https://github.com/moby/buildkit/issues/815
#RUN --mount=type=secret,id=scigraph-api-key,uid=${NUID} \
RUN --mount=type=secret,id=scigraph-api-key,uid=1000 source /run/secrets/scigraph-api-key \
; python -m neurondm.models.allen_cell_types \
; python -m neurondm.models.huang2017 \
; python -m neurondm.models.ma2015 \
; git -C ~/git/NIF-Ontology status
# phase five build
# XXX FIXME we can't run this for the demonstrator because the lack of
# npokb identifiers causes the queries to fail we probably want two
# separate images for this
ARG SCIGRAPH_API
ARG NEURONS_BRANCH
ARG NUID=11741
# FIXME waiting on https://github.com/moby/buildkit/issues/815
#RUN --mount=type=secret,id=scigraph-api-key,uid=${NUID} \
RUN --mount=type=secret,id=scigraph-api-key,uid=1000 source /run/secrets/scigraph-api-key \
; python -m neurondm.models.allen_cell_types \
; python -m neurondm.models.huang2017 \
; python -m neurondm.models.ma2015 \
; git -C ~/git/NIF-Ontology status

interlex

run

WARNING! If you mount your postgres data directory like this make sure the host system is NOT also running postgres on top of that directory otherwise you will have a BAD TIME.

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v ~/files/docker-postgres/interlex-dev:/var/lib/postgresql \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:interlex

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:interlex \
--file musl/interlex/Dockerfile musl/interlex

file

FROM tgbugs/musl:binpkg-only


ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

dev-python/interlex
dev-libs/redland

blazegraph

run

docker run \
-v /var/lib/blazegraph:/var/lib/blazegraph \
-p 9999:9999 \
-it tgbugs/musl:blazegraph

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:blazegraph \
--file musl/blazegraph/Dockerfile musl/blazegraph

file

FROM tgbugs/musl:binpkg-only-nox

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE
ADD entrypoint.sh /etc/entrypoint.sh
ENTRYPOINT /etc/entrypoint.sh

world

dev-libs/nss
dev-java/icedtea-bin::local
dev-db/blazegraph-bin

entrypoint

rc-status
touch /run/openrc/softlevel
rc-service blazegraph start

scigraph

run

docker run \
-v /var/lib/scigraph:/var/lib/scigraph \
-p 9000:9000 \
tgbugs/musl:scigraph

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:scigraph \
--file musl/scigraph/Dockerfile musl/scigraph

file

FROM tgbugs/musl:binpkg-only

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE
ADD entrypoint.sh /etc/entrypoint.sh
ENTRYPOINT /etc/entrypoint.sh

world

dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-java/scigraph-bin

entrypoint

rc-status
touch /run/openrc/softlevel
rc-service scigraph start

kg-release

Base environment for knowledge graph distribution and interaction. Combines both server and client functionalities into a single image. In principle this could be split into multiple images, but for the sake of simplicity and reproducibility it is a single image.

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-release

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-release \
--file musl/kg-release/Dockerfile musl/kg-release

file

FROM tgbugs/musl:emacs


ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

app-emacs/vterm
app-editors/emacs
dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-db/blazegraph-bin
dev-java/scigraph-bin
media-gfx/feh
media-gfx/graphviz
dev-python/ipykernel
dev-python/pip
dev-haskell/dot2graphml

kg-release-user

run

Quick link to #create-sckan-data useful if sckan-data has not been created or was wiped in a purge.

docker run \
--volumes-from sckan-data \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-release-user

with configuration for xdg-open forwarding

docker run \
--volumes-from sckan-data \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--add-host=host.docker.internal:host-gateway \
-e FORWARD_URL_HOST=host.docker.internal \
-e FORWARD_URL_PORT=59213 \
-it tgbugs/musl:kg-release-user

debug with network in bridge mode

docker run \
--volumes-from local-repos-snap \
--add-host local.binhost:127.0.0.1 \
--volumes-from sckan-data \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--add-host=host.docker.internal:host-gateway \
-e FORWARD_URL_HOST=host.docker.internal \
-e FORWARD_URL_PORT=59213 \
-it tgbugs/musl:kg-release-user

debug with host network

docker run \
--volumes-from local-repos-snap \
--add-host local.binhost:127.0.0.1 \
--volumes-from sckan-data \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--add-host=host.docker.internal:host-gateway \
--network=host \
-e FORWARD_URL_HOST=host.docker.internal \
-e FORWARD_URL_PORT=59213 \
-it tgbugs/musl:kg-release-user

build

unset _devel _docd _sckand _docsfsc
_devel=
_docd=(queries.org)
_docsf="https://raw.githubusercontent.com/SciCrunch/sparc-curation/master/docs/"
_sckand=(welcome.org tutorial.org overview.org examples.org scratch.org README.org)
_docsfsc="${_docsf}sckan/"
pushd ./musl/kg-release-user
  [ -d sckan ] && rm -r sckan
  mkdir sckan
  pushd sckan
    mkdir images
    mkdir reports
    if [ -n "${_devel}" ]; then
      cp -aL ~/git/sparc-curation/docs/sckan/*.org . ;
    else
      for fn in ${_docd[@]};   do curl -O ${_docsf}${fn}  ; done
      for fn in ${_sckand[@]}; do curl -O ${_docsfsc}${fn}; done
    fi
    chmod +x ./queries.org
  popd
popd

docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user
docker build \
--tag tgbugs/musl:kg-release-user \
--build-arg UID=${UID} \
--file musl/kg-release-user/Dockerfile musl/kg-release-user

entrypoints

Default interactive entrypoint.

rc-status
touch /run/openrc/softlevel
/etc/init.d/scigraph start
/etc/init.d/blazegraph start
su user -c 'emacs -geometry 120x40 -eval "(find-file-noselect (pop argv))" ~/sckan/welcome.org'
/etc/init.d/scigraph stop
/etc/init.d/blazegraph stop

Entrypoint to start services and run in the background.

rc-status
touch /run/openrc/softlevel
/etc/init.d/scigraph start
/etc/init.d/blazegraph start
tail -f /dev/null

file

sparcSCKAN-2021
FROM tgbugs/musl:kg-release as builder

WORKDIR /build

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -m -k /etc/skel -u ${UID} -g ${UID} -d $(pwd)/home/${USER_NAME} ${USER_NAME}

RUN \
mkdir -p home/${USER_NAME}/.local/bin

RUN \
chown -R ${UID}:${UID} home/${USER_NAME}

ARG HOME=/build/home/${USER_NAME}

WORKDIR $HOME

COPY --chown=${UID}:${UID} sckan sckan

USER ${USER_NAME}

RUN \
./sckan/queries.org

RUN \
emacs -batch -eval \
"(let ((user-init-file (pop argv))) (package-initialize) (while argv (let ((f (pop argv))) (orgstrap-whitelist-file f) (kill-buffer (find-file-noselect f)))) (ow-use-packages evil undo-tree))" \
$HOME/.emacs.d/init.el sckan/{queries,welcome,examples,scratch}.org

FROM tgbugs/musl:kg-release

COPY --from=builder /build /

ADD services.sh /etc/services.sh
ADD entrypoint.sh /etc/entrypoint.sh

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

USER 0

RUN \
usermod -a -G blazegraph user \
;  usermod -a -G scigraph user \
;  usermod -a -G wheel user

RUN \
echo 'root:sparcSCKAN-2021' | chpasswd

# make it easier to use portage inside a container
RUN \
echo 'EMERGE_DEFAULT_OPTS=""' >> /etc/portage/make.conf \
&& echo 'FEATURES=""' >> /etc/portage/make.conf

# TODO when running this you will have to set the right mounts
# unless you bake a new kg-dev-with-data release
ENTRYPOINT /etc/entrypoint.sh

kg-dev

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-dev
docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v /tmp/scigraph-build:/tmp/scigraph-build \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-dev \
echo TODO secrets, apinat build and more!

debug

docker run \
--volumes-from local-repos-snap \
--network host \
--add-host local.binhost:127.0.0.1 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-dev

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:kg-dev \
--build-arg UID=${UID} \
--file musl/kg-dev/Dockerfile musl/kg-dev

world

app-emacs/vterm
app-editors/emacs
dev-libs/nss
x11-libs/libXcomposite
x11-libs/libXtst
dev-java/icedtea-bin::tgbugs-overlay
dev-db/blazegraph-bin
dev-java/scigraph-bin
media-gfx/feh
media-gfx/graphviz
dev-python/ipykernel
dev-python/pip
dev-haskell/dot2graphml
app-misc/screen
dev-scheme/racket
net-libs/nodejs
app-arch/zip
app-misc/yq
dev-java/robot-bin
dev-node/apinat-converter
dev-python/nifstd-tools
dev-python/sparcur

file

FROM tgbugs/musl:kg-release

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
eselect racket set cs

kg-dev-user

run

# docker create -v /var/lib/blazegraph -v /var/lib/scigraph --name sckan-data tgbugs/sckan:latest /bin/true
docker run \
--volumes-from sckan-data \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-e SCIGRAPH_API=http://localhost:9000/scigraph \
-it tgbugs/musl:kg-dev-user

docker run \
-v /var/lib/blazegraph:/var/lib/blazegraph \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:kg-dev-user

build

docker build \
--tag tgbugs/musl:kg-dev-user \
--build-arg UID=${UID} \
--file musl/kg-dev-user/Dockerfile musl/kg-dev-user

entrypoint

if [ -d /tmp/blazegraph ]; then
    cp /tmp/blazegraph/blazegraph.jnl /var/lib/blazegraph/
    cp /tmp/blazegraph/prefixes.conf /var/lib/blazegraph/
    chown -R blazegraph:blazegraph /var/lib/blazegraph
fi
rc-status
touch /run/openrc/softlevel
/etc/init.d/scigraph start
/etc/init.d/blazegraph start
#su user -c 'emacs -visit ~/git/sparc-curation/docs/queries.org'
su user -
/etc/init.d/scigraph stop
/etc/init.d/blazegraph stop

file

ARG INIT_URL=https://raw.githubusercontent.com/tgbugs/orgstrap/master/init-simple.el

RUN \
emacs --batch --quick --eval \
"(progn (url-handler-mode 1) (find-file (pop argv)) (eval-buffer))" \
"${INIT_URL}"

RUN \
pushd ~/.emacs.d \
&& ln -s reval/cache/*/*-ow.el ow.el \
&& ln -s reval/cache/*/*-reval.el reval.el \
&& ln -s reval/cache/*/*-init-content.el init-content.el \
&& echo "(load (expand-file-name \"ow.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"reval.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"init-content.el\" user-emacs-directory))" >> init.el \
&& popd
FROM tgbugs/musl:kg-dev as builder

WORKDIR /build

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -m -k /etc/skel -u ${UID} -g ${UID} -d $(pwd)/home/${USER_NAME} ${USER_NAME}

RUN \
mkdir -p home/${USER_NAME}/.local/bin

RUN \
chown -R ${UID}:${UID} home/${USER_NAME}

RUN \
usermod --move-home --home /home/user ${USER_NAME}
#mv /build/home/user /home/ \
#&& usermod -d /home/user -m

USER ${USER_NAME}

#ARG HOME=/build/home/${USER_NAME}  # FIXME somehow /build/ lingers ??? do I have a stale file !?? !
# XXX the issue is &musl-user-skel-common uses /build/home/user in useradd with the expectation that
# it will not affect the actual image only the builder image
# FIXME XXXXXXXXXXXXXXXXXXXXXX SO SO SO SO BROKEN ARGH this breaks emacs and everything else
# it looks like /etc/passwd still has /build/home/user as HOME so setting $HOME doesn't save us?
# at least during debug that is what it looks like
ARG HOME=/home/${USER_NAME}

WORKDIR $HOME

ARG INIT_URL=https://raw.githubusercontent.com/tgbugs/orgstrap/master/init-simple.el

RUN \
emacs --batch --quick --eval \
"(progn (url-handler-mode 1) (find-file (pop argv)) (eval-buffer))" \
"${INIT_URL}"

RUN \
pushd ~/.emacs.d \
&& ln -s reval/cache/*/*-ow.el ow.el \
&& ln -s reval/cache/*/*-reval.el reval.el \
&& ln -s reval/cache/*/*-init-content.el init-content.el \
&& echo "(load (expand-file-name \"ow.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"reval.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"init-content.el\" user-emacs-directory))" >> init.el \
&& popd

RUN \
mkdir ~/git

# FIXME that is going to need to go in .bashrc or something
ENV PYTHONPYCACHEPREFIX=${HOME}/.cache/pycache/

# FIXME break these into their own images to avoid serial dependencies

# FIXME pip install --user -e . fails when run in /build/ due to change in $HOME
# because it uses an expanded directory of course pip doesn't have any only-deps
# option

RUN \
pushd git \
&&     git clone https://github.com/tgbugs/pyontutils.git \
&&     git clone https://github.com/SciCrunch/sparc-curation.git \
&& popd

RUN \
pushd git \
&&     pushd pyontutils \
&&         pip install --user -e . \
&&         pushd nifstd \
&&             pip install --user -e . \
&&             python setup.py --release || true \
&&         popd \
&&     popd \
&&     pushd sparc-curation \
&&         pip install --user -e . \
&&         python setup.py --release || true \
&&     popd \
&& popd \
&& ln -s ../../git/sparc-curation/docs/apinatomy.org ~/.local/bin/apinat-build \
&& rm -r ~/.cache/pip

RUN \
./git/sparc-curation/docs/queries.org

RUN \
./git/sparc-curation/docs/apinatomy.org

RUN \
emacs -batch -eval \
"(let ((user-init-file (pop argv))) (package-initialize) (while argv (orgstrap-whitelist-file (pop argv))))" \
$HOME/.emacs.d/init.el \
./git/sparc-curation/docs/queries.org \
./git/sparc-curation/docs/apinatomy.org

FROM tgbugs/musl:kg-dev

COPY --from=builder /home/${USER_NAME} /home/${USER_NAME}

ADD entrypoint.sh /etc/entrypoint.sh

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

# XXX somehow this induces ~10MB of new content !??!
#RUN \
#pip install --user --no-deps -e \
#git/pyontutils/nifstd \
#git/sparc-curation \
#&& rm -r ~/.cache/pip

USER 0

RUN \
usermod -a -G blazegraph user \
;  usermod -a -G scigraph user \
;  usermod -a -G wheel user

RUN \
echo 'root:sparcSCKAN-2021' | chpasswd

# make it easier to use portage inside a container
RUN \
echo 'EMERGE_DEFAULT_OPTS=""' >> /etc/portage/make.conf \
&& echo 'FEATURES=""' >> /etc/portage/make.conf

# TODO when running this you will have to set the right mounts
# unless you bake a new kg-dev-with-data release
ENTRYPOINT /etc/entrypoint.sh

racket

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:racket \
--file musl/racket/Dockerfile musl/racket

Build debug workflow.

# if you have not done so already
docker create \
-v /var/db/repos/gentoo \
--name local-portage-snap \
gentoo/portage:latest \
/bin/true

# if you have you have to clear the container with
# docker rm local-portage-snap

# then
docker run \
--volumes-from local-portage-snap \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:racket

file

FROM tgbugs/musl:emacs

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
eselect racket set cs

world

app-emacs/vterm
app-editors/emacs
dev-scheme/racket

racket-user

run

# to allow the container access to the local x session you have to run the following
xhost local:docker
# use xhost -local:docker to remove

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:racket-user

build

docker build \
--tag tgbugs/musl:racket-user \
--build-arg UID=${UID} \
--file musl/racket-user/Dockerfile musl/racket-user

file

FROM tgbugs/musl:racket

COPY --from=tgbugs/musl:user / /

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

dynapad-base

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:dynapad-base \
--file musl/dynapad-base/Dockerfile musl/dynapad-base

file

FROM tgbugs/musl:racket

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

app-emacs/vterm
app-editors/emacs
dev-scheme/racket
dev-libs/libconfig
sys-libs/db
dev-lang/tk
media-gfx/imagemagick
app-text/poppler

dynapad-user

build

docker build \
--tag tgbugs/musl:dynapad-user \
--build-arg UID=${UID} \
--file musl/dynapad-user/Dockerfile musl/dynapad-user

file

FROM tgbugs/musl:dynapad-base

COPY --from=tgbugs/musl:user / /

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

dynapad

run

Once you have created the tgbugs/musl:dynapad image (see the build section below) you can use this command to run it and commit on close each time so as not to lose any work. You will probably want to mount any additional directories you will need .e.g for images using -v.

  • linux
    docker run \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v ~/git/dynapad:/home/dynapad/git/dynapad \
    -e DISPLAY=$DISPLAY \
    -it tgbugs/musl:dynapad \
    sh -c 'pushd ~/git/dynapad && racketcgc -it apps/paddraw/paddraw.rkt'
    
    # docker commit $(docker ps -lq) tgbugs/musl:dynapad
    
  • macos

    See for notes on getting docker working with XQuartz. Assuming everything is set up correctly you can the run the following.

    docker run \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v ~/git/dynapad:/home/dynapad/git/dynapad \
    -e DISPLAY=host.docker.internal:0 \
    -it tgbugs/musl:dynapad \
    sh -c 'pushd ~/git/dynapad && racketcgc -it apps/paddraw/paddraw.rkt'
    
    # docker commit $(docker ps -lq) tgbugs/musl:dynapad
    
    xattr -d -r -s com.apple.quarantine /Applications/Docker.app
    

build

Since we need to mount the git directory from outside the image we can't use a docker file. Commit the image after these steps are finished (the commands above do that automatically).

If your UID is something other than 1000 you will probably want to rebuild tgbugs/musl:dynapad-user so that your UID matches.

docker pull tgbugs/musl:dynapad-user

docker run \
-v ~/git/dynapad:/home/dynapad/git/dynapad \
-it tgbugs/musl:dynapad-user
docker commit $(docker ps -lq) tgbugs/musl:dynapad

In the image run the following and then exit, the commit will be made automatically. NOTE You may need to remove build_musl if it already exists.

function dynapad-build-all () {
local build_dir SUBPATH SO_SUFFIX
#local PATH
#PATH=~/git/NOFORK/racket/racket/bin/:/usr/bin:/bin
# command -v racketcgc
# command -v racocgc
build_dir=${1:-build}
    mkdir ${build_dir}
    pushd ${build_dir}
        cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug
        ninja
    popd
    SUBPATH=$(racketcgc -e "(display (path->string (system-library-subpath)))")
    SO_SUFFIX=$(racketcgc -e "(display (bytes->string/utf-8 (system-type 'so-suffix)))")
    mkdir -p dynapad/compiled/bc/native/${SUBPATH}
    racocgc ctool --cgc \
            ++ldf -Wl,-rpath,"${PWD}/${build_dir}/" \
            --ld dynapad/compiled/bc/native/${SUBPATH}/libdynapad_rkt${SO_SUFFIX} \
            "${PWD}/${build_dir}/libdynapad${SO_SUFFIX}"
    racocgc pkg install dynapad-collects/ dynapad/
    racocgc make apps/paddraw/paddraw.rkt
    racocgc make apps/uberapp/uberapp.rkt
}
dynapad-build-all build_musl

sparcur

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:sparcur

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sparcur \
--file musl/sparcur/Dockerfile musl/sparcur

file

FROM tgbugs/musl:binpkg-only


ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

dev-db/redis
net-misc/rabbitmq-server
dev-python/pip
dev-python/sparcur
www-servers/uwsgi

sparcur-user

run

To run as a daemon use -d option in then docker ps to get the container id, and then docker logs -f the container.

Development docker run example.

_f=$(basename ~/ni/dev/sparc-curation-*.json)
_h=protocols-io-api-token-rw.pickle
docker run \
-v /var/lib/sparc/files:/var/lib/sparc/files \
-v /var/lib/sparc/.local/share/sparcur:/var/lib/sparc/.local/share/sparcur \
-v /var/lib/sparc/.cache:/var/lib/sparc/.cache \
-v /var/lib/sparc/.config/sparcur/docker-config.yaml:/var/lib/sparc/.config/sparcur/config.yaml \
-v ~/ni/dev/secrets-sparcron.yaml:/var/lib/sparc/.config/orthauth/secrets.yaml \
-v ~/ni/dev/${_f}:/var/lib/sparc/.config/orthauth/${_f} \
-v ~/ni/dev/${_h}:/var/lib/sparc/.config/orthauth/${_h} \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-e SCIGRAPH_API=http://192.168.1.207:9000/scigraph \
-it tgbugs/musl:sparcur-user

Production docker run example. Must be run as root.

function docker-run-sparcron () {
_f=$(su sparc -c 'basename /var/lib/sparc/.config/pyontutils/sparc-curation-*.json')
_h=protocols-io-api-token-rw.pickle
docker run \
-d \
-v /var/lib/sparc/files:/var/lib/sparc/files \
-v /var/lib/sparc/.local/share/sparcur:/var/lib/sparc/.local/share/sparcur \
-v /var/lib/sparc/.cache:/var/lib/sparc/.cache \
-v /var/lib/sparc/.config/sparcur/docker-config.yaml:/var/lib/sparc/.config/sparcur/config.yaml \
-v /var/lib/sparc/.config/pyontutils/secrets.yaml:/var/lib/sparc/.config/orthauth/secrets.yaml \
-v /var/lib/sparc/.config/pyontutils/${_f}:/var/lib/sparc/.config/orthauth/${_f} \
-v /var/lib/sparc/.config/pyontutils/${_h}:/var/lib/sparc/.config/orthauth/${_h} \
-e SCIGRAPH_API=https://scigraph.olympiangods.org/scigraph \
-e UWSGI_SOCKET_SPARCRON=0.0.0.0:7260 \
-p 7260:7260 \
-it tgbugs/musl:sparcur-user
}

Production image upgrade.

function upgrade-sparcron () {
_image=tgbugs/musl:sparcur-user
_image_date=$(date -I --date $(docker inspect ${_image} --format '{{.Created}}'))
_cid_old=$(docker ps -lqf ancestor=${_image})
docker tag ${_image} ${_image}-${_image_date}
docker pull ${_image}
docker stop ${_cid_old}
docker-run-sparcron
_cid_new=$(docker ps -lqf ancestor=${_image})
docker logs -f ${_cid_new}
}

Production image archive.

for img in $(docker image ls tgbugs/musl:sparcur-user-* --format '{{.Repository}}:{{.Tag}}'); do
docker save "${img}" | gzip > /mnt/str/sparc/docker-images/"${img//\//-}".tar.gz
done

for img in $(docker image ls tgbugs/musl:sparcur-user-* --format '{{.Repository}}:{{.Tag}}' | sort | head -n -1); do
docker image rm "${img}" || break
done

build

docker build \
--tag tgbugs/musl:sparcur-user \
--file musl/sparcur-user/Dockerfile musl/sparcur-user

file

FROM tgbugs/musl:sparcur

ADD --chown=836:836 idlib-config.yaml /var/lib/sparc/.config/idlib/config.yaml
ADD --chown=836:836 sparcur-config.yaml /var/lib/sparc/.config/sparcur/config.yaml

ARG HOME=/var/lib/sparc

WORKDIR $HOME

ADD entrypoint.sh /etc/entrypoint.sh

ENTRYPOINT /etc/entrypoint.sh

configs

This config provides sane defaults, if you need to add a section (such as a datasets-no:) then use -v in docker run to mount over the location of this file.

auth-stores:
  secrets:
    path: '{:user-config-path}/orthauth/secrets.yaml'
auth-variables:
  google-api-service-account-file-readonly:
    path: google api saro
  hypothesis-api-key: hypothesis api default-user
  hypothesis-group: hypothesis group sparc-curation
  remote-organization: N:organization:618e8dd9-f8d2-4dc4-9abb-c6aaab2e78a0
auth-stores:
  secrets:
    path: '{:user-config-path}/orthauth/secrets.yaml'
auth-variables:
  protocols-io-api-creds-file:
    path: protocols-io api creds-file
  protocols-io-api-store-file:
    path: protocols-io api store-file

entrypoint

Slowly inching toward being able to run this via a service manager.

if [ -n "${UWSGI_SOCKET_SPARCRON}" ]; then
    echo "UWSGI_SOCKET_SPARCRON=${UWSGI_SOCKET_SPARCRON}" >> /etc/conf.d/sparcron-server
fi

rc-status
touch /run/openrc/softlevel
/etc/init.d/redis start
/etc/init.d/rabbitmq start
/etc/init.d/sparcron-server start

# testing and ensure that there is an existing cache on first run
su sparc -c 'pypy3 -m sparcur.sparcron'

su sparc -c 'EPYTHON=pypy3 PYTHONBREAKPOINT=0 celery --app sparcur.sparcron worker -n wcron -Q cron,default --concurrency=1 --beat --schedule-filename ./sparcur-cron-schedule --loglevel=INFO' &

su sparc -c 'EPYTHON=pypy3 PYTHONBREAKPOINT=0 celery --app sparcur.sparcron worker -n wexport -Q export --loglevel=INFO'
# FIXME missing rmeta stuff ?

#/etc/init.d/redis stop
#/etc/init.d/rabbitmq stop

protc

world

dev-libs/redland

musl static

Same metadata as musl except with static-libs in order to produce statically linked binaries.

profile-static-x

run

technically this is just debug since we can't actually run these

_name=profile-static-x.tar
docker create --name="tmp_$$" tgbugs/musl:profile-static-x true > /dev/null &&
docker export tmp_$$ > ${_name} &&
docker rm tmp_$$ > /dev/null
printf ${_name}

build

docker build \
--tag tgbugs/musl:profile-static-x \
--file musl/profile-x/static.Dockerfile .

file

FROM busybox:latest as builder

WORKDIR /build

ADD docker-profile/x/docker-profile var/db/docker-profile
ADD docker-profile/static/docker-profile var/db/docker-profile
ADD docker-profile/base/binrepos-multi.conf etc/portage/binrepos.conf/multi.conf

ARG bp=docker-profile/static/
ARG hr=helper-repos/

# ADD ${bp}sbcl.env etc/portage/env/dev-lisp/sbcl  # gets klobbered when we make the profile so have to do it differently
ADD ${hr}sbcl/patches/dev-lisp etc/portage/patches/dev-lisp

FROM scratch

WORKDIR /
COPY --from=builder /build /

static-xorg

run

debug

docker run \
--net host \
--add-host local.binhost:127.0.0.1 \
--volumes-from local-repos-snap \
-v ~/files/binpkgs/multi:/var/cache/binpkgs \
-v /mnt/str/portage/distfiles:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
--rm \
-it \
tgbugs/musl:static-xorg

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:static-xorg \
--build-arg PROFILE='docker-profile:tgbugs/musl/static/x' \
--build-arg PROFILE_IMAGE='tgbugs/musl:profile-static-x' \
--build-arg START_IMAGE='tgbugs/musl:updated' \
--file musl/xorg/Dockerfile musl/xorg

static-package-builder

populate 0

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/musl:static-xorg \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'

run

docker run tgbugs/musl:static-package-builder
docker commit $(docker ps -lq) tgbugs/musl:static-package-builder-snap

cat ./musl/package-builder/world | xargs \
docker run \
--volumes-from local-repos-snap \
--volumes-from cross-sbcl \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v ${_path_distfiles}:/var/cache/distfiles \
tgbugs/musl:static-package-builder-snap \
emerge --color=y -j4 -q --keep-going -uDN

docker commit $(docker ps -lq) tgbugs/musl:static-package-builder-snap

build

docker build \
--tag tgbugs/musl:static-package-builder \
--file musl/package-builder/static.Dockerfile musl/package-builder

file

FROM tgbugs/musl:static-xorg

COPY --from=tgbugs/musl:portage-maven / /

ADD repo_name /var/db/crossdev/profiles/repo_name
ADD layout.conf /var/db/crossdev/metadata/layout.conf
ADD crossdev.conf /etc/portage/repos.conf/crossdev.conf
ADD sbcl.env /etc/portage/env/dev-lisp/sbcl

RUN \
echo 'FEATURES="${FEATURES} buildpkg"' >> /etc/portage/make.conf \
&& echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkg"' >> /etc/portage/make.conf

ADD static-sbcl.env /etc/portage/env/dev-lisp/sbcl

world

app-emacs/vterm
app-editors/emacs
dev-lisp/uiop
dev-lisp/asdf
dev-lisp/sbcl
dev-libs/openssl
dev-libs/gmp
dev-libs/capstone
dev-libs/mpfr
dev-libs/redland
dev-libs/openssl
dev-libs/gmp
dev-libs/capstone
dev-libs/mpfr
dev-libs/redland

static-binpkg-only

build

docker build \
--tag tgbugs/musl:static-binpkg-only \
--file musl/binpkg-only/static.Dockerfile musl/binpkg-only

file

FROM tgbugs/musl:static-xorg

RUN \
echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkgonly --getbinpkgonly"' >> /etc/portage/make.conf \
&& echo 'FEATURES="${FEATURES} parallel-install -ebuild-locks"' >> /etc/portage/make.conf

sbcl

build

docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--tag tgbugs/musl:sbcl \
--file musl/sbcl/Dockerfile musl/sbcl

file

FROM tgbugs/musl:static-binpkg-only

ARG ARCHIVE

ADD world /var/lib/portage/world

# -ebuild locks is so much faster building acct-* ebuilds first is MUCH faster
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
FEATURES=ebuild-locks emerge -1 -j4 -q -uDN $(cat /var/lib/portage/world | xargs emerge -p | grep -o 'acct-.\+$' | sed 's/^/=/') \
;  cat /var/lib/portage/world | xargs emerge -j4 -q -uDN \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

world

app-emacs/vterm
app-editors/emacs
dev-lisp/uiop
dev-lisp/asdf
dev-lisp/sbcl

patches

make the patches since they are too much to tangle FIXME this is currently an entirely manual step FIXME this needs to be moved to run inside a builder phase

function sbcl-static-patch () {
local version tag spath tpath patch
version=${1}
tag=sbcl-${version}
patch=static-${version}.patch
spath=./helper-repos/sbcl/patches
tpath=./docker-profile/static/
ipath=patches/dev-lisp/sbcl-${version}/
sighpath=./helper-repos/sbcl/patches/dev-lisp/sbcl-${version}/${patch}
if [[ ! -f "${sighpath}" ]]; then
  mkdir helper-repos
  pushd helper-repos
    git clone https://github.com/sbcl/sbcl.git
    pushd sbcl
      git fetch
      git remote add tgbugs https://github.com/tgbugs/sbcl.git
      git fetch tgbugs
      mkdir -p ${ipath}
      # gentoo eapply_user happens after gentoo patches are applied so we have to compensate here :/
      git diff ${tag}..remotes/tgbugs/static-executable-v2-${version} ':(exclude)README*' | \
        sed 's,maybetime sh,maybetime sh -x,' > \
        ${ipath}/${patch}
    popd
  popd
fi
# XXX old, we renamed this so that they will work
# this portion has to be repeatable because we zap docker-profile on every tangle
# mkdir -p ${tpath}
# cp -a ${spath} ${tpath}
}
function sbcl-static-patch () {
local version tag spath tpath patch
version=${1}
tag=sbcl-${version}
patch=static-${version}.patch
spath=./helper-repos/sbcl/patches
tpath=./docker-profile/static/
ipath=patches/dev-lisp/sbcl-${version}/
sighpath=./helper-repos/sbcl/patches/dev-lisp/sbcl-${version}/${patch}
if [[ ! -f "${sighpath}" ]]; then
  mkdir helper-repos
  pushd helper-repos
    git clone https://github.com/sbcl/sbcl.git
    pushd sbcl
      git fetch
      git remote add tgbugs https://github.com/tgbugs/sbcl.git
      git fetch tgbugs
      mkdir -p ${ipath}
      # gentoo eapply_user happens after gentoo patches are applied so we have to compensate here :/
      git diff ${tag}..remotes/tgbugs/static-executable-v2-${version} ':(exclude)README*' | \
        sed 's,maybetime sh,maybetime sh -x,' > \
        ${ipath}/${patch}
    popd
  popd
fi
# XXX old, we renamed this so that they will work
# this portion has to be repeatable because we zap docker-profile on every tangle
# mkdir -p ${tpath}
# cp -a ${spath} ${tpath}
}
sbcl-static-patch 2.2.6
sbcl-static-patch 2.2.7
post_src_configure() {
truncate -s $(head -n -2 "${CONFIG}" | wc -c) "${CONFIG}"
sbcl_feature "true" ":sb-linkable-runtime"
sbcl_feature "true" ":sb-prelink-linkage-table"
echo ') list)' >> "${CONFIG}"
}
src_unpack() {
        unpack ${A}
        [ -d /sbcl ] && {
                einfo "Using /sbcl for bootstrap"
                cp -r /sbcl sbcl-binary || die;
                cp -a ${S}/run-sbcl.sh sbcl-binary/ || die;
        } || {
        command -v sbcl && {
                einfo "Using local sbcl found at $(command -v sbcl) for bootstrap"
                local bin_core_home;
                IFS=',' read -r -a bin_core_home <<< $(sbcl --noinform --no-sysinit --no-userinit --eval \
                '(progn (format t "~a,~a,~a" sb-ext:*runtime-pathname* sb-ext:*core-pathname* (sb-int:sbcl-homedir-pathname)))' --quit) || die;
                mkdir -p sbcl-binary/src/runtime || die;
                mkdir -p sbcl-binary/output || die;
                mkdir -p sbcl-binary/obj/sbcl-home || die;
                cp -a ${bin_core_home[0]} sbcl-binary/src/runtime/ || die;
                cp -a ${bin_core_home[1]} sbcl-binary/output/ || die;
                cp -a ${bin_core_home[2]}/contrib sbcl-binary/obj/sbcl-home/contrib || die;
                cp -a ${S}/run-sbcl.sh sbcl-binary/ || die;
        } } ||
        mv sbcl-*-* sbcl-binary || die
        cd "${S}"
}

post_src_configure() {
truncate -s $(head -n -2 "${CONFIG}" | wc -c) "${CONFIG}"
sbcl_feature "true" ":sb-linkable-runtime"
sbcl_feature "true" ":sb-prelink-linkage-table"
echo ') list)' >> "${CONFIG}"
}

sbcl-user

run

docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/musl:sbcl-user

build

docker build \
--tag tgbugs/musl:sbcl-user \
--build-arg UID=${UID} \
--file musl/sbcl-user/Dockerfile musl/sbcl-user

file

FROM tgbugs/musl:sbcl

COPY --from=tgbugs/musl:user / /

ARG UID=1000
ARG USER_NAME=user

RUN \
groupadd -g ${UID} ${USER_NAME} \
&& useradd -M -u ${UID} -g ${UID} ${USER_NAME}

USER $USER_NAME

WORKDIR /home/${USER_NAME}

ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}"

# FIXME builder to factor common here
ARG INIT_URL=https://raw.githubusercontent.com/tgbugs/orgstrap/master/init-simple.el

RUN \
emacs --batch --quick --eval \
"(progn (url-handler-mode 1) (find-file (pop argv)) (eval-buffer))" \
"${INIT_URL}"

RUN \
pushd ~/.emacs.d \
&& ln -s reval/cache/*/*-ow.el ow.el \
&& ln -s reval/cache/*/*-reval.el reval.el \
&& ln -s reval/cache/*/*-init-content.el init-content.el \
&& echo "(load (expand-file-name \"ow.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"reval.el\" user-emacs-directory))" >> init.el \
&& echo "(load (expand-file-name \"init-content.el\" user-emacs-directory))" >> init.el \
&& popd

gnu

may not need this if we can use crossdev to build glibc sbcl on musl that that seems a stretch

profile

build

docker build \
--tag tgbugs/gnu:profile \
--file gnu/profile/Dockerfile .

file

FROM busybox:latest as builder

WORKDIR /build

# XXX FIXME this is from musl so we don't want all of these
# we don't put this in var/db/repos because repos is managed via tgbugs/repos:latest
ARG bp=docker-profile/base/

ADD ${bp}docker-profile                          var/db/docker-profile
ADD ${bp}docker-profile.conf                     etc/portage/repos.conf/docker-profile.conf
ADD ${bp}binrepos-multi.conf                     etc/portage/binrepos.conf/multi.conf
ADD ${bp}package.accept_keywords                 etc/portage/package.accept_keywords/profile
ADD ${bp}package.mask                            etc/portage/package.mask/profile
ADD ${bp}package.unmask                          etc/portage/package.unmask/profile
ADD ${bp}emacs.env                               etc/portage/env/app-editors/emacs
ADD ${bp}erlang.env                              etc/portage/env/dev-lang/erlang
ADD ${bp}rabbitmq.env                            etc/portage/env/net-misc/rabbitmq-server
ADD ${bp}no-distcc.env                           etc/portage/env/no-distcc
ADD ${bp}package.env                             etc/portage/package.env/profile
ADD ${bp}musl-find_library.patch                 etc/portage/patches/dev-lang/python:2.7/musl-find_library.patch
ADD ${bp}musl-include-sys-time.patch             etc/portage/patches/dev-python/pypy3-exe/musl-include-sys-time.patch
ADD ${bp}musl-fix-stdio-defs.patch               etc/portage/patches/dev-python/pypy3-exe/musl-fix-stdio-defs.patch
ADD ${bp}pypy3-json-str-subclass-safety.patch    etc/portage/patches/dev-python/pypy3/json-str-subclass-safety.patch

FROM scratch

WORKDIR /
COPY --from=builder /build /

eselect-repo

build

docker build \
--tag tgbugs/gnu:eselect-repo \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/eselect-repo/Dockerfile gnu/eselect-repo

file

FROM gentoo/stage3:hardened

ARG ARCHIVE

COPY --from=tgbugs/gnu:profile / /

RUN \
# FIXME tgbugs-overlay symlinks
ln -s /var/db/repos/gentoo /usr/portage

RUN \
eselect news read all \
&& eselect news purge

# XXX these are retained to avoid crossdev and other issues where
# portage needs these to be folders and are expected to error if
# the profile in question creates a ./profile file in these folders
RUN \
   mkdir /etc/portage/package.accept_keywords > /dev/null 2>&1 \
;  mkdir /etc/portage/package.env             > /dev/null 2>&1 \
;  mkdir /etc/portage/package.mask            > /dev/null 2>&1 \
;  mkdir /etc/portage/package.unmask          > /dev/null 2>&1 \
;  mkdir /etc/portage/package.use             > /dev/null 2>&1 \
;  mkdir /etc/portage/repos.conf              > /dev/null 2>&1 \
|| true

RUN \
eselect profile set docker-profile:tgbugs/gnu

# FIXME MAKEOPTS_LOCAL
RUN \
echo "MAKEOPTS=\"-j$(nproc)\"" >> /etc/portage/make.conf
# XXX setting PORTAGE_BINHOSTS has to come later? maybe as an envar?

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge --info 2>&1 | { grep Invalid\ atom && exit 1; exit 0; }

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
emerge -j4 -q \
   --getbinpkg \
   dev-vcs/git \
   app-eselect/eselect-repository \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=gentoo/portage:latest,source=/var/db/repos/gentoo,target=/var/db/repos/gentoo,rw \
eselect repository add tgbugs-overlay git https://github.com/tgbugs/tgbugs-overlay.git \
&& eselect repository enable lisp \
&& eselect repository enable haskell

package-builder

populate 0

docker run \
--volumes-from local-repos-snap \
-v ${_path_binpkgs}:/var/cache/binpkgs \
-v "$(pwd)"/bin/quickpkg-new:/tmp/quickpkg-new \
--rm \
tgbugs/gnu:package-builder \
/bin/sh -c 'quickpkg $(/tmp/quickpkg-new)'

build

docker build \
--tag tgbugs/gnu:package-builder \
--file gnu/package-builder/Dockerfile gnu/package-builder

file

FROM tgbugs/gnu:eselect-repo

COPY --from=tgbugs/musl:portage-maven / /

ADD repo_name /var/db/crossdev/profiles/repo_name
ADD layout.conf /var/db/crossdev/metadata/layout.conf
ADD crossdev.conf /etc/portage/repos.conf/crossdev.conf
ADD sbcl.env /etc/portage/env/dev-lisp/sbcl

RUN \
echo 'FEATURES="${FEATURES} buildpkg"' >> /etc/portage/make.conf \
&& echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --usepkg"' >> /etc/portage/make.conf

crossdev

crossdev
masters = gentoo
thin-manifests = true
[crossdev]
location = /var/db/crossdev
priority = 10
masters = gentoo
auto-sync = no

crossdev

build

docker build \
--tag tgbugs/gnu:crossdev \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/crossdev/Dockerfile gnu/crossdev

file

FROM tgbugs/gnu:eselect-repo

#emerge -j4 -q -uDN \  # yeahno
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -q \
   --getbinpkg \
   --keep-going \
   sys-devel/crossdev \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge --usepkg --getbinpkgonly \
   cross-x86_64-pc-linux-musl/musl \
   cross-x86_64-pc-linux-musl/linux-headers \
   cross-x86_64-pc-linux-musl/gcc \
   cross-x86_64-pc-linux-musl/binutils \
;  crossdev --stable --target x86_64-pc-linux-musl --stage4 \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

ghc-cross   do_not_use

This is very much not working right now, our solution to use alpine to get a ghc that works with musl 1.2.3 works. I suspect that the ghc ebuilds are not set up to work with cross compiling for some reason.

run

docker run \
--volumes-from local-repos-snap \
-v /mnt/str/portage/distfiles:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/gnu:ghc-cross

Test that the cross compiled version is working as expected.

docker run \
-it tgbugs/gnu:ghc-cross \
/usr/x86_64-pc-linux-musl/usr/bin/ghci

build

docker build \
--tag tgbugs/gnu:ghc-cross \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/ghc-cross/Dockerfile gnu/ghc-cross

file

FROM tgbugs/gnu:crossdev

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -q \
   --getbinpkg \
   --keep-going \
   dev-lang/ghc \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
x86_64-pc-linux-musl-emerge -j4 -q \
   --getbinpkg \
   --keep-going \
   sys-libs/musl \
   sys-libs/zlib \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
USE=ghcbootstrap x86_64-pc-linux-musl-emerge -j4 -q \
   dev-lang/ghc \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

patch

  • ignore Winline (fails)

    evil but generalized solution to fatal inline warnings, this is a bootstrap build after all

    --- a/rts/ghc.mk
    +++ b/rts/ghc.mk
    @@ -355,7 +355,6 @@
     WARNING_OPTS += -Wstrict-prototypes
     WARNING_OPTS += -Wmissing-prototypes
     WARNING_OPTS += -Wmissing-declarations
    -WARNING_OPTS += -Winline
     WARNING_OPTS += -Wpointer-arith
     WARNING_OPTS += -Wmissing-noreturn
     WARNING_OPTS += -Wnested-externs
    

    but then linking fails

    `x86_64-pc-linux-musl-ld' failed in phase `Merge objects'. (Exit code: 1)
    make[1]: *** [libraries/ghc-prim/ghc.mk:4: libraries/ghc-prim/dist-install/build/GHC/Prim/Ext.o] Error 1
    

    not sure if related https://gitlab.haskell.org/ghc/ghc/-/issues/17962

    also seems to fail at other steps, but the build processes more or less works as expected if you go in an just call make as root … very likely because the environment is totally different

  • previous attempts (fails)

    mkdir -p /usr/x86_64-pc-linux-musl/etc/portage/patches/dev-lang/ghc-9.0.2

    --- a/rts/sm/Evac.c       2021-09-15 15:27:32.000000000 -0000
    +++ b/rts/sm/Evac.c       2022-12-01 19:52:51.123156616 -0000
    @@ -58,7 +58,7 @@
     #define MAX_THUNK_SELECTOR_DEPTH 16
    
     static void eval_thunk_selector (StgClosure **q, StgSelector *p, bool);
    -STATIC_INLINE void evacuate_large(StgPtr p);
    +static void evacuate_large(StgPtr p);
    
     /* -----------------------------------------------------------------------------
        Allocate some space in which to copy an object.
    
    

    from ghc fc8a7f8f2aed3420dcbe2c5c25a525634779166f

    diff --git a/includes/Rts.h b/includes/Rts.h
    index 1e5a60262b..027d5173a1 100644
    --- a/includes/Rts.h
    +++ b/includes/Rts.h
    @@ -37,12 +37,17 @@ extern "C" {
     #include "HsFFI.h"
     #include "RtsAPI.h"
    
    -// Turn off inlining when debugging - it obfuscates things
    +// Disencourage gcc from inlining when debugging - it obfuscates things
     #if defined(DEBUG)
     # undef  STATIC_INLINE
     # define STATIC_INLINE static
     #endif
    
    +// Fine grained inlining control helpers.
    +#define ATTR_ALWAYS_INLINE __attribute__((always_inline))
    +#define ATTR_NOINLINE      __attribute__((noinline))
    +
    +
     #include "rts/Types.h"
     #include "rts/Time.h"
    
    diff --git a/rts/sm/Evac.c b/rts/sm/Evac.c
    index e660fad1d8..8595a80c38 100644
    --- a/rts/sm/Evac.c
    +++ b/rts/sm/Evac.c
    @@ -58,7 +58,7 @@
     #define MAX_THUNK_SELECTOR_DEPTH 16
    
     static void eval_thunk_selector (StgClosure **q, StgSelector *p, bool);
    -STATIC_INLINE void evacuate_large(StgPtr p);
    +ATTR_NOINLINE static void evacuate_large(StgPtr p);
    
     /* -----------------------------------------------------------------------------
        Allocate some space in which to copy an object.
    @@ -134,8 +134,13 @@ alloc_for_copy (uint32_t size, uint32_t gen_no)
        The evacuate() code
        -------------------------------------------------------------------------- */
    
    -/* size is in words */
    -STATIC_INLINE GNUC_ATTR_HOT void
    +/* size is in words
    +
    +   We want to *always* inline this as often the size of the closure is static,
    +   which allows unrolling of the copy loop.
    +
    + */
    +ATTR_ALWAYS_INLINE GNUC_ATTR_HOT static inline void
     copy_tag(StgClosure **p, const StgInfoTable *info,
              StgClosure *src, uint32_t size, uint32_t gen_no, StgWord tag)
     {
    @@ -194,7 +199,7 @@ copy_tag(StgClosure **p, const StgInfoTable *info,
     }
    
     #if defined(PARALLEL_GC) && !defined(PROFILING)
    -STATIC_INLINE void
    +ATTR_ALWAYS_INLINE static inline void
     copy_tag_nolock(StgClosure **p, const StgInfoTable *info,
              StgClosure *src, uint32_t size, uint32_t gen_no, StgWord tag)
     {
    @@ -231,7 +236,7 @@ copy_tag_nolock(StgClosure **p, const StgInfoTable *info,
      * pointer of an object, but reserve some padding after it.  This is
      * used to optimise evacuation of TSOs.
      */
    -static bool
    +ATTR_ALWAYS_INLINE static inline bool
     copyPart(StgClosure **p, StgClosure *src, uint32_t size_to_reserve,
              uint32_t size_to_copy, uint32_t gen_no)
     {
    @@ -283,7 +288,7 @@ spin:
    
    
     /* Copy wrappers that don't tag the closure after copying */
    -STATIC_INLINE GNUC_ATTR_HOT void
    +ATTR_ALWAYS_INLINE GNUC_ATTR_HOT static inline void
     copy(StgClosure **p, const StgInfoTable *info,
          StgClosure *src, uint32_t size, uint32_t gen_no)
     {
    @@ -301,7 +306,7 @@ copy(StgClosure **p, const StgInfoTable *info,
        that has been evacuated, or unset otherwise.
        -------------------------------------------------------------------------- */
    
    -static void
    +ATTR_NOINLINE static void
     evacuate_large(StgPtr p)
     {
       bdescr *bd;
    -- 
    2.37.4
    

    We haven't resolved all the issues yet …

    In file included from includes/Rts.h:244,
    
                     from rts/Interpreter.c:8:0: error: 
    rts/Interpreter.c: In function ‘interpretBCO’:
    
    includes/rts/StablePtr.h:32:8: error:
         warning: inlining failed in call to ‘deRefStablePtr’: call is unlikely and code size would grow [-Winline]
           32 | StgPtr deRefStablePtr(StgStablePtr sp)
              |        ^~~~~~~~~~~~~~
       |
    32 | StgPtr deRefStablePtr(StgStablePtr sp)
       |        ^
    
    rts/Interpreter.c:1112:45: error:
         note: called from here
         1112 |                   ioAction = (StgClosure *) deRefStablePtr (
              |                                             ^~~~~~~~~~~~~~~~
         1113 |                       rts_breakpoint_io_action);
              |                       ~~~~~~~~~~~~~~~~~~~~~~~~~
         |
    1112 |                   ioAction = (StgClosure *) deRefStablePtr (
         |                                             ^
    
    

    let's see if 9.2.4 will compile any better

    mkdir -p /usr/x86_64-pc-linux-musl/etc/portage/repos.conf
    cp /etc/portage/repos.conf/eselect-repo.conf /usr/x86_64-pc-linux-musl/etc/portage/repos.conf/
    ACCEPT_KEYWORDS='**' FEATURES=-distcc USE=ghcbootstrap x86_64-pc-linux-musl-emerge =dev-lang/ghc-9.2.4::haskell   
    

    … ugh nope, this one fails well before 9.0.2 does

    config.status: executing src commands
    # wc on OS X has spaces in its output, which libffi's Makefile
    # doesn't expect, so we tweak it to sed them out
    mv libffi/build/Makefile libffi/build/Makefile.orig
    sed "s#wc -w#wc -w | sed 's/ //g'#" < libffi/build/Makefile.orig > libffi/build/Makefile
    "touch" libffi/stamp.ffi.static-shared.configure
    make: *** [Makefile:128: ghc/stage2/build/tmp/ghc-stage2] Error 2
    

    when running make in libraries/ghc-prim we find some many additional issues I have no idea why these are showing up in the musl cross builds when they are not in the native gnu case a sampling of the kinds of issues

    In function 'updateRemembSetPushTSO':
    
    rts/sm/NonMovingMark.c:693:20: error:
         warning: inlining failed in call to 'finish_upd_rem_set_mark': --param max-inline-insns-single limit reached [-Winline]
          693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
              |                    ^~~~~~~~~~~~~~~~~~~~~~~
        |
    693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
        |                    ^
    
    rts/sm/NonMovingMark.c:719:9: error:
         note: called from here
          719 |         finish_upd_rem_set_mark((StgClosure *) tso);
              |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |
    719 |         finish_upd_rem_set_mark((StgClosure *) tso);
        |         ^
    rts/sm/NonMovingMark.c: In function 'updateRemembSetPushStack':
    
    rts/sm/NonMovingMark.c:693:20: error:
         warning: inlining failed in call to 'finish_upd_rem_set_mark': --param max-inline-insns-single limit reached [-Winline]
          693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
              |                    ^~~~~~~~~~~~~~~~~~~~~~~
        |
    693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
        |                    ^
    
    rts/sm/NonMovingMark.c:734:13: error:
         note: called from here
          734 |             finish_upd_rem_set_mark((StgClosure *) stack);
              |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |
    734 |             finish_upd_rem_set_mark((StgClosure *) stack);
        |             ^
    
    rts/sm/NonMovingMark.c:693:20: error:
         warning: inlining failed in call to 'finish_upd_rem_set_mark': --param max-inline-insns-single limit reached [-Winline]
          693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
              |                    ^~~~~~~~~~~~~~~~~~~~~~~
        |
    693 | STATIC_INLINE void finish_upd_rem_set_mark(StgClosure *p)
        |                    ^
    
    rts/sm/NonMovingMark.c:734:13: error:
         note: called from here
          734 |             finish_upd_rem_set_mark((StgClosure *) stack);
              |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |
    734 |             finish_upd_rem_set_mark((StgClosure *) stack);
        |    
    

sbcl-cross

run

docker run \
--volumes-from local-repos-snap \
-v /mnt/str/portage/distfiles:/var/cache/distfiles \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
-it tgbugs/gnu:sbcl-cross

Test that the cross compiled version is working as expected.

docker run \
-it tgbugs/gnu:sbcl-cross \
/usr/x86_64-pc-linux-musl/usr/bin/sbcl --core /usr/x86_64-pc-linux-musl/usr/lib/sbcl/sbcl.core

build

docker build \
--tag tgbugs/gnu:sbcl-cross \
--network host \
--add-host local.binhost:127.0.0.1 \
--file gnu/sbcl-cross/Dockerfile gnu/sbcl-cross

file

FROM tgbugs/gnu:crossdev

# sbcl crossdev build looks in the wrong place for asdf and uiop
RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
emerge -j4 -q \
   --getbinpkg \
   --keep-going \
   dev-lisp/asdf \
   dev-lisp/uiop \
   dev-lisp/sbcl \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

ADD alt-ld.patch /etc/portage/patches/dev-lisp/sbcl/alt-ld.patch
ADD alt-ld.patch /usr/x86_64-pc-linux-musl/etc/portage/patches/dev-lisp/sbcl/alt-ld.patch
ADD 99-sbcl /usr/x86_64-pc-linux-musl/etc/portage/package.use/99-sbcl

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
x86_64-pc-linux-musl-emerge -j4 -q \
   --getbinpkg \
   --keep-going \
   sys-libs/musl \
   sys-libs/zlib \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

RUN \
ln -s /usr/x86_64-pc-linux-musl/usr/lib/libc.so /lib/ld-musl-x86_64.so.1

RUN --mount=from=tgbugs/repos:latest,source=/var/db/repos,target=/var/db/repos,rw \
x86_64-pc-linux-musl-emerge -j4 -q \
   dev-lisp/asdf \
   dev-lisp/uiop \
   dev-lisp/sbcl \
;  export CODE=$? \
;  echo CODE $CODE \
;  [[ -n ${ARCHIVE} ]] \
|| { rm -r /var/cache/distfiles/* > /dev/null 2>&1 \
   ; rm -r /var/cache/binpkgs/* > /dev/null 2>&1; } \
;  exit $CODE

Until we can figure out how to get the cross build to link this correctly we leave it out. We don't really need it since this build is only for a bootstrapping sbcl on musl. There are native ways to do this inside of the sbcl toolset itself, but for now this is easier.

dev-lisp/sbcl -zlib  # crossdev compile reference errors
diff --git a/make-target-contrib.sh b/make-target-contrib.sh
index 217b5b2e0..45406f506 100755
--- a/make-target-contrib.sh
+++ b/make-target-contrib.sh
@@ -29,8 +29,12 @@ if [ -z "$CC" ]; then
     fi
 fi

+if [ -z "${LD}" ]; then
+    LD=ld
+fi
+
 unset EXTRA_CFLAGS # avoid any potential interference 
-export CC LANG LC_ALL
+export CC LD LANG LC_ALL

 # Load our build configuration
 . output/build-config
diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile
index 0543c1244..284755e5c 100644
--- a/src/runtime/GNUmakefile
+++ b/src/runtime/GNUmakefile
@@ -24,7 +24,6 @@ SBCL_PAXCTL ?= :
 LINKFLAGS += -g
 DEPEND_FLAGS = -MM
 GREP = grep
-LD = ld

 # By default, don't make and use a library, just use the object files.
 LIBSBCL = $(OBJS)
git clone https://github.com/sbcl/sbcl.git
pushd sbcl
git remote add daewok https://github.com/daewok/sbcl.git
git fetch daewok
git checkout daewok/static-executable

musl/cross/sbcl

build

docker build \
--tag tgbugs/musl:cross-sbcl \
--file musl/cross/sbcl/Dockerfile musl/cross/sbcl

docker rm cross-sbcl
docker create -v /sbcl --name cross-sbcl tgbugs/musl:cross-sbcl /bin/true

file

FROM busybox:latest

WORKDIR /

COPY --from=tgbugs/gnu:sbcl-cross /usr/x86_64-pc-linux-musl/usr/lib/sbcl /sbcl
COPY --from=tgbugs/gnu:sbcl-cross /usr/x86_64-pc-linux-musl/usr/bin/sbcl /sbcl/src/runtime/sbcl

RUN \
mkdir -p /sbcl/obj/sbcl-home \
&& ln -s /sbcl/contrib /sbcl/obj/sbcl-home/contrib \
&& mkdir -p /sbcl/output \
&& ln -s /sbcl/sbcl.core /sbcl/output/sbcl.core

VOLUME /sbcl

other

alpine bootstrap

Barely working and incomplete bootstrap in alpine. Might be useful for CI depending on how well the tgbugs/musl:docker work progresses.

(let ((u (pop argv)) (p (pop argv)) (enable-local-eval t)) (mkdir (file-name-directory p) t) (org-babel-do-load-languages 'org-babel-load-languages '((screen . t))) (url-handler-mode 1) (find-file u) (write-file p) (chmod p #o755) (find-file p) (org-sbe workflow))
SHELL=/bin/bash screen -dmS org-session
# emacs -batch -eval "(let ((u (pop argv)) (p (pop argv)) (enable-local-eval t)) (mkdir (file-name-directory p) t) (org-babel-do-load-languages 'org-babel-load-languages '((screen . t))) (url-handler-mode 1) (find-file u) (write-file p) (chmod p #o755) (find-file p) (org-sbe workflow))" https://raw.githubusercontent.com/tgbugs/dockerfiles/master/source.org ~/git/dockerfiles/source.org
docker run -v /var/run/docker.sock:/var/run/docker.sock -u ${UID} -it tgbugs/other:alpine-bootstrap
docker build \
--network host \
--add-host local.binhost:127.0.0.1 \
--build-arg DUID=$(getent group docker | cut -d: -f3) \
--tag tgbugs/other:alpine-bootstrap \
--file other/alpine-bootstrap/Dockerfile other/alpine-bootstrap
FROM alpine:latest

ARG DUID=48

RUN  \
addgroup -g ${DUID} docker

RUN \
apk add bash docker emacs-nox git screen

ARG UID=1000
ARG USER_NAME=user

RUN \
addgroup -g ${UID} ${USER_NAME} \
&& adduser -HD -u ${UID} -G ${USER_NAME} ${USER_NAME} \
&& adduser ${USER_NAME} docker

USER $USER_NAME

WORKDIR /home/${USER_NAME}

RUN \
git clone https://github.com/tgbugs/dockerfiles.git

RUN \
dockerfiles/source.org setup

# RUN \
# mkdir -p ~/files/binpkgs/multi

ubuntu-genera-base

file

FROM ubuntu:18.04

RUN apt update

RUN apt install -y \
curl \
inetutils-inetd \
vim \
telnet \
nfs-common \
nfs-kernel-server \
iproute2 \
libx11-6 \
xserver-xephyr \
x11-xserver-utils \
iputils-ping

build

docker build \
--tag tgbugs/other:ubuntu-genera-base \
--file other/ubuntu-genera-base/Dockerfile other/ubuntu-genera-base

genera

A docker file that specifies and image that can run Open Genera 2.0.

We can't distribute the final image for a variety of reasons, however the configured base image can be distributed and is a valuable resource as a result.

Useful as a starting point for debugging why it won't work on other systems.

Nearly everything is working except that docker and NFS exports seem to be fighting with each other. Old comments on the web mention issues with exporting overlayfs mounts to NFS, but this commit from 2017 https://patchwork.kernel.org/project/linux-fsdevel/patch/1508258671-10800-15-git-send-email-amir73il@gmail.com/ seems to have fixed that issue.

Three entry points. https://www.reddit.com/r/lisp/comments/lhsltk/lisp_implementations_similiar_to_old_lisp_machines/ https://gist.github.com/oubiwann/1e7aadfc22e3ae908921aeaccf27e82d https://archives.loomcom.com/genera/genera-install.html

exploration

This will eventually become a docker file, but right now it is still too experimental so the workflow is run and commit rather than build.

xhost local:docker

# NET_ADMIN apparently needed for tuntap creation (bsd jails and vnets looking really good right now)
# SYS_ADMIN apparently needed to get NFS exports to work (bsd jails looking even better!?)
# generally though this is ok because we are really only using this docker image as a way to get
# an environment where genera will run

docker run -it \
-v ~/files/tmp/genera:/files \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
--device /dev/net/tun \
--cap-add NET_ADMIN \
--cap-add SYS_ADMIN \
tgbugs/other:ubuntu-genera-base

In the docker shell (will become the docker file or a script run in the docker file)

#mkdir -p /dev/net
#mknod /dev/net/tun c 10 200

# tunnel creation
# ip tuntap delete dev tap0 mode tap  # to remove since it fights with the host
ip tuntap add dev tap0 mode tap
ip addr add 192.168.2.1/24 dev tap0
ip link set dev tap0 up

# inetd

echo "time      stream  tcp  nowait root internal" >> /etc/inetd.conf
echo "time      dgram   udp  wait   root internal" >> /etc/inetd.conf
echo "daytime   stream  tcp  nowait root internal" >> /etc/inetd.conf
echo "daytime   dgram   udp  wait   root internal" >> /etc/inetd.conf

service inetutils-inetd restart

# retrieve genera files TODO snapshot these to reduce redownload

mkdir genera
pushd genera
curl -LO https://archives.loomcom.com/genera/genera
chmod a+x genera
curl -L -O https://archives.loomcom.com/genera/worlds/Genera-8-5-xlib-patched.vlod
curl -L -O https://archives.loomcom.com/genera/worlds/VLM_debugger
curl -L -O https://archives.loomcom.com/genera/worlds/dot.VLM
mv dot.VLM .VLM
mkdir lib
pushd lib
curl -L -O https://archives.loomcom.com/genera/var_lib_symbolics.tar.gz
tar xvf var_lib_symbolics.tar.gz
chown -R root:root symbolics
ln -s /genera/lib/symbolics /var/lib/symbolics  # may fail
popd

sed -i 's,/home/seth,,' .VLM
echo "192.168.2.1    genera-vlm" >> /etc/hosts
echo "192.168.2.2    genera" >> /etc/hosts

# nfs XXX TODO broken

echo 'RPCNFSDCOUNT="--nfs-version 2 8"' >> /etc/default/nfs-kernel-server
echo 'RPCMOUNTDOPTS="--nfs-version 2 --manage-gids"' >> /etc/default/nfs-kernel-server
echo "/files genera(rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000)" >> /etc/exports
# we really want to export / but I'm seeing the following error
# exportfs: / does not support NFS export
#echo "/ genera(rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000)" >> /etc/exports

# I think rpcbind needs be be started, otherwise nfs-kernel-server may fail to start
# and/or NFS will not work at all
service rpcbind start

service nfs-kernel-server restart

# start genera using host X server

DISPLAY=:0.0; ./genera -coldloadgeometry 640x480+0+0 -geometry 1280x1024+0+0 &

# start genera using Xephyr (a bit more stable/predictable)

DISPLAY=:0.0; Xephyr -br -reset -terminate -ac -noreset -screen 1280x1024 :3 &
DISPLAY=:3.0; ./genera -coldloadgeometry 640x480+0+0 -geometry 1280x1024+0+0 &

sckan

base must be built before services, obvious from errors or from reading the docker files but doesn't jump out and is the inverse of the order of specification (because services is rebuilt more frequently).

save

To save a gzipped archive run

# first run the following to find the latest build, then
docker image ls tgbugs/sckan:data-*
_datetime=$(docker image ls tgbugs/sckan:data-* | sort | tail -n 1 | awk '{ print $2 }')
docker save tgbugs/sckan:${_datetime} | gzip > /tmp/docker-sckan-${_datetime}.tar.gz

To restore from the archive run

docker load --input sckan-data-2021-09-30T232453Z.tar.gz

services

This combines the raw (data) base image with prefixes.conf and services.yaml. Note that the image names for these are shifted so that they don't confuse users. The logic is that base + services = data, but users don't know anything about services.

container

Test this with tgbugs/musl:kg-release-user

docker container inspect sckan-data > /dev/null && \
docker rm sckan-data
docker create -v /var/lib/blazegraph -v /var/lib/scigraph --name sckan-data tgbugs/sckan:latest /bin/true

build

mkdir -p ./sckan/services/blazegraph

[ -d ./sckan/services/scigraph ] && rm -r ./sckan/services/scigraph
mkdir -p ./sckan/services/scigraph

pushd ./sckan/services

# blazegraph
_sckanl="$(ls -d /tmp/build/release-*-sckan | sort -u | tail -n 1)"
rsync -a ${_sckanl}/data/prefixes.conf blazegraph/

# scigraph
~/git/pyontutils/nifstd/scigraph/bin/run-build-services-sparc
rsync -a /tmp/scigraph-build/sparc/services.yaml scigraph/
rsync -a /tmp/scigraph-build/sparc/$(head -n 1 scigraph/services.yaml | cut -b3-) scigraph/

popd

docker build \
--tag tgbugs/sckan:data-$(date --utc +%Y-%m-%dT%H%M%SZ) \
--tag tgbugs/sckan:latest \
--file sckan/services/Dockerfile sckan/services

file

FROM busybox:latest as builder

WORKDIR /build

ADD --chown=834:834 blazegraph/ /build/var/lib/blazegraph
ADD --chown=835:835 scigraph/ /build/var/lib/scigraph

FROM tgbugs/sckan:base-latest
COPY --from=builder /build /

base

build

mkdir -p ./sckan/base/blazegraph

[ -d ./sckan/base/scigraph ] && rm -r ./sckan/base/scigraph
mkdir -p ./sckan/base/scigraph

pushd ./sckan/base

_sckanl="$(ls -d /tmp/build/release-*-sckan | sort -u | tail -n 1)"
rsync -a ${_sckanl}/data/blazegraph.jnl blazegraph/

# TODO run-load-graph-sparc-sckan
_zip=$(realpath /tmp/scigraph-build/sparc-sckan/LATEST)
_path="${_zip%.*}"
_scigr="${_path##*/}"
rsync -a ${_path} scigraph/
ln -s /var/lib/scigraph/${_scigr} scigraph/graph

popd

docker build \
--tag tgbugs/sckan:base-$(date --utc +%Y-%m-%dT%H%M%SZ) \
--tag tgbugs/sckan:base-latest \
--file sckan/base/Dockerfile sckan/base

file

FROM busybox:latest as builder

WORKDIR /build

ADD --chown=834:834 blazegraph/ /build/var/lib/blazegraph
ADD --chown=835:835 scigraph/ /build/var/lib/scigraph

FROM scratch
COPY --from=builder /build /

Footnotes:

Date: 2022-12-05T16:34:14-08:00

Author: Tom Gillespie

Created: 2022-12-22 Thu 01:38

Validate