Files
IfcOpenShell/docker
Stephen Boddy 316dace11a Harden docker build tooling: non-root, clean lifecycle, try()
Dockerfile (renamed from Dockerfile_init, Dockerfile_update removed):
- Run as a non-root `builder` user matching the host UID/GID (passed as
  --build-arg by create() from id -u/id -g), so build output under the
  bind mount stays owned by the host user instead of root.
- Fix CCACHE_MAXSIZE: `ccache -M 5G` wrote its limit to a config file
  under /ccache at image-build time, but /ccache is a volume mount
  point, so that file gets shadowed by the (empty) volume the moment
  the container actually runs - the cap never took effect. Set
  CCACHE_MAXSIZE=5G as an image ENV instead.
- Dedupe ccache/libffi-devel, add --setopt=install_weak_deps=False
  --setopt=tsflags=nodocs, add `git lfs install --system`, combine the
  dnf update+install into one layer.
- Drop Dockerfile_update: it built FROM its own previous output, so
  every `update` call made the image strictly larger forever (Docker
  layers are append-only, `dnf clean` in a later layer can't shrink an
  earlier one). `update` now just calls create(), which already runs
  `dnf update -y` FROM a clean rockylinux:9 every time.

compose.yaml: pin platform: linux/amd64 so this doesn't silently run
under emulation on an ARM host.

ifcos_env:
- Split the previously-conflated stop/down into six distinct,
  Compose-native lifecycle commands: up (create-or-start), down
  (remove), stop, start, restart (stop+start, same container),
  recreate (down+up, fresh container). Previously `stop` was aliased
  to `down`, which silently removed the container instead of pausing
  it.
- Implement try(): copies the built wrapper into a real Blender/Bonsai
  install for manual testing, reading the target from a new
  BLENDER_USER_RESOURCE .env variable and auto-detecting the built
  Python version (disambiguating via PY_TGT for multi-version builds).
  Deliberately kept human-only - it mutates a live Blender install, so
  it shouldn't run unattended as part of an automated/AI workflow,
  which should instead copy the wrapper into the repo's own
  src/ifcopenshell-python/ifcopenshell/ (documented in SKILL.md).
- Fix unique(): the "has .env already got a UNIQUE_ID line" check
  referenced an unset $FILE instead of $ENV_FILE, so it always
  evaluated true and appended a fresh "UNIQUE_ID=dummy" line to .env
  on every single `up`.
- Minor: differentiate remove()'s log message from down()'s (no longer
  identical now that they're distinct operations), tidy help text
  alignment and a stray double-space typo in clean().

SKILL.md: rewritten as current-state documentation (no more "fixed in
this copy" changelog framing) covering the above, plus a migration
note for anyone hitting root-owned leftovers from an older image.

Verified by actually building the image and driving every new
lifecycle command (stop/start/restart keep the same container ID;
down+up and recreate produce a new one) and try() (including the
quoted-tilde BLENDER_USER_RESOURCE edge case) against the real container.

Generated with the assistance of an AI coding tool.

(cherry picked from commit 92c50ed3b4)
2026-07-25 23:15:23 +10:00
..
2026-07-25 23:15:23 +10:00
2026-07-25 23:15:23 +10:00

Docker build environment

This is a small utility to make it easy to compile a perfect _ifcopenshell_wrapper.cpython-*-x86_64-linux-gnu.so files.

The reason for this tool is that I was trying to follow the web page directions, and my build was behaving differently to the release builds. Eventually I concluded that the differences between toolchains on the RHEL based rocky9 image and Ubuntu were just too great. Getting the build setup was already a lot of trial and error, so I thought I'd spend more time trying to reuse the github actions that perform the build, using a utility called act. I learnt a lot, in particular how much time, energy, and bandwidth Github waste. I also realised I was most of the way to a regular docker setup anyway, so I might as well just do that. So I've deconstructed all the github action steps, and turned it into a local docker build environment that uses the exact same base, tools, libraries, and build command/flags etc.

Right now a Github action will:

  • launch the rocky9 base
  • upgrade all the packages
  • install a bunch of extra tools
  • do a recursive checkout of your repo
  • checkout the build repository
  • unpack dependencies
  • run the build script, making all python versions (5? right now I think)
  • create the .zip release files

And it does all of that every time. This is not a fault of the action writers - it's just how Github seems to work.

These dockers tools do the following differently, and it's actually a bit more powerful too:

  • build the base image once.
  • update the packages once.
  • install the extra tools once.
  • the repository is the one on your host, that gets bind mounted in the container as the working directory.
  • by adding an environment variable to .env, restricts to compiling for just a single python version.
  • when the build is finished the created files are right there under your local repositry (but not added to git) for ease of access
  • each repository can have it's own build environment container.
  • the image is shared between those environments.
  • the containers share the ccache, so additional envs should get a helping hand.
  • it has a simple set of user friendly commands to drive it all.

For example:

# To see the commands (a superset of docker compose commands)
./ifcos_env

# Enable autocomplete of commands
source .ifcos_env

# First time commands
./ifcos_env create
./ifcos_env up
./ifcos_env build

# install and test library
# find an issue
# edit code
./ifcos_env build

# and so on. When done stop and optionally delete the container
./ifcos_env stop
./ifcos_env remove

To limit the build to one python version just add

PY_TGT=py-311

or whichever version your Blender requires.

You might see UNIQUE_ID in the .env file too. This keeps containers for separate folders, separate.

System requirements

  1. Linux-x64 only at this time.
  2. Docker and docker-compose need to be installed.
  3. Have a good amount of disk space. (image is in /var (typically the root partition) and will be about 1.7 GB)
  4. The build action will create about 10GB in your repository folder. Make sure this partition is spacious particularly if you intent on having multiple clones building.
  5. ... I think that covers most of it.