From c93f3f3105f49170dd909662f2c5c06bf5d3d33e Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Mon, 27 Oct 2025 16:15:46 +0000 Subject: [PATCH 01/13] build(devcontainer): add development container setup Add a complete devcontainer environment for building and testing darktable, including Dockerfile with all dependencies, configuration, and documentation. Also update .gitignore to exclude AppDir for AppImage builds. --- .devcontainer/Dockerfile | 76 ++++++++++++++ .devcontainer/README.md | 169 ++++++++++++++++++++++++++++++++ .devcontainer/devcontainer.json | 33 +++++++ .gitignore | 1 + 4 files changed, 279 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/README.md create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..150e13b60c8 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,76 @@ +# Use Ubuntu 24.04 LTS as base image +FROM ubuntu:24.04 + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Set up locale +RUN apt-get update && apt-get install -y locales && \ + locale-gen en_US.UTF-8 && \ + update-locale LANG=en_US.UTF-8 + +ENV LANG=en_US.UTF-8 +ENV LANGUAGE=en_US:en +ENV LC_ALL=en_US.UTF-8 + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + # Build tools + build-essential \ + cmake \ + git \ + ninja-build \ + pkg-config \ + intltool \ + gettext \ + po4a \ + xsltproc \ + libxml2-utils \ + python3-jsonschema \ + # Required dependencies + libgtk-3-dev \ + libglib2.0-dev \ + libsqlite3-dev \ + libcurl4-openssl-dev \ + libpng-dev \ + libexiv2-dev \ + libpugixml-dev \ + liblensfun-dev \ + libjpeg-dev \ + libtiff-dev \ + liblcms2-dev \ + librsvg2-dev \ + libjson-glib-dev \ + # Optional dependencies for full functionality + libomp-dev \ + llvm-dev \ + ocl-icd-opencl-dev \ + liblua5.4-dev \ + libgphoto2-dev \ + libimath-dev \ + libavif-dev \ + libheif-dev \ + libjxl-dev \ + libwebp-dev \ + libcolord-dev \ + libportmidi-dev \ + libsdl2-dev \ + libcups2-dev \ + libopenexr-dev \ + libopenjp2-7-dev \ + libgraphicsmagick1-dev \ + # Additional tools + clang-format \ + vim \ + nano \ + wget \ + curl \ + sudo \ + # AppImage building tools + desktop-file-utils \ + && rm -rf /var/lib/apt/lists/* + +# Set the working directory +WORKDIR /workspace + +CMD ["/bin/bash"] diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 00000000000..6e50055bedd --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,169 @@ +# Darktable Development Container + +A complete development environment for building and testing darktable with all dependencies pre-installed. + +## Purpose + +This devcontainer provides: +- ✅ Build darktable from source +- ✅ Create AppImage for GUI testing on host +- ✅ Debug with GDB +- ❌ Does NOT run GUI inside container (use AppImage on host) + +## Prerequisites + +- [Docker](https://www.docker.com/products/docker-desktop/) +- [Visual Studio Code](https://code.visualstudio.com/) with [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +## Quick Start + +1. Open this repository in VS Code +2. Click "Reopen in Container" when prompted (or F1 → "Dev Containers: Reopen in Container") +3. Wait for container build (~5-10 minutes first time) +4. Git submodules are initialized automatically +5. You're ready to build! + +## Building Darktable + +### Basic Build (for development) + +```bash +# Build darktable (binaries in ./build/bin/) +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo + +# Run from build directory +./build/bin/darktable --version +``` + +### Build with Debug Symbols + +```bash +./build.sh --prefix /tmp/dt --build-type Debug +``` + +### Clean Build + +```bash +rm -rf build +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo +``` + +## Testing + +### GUI Testing with AppImage + +GUI testing requires building an AppImage and running it on your host system: + +```bash +# 1. Create lensfun directory (avoids warnings) +sudo mkdir -p /var/lib/lensfun-updates + +# 2. Build AppImage (takes ~10-15 minutes) +APPIMAGE_EXTRACT_AND_RUN=1 ./tools/appimage-build-script.sh + +# 3. The AppImage is created in: build/Darktable-*.AppImage +``` + +**To run on your host:** + +```bash +# From host terminal (not in container) +# If workspace is mounted, the AppImage is accessible at: +cd /build + +# Make executable and run +chmod +x Darktable-*.AppImage +./Darktable-*.AppImage --configdir ~/.config/darktable-test +``` + +**Using `--configdir`** creates a separate configuration to avoid conflicts with your production darktable installation. + +## Development Tools Included + +- **Compilers:** GCC 13, Clang +- **Build Systems:** CMake, Ninja, Make +- **Libraries:** GTK3, GLib, SQLite, libcurl, Exiv2, libavif, libheif, libjxl, WebP, and more +- **VS Code Extensions:** C/C++ tools, CMake Tools, clang-format +- **Editors:** vim, nano + +## Troubleshooting + +### Build fails with missing dependencies + +```bash +# Rebuild the container +# F1 → "Dev Containers: Rebuild Container" +``` + +### Git submodules not initialized + +```bash +git submodule init && git submodule update +``` + +### AppImage build fails with FUSE error + +Always use the environment variable: +```bash +APPIMAGE_EXTRACT_AND_RUN=1 ./tools/appimage-build-script.sh +``` + +### Need to install additional packages + +```bash +sudo apt-get update +sudo apt-get install +``` + +### Want to enable unit tests? + +Tests are disabled by default and require additional dependencies. To enable: + +```bash +# Install test framework +sudo apt-get install -y libcmocka-dev + +# Build with tests enabled +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -- -DBUILD_TESTING=ON + +# Run tests +cd build && ctest +``` + +## File Structure + +``` +.devcontainer/ +├── devcontainer.json # Container configuration +├── Dockerfile # Environment setup with all build dependencies +└── README.md # This file +``` + +## Build Options Reference + +```bash +# Build types +--build-type Release # Optimized, no debug info +--build-type Debug # Debug symbols, no optimization +--build-type RelWithDebInfo # Optimized + debug symbols (recommended) + +# Parallel jobs +-j N # Use N parallel jobs (default: all CPUs) + +# Installation +--prefix # Set installation prefix (not required for development) +--install # Actually install files (not recommended in container) +``` + +## Notes + +- Workspace folder mounted at `/workspaces/darktable` +- Build artifacts go to `build/` directory +- Container runs as user `vscode` (UID 1000) +- Git submodules initialized automatically on container creation + +## Resources + +- [Darktable Build Instructions](https://github.com/darktable-org/darktable#building) +- [Developer's Guide](https://github.com/darktable-org/darktable/wiki/Developer's-guide) +- [User Manual](https://docs.darktable.org/) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..a1060bda90d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,33 @@ +{ + "name": "Darktable Development", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt=seccomp=unconfined" + ], + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "username": "vscode" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools", + "xaver.clang-format", + "ms-vscode.cpptools-extension-pack" + ], + "settings": { + "cmake.configureOnOpen": false, + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" + } + } + }, + "forwardPorts": [], + "postCreateCommand": "git submodule init && git submodule update && echo 'Development environment ready! See .devcontainer/README.md for build instructions.'", + "remoteUser": "vscode" +} diff --git a/.gitignore b/.gitignore index 97143fbec46..8582dca57be 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ CMakeLists.txt.user workspace/ cmake-build-debug/ .idea/ +AppDir/ From 8582a3bf74e58690e4ad88b73b8872c39e322e9f Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Fri, 13 Mar 2026 07:33:37 +0000 Subject: [PATCH 02/13] Remove apt cache in the container Co-authored-by: Philipp Lutz <810285+da-phil@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 150e13b60c8..747345d20be 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -68,7 +68,7 @@ RUN apt-get update && apt-get install -y \ sudo \ # AppImage building tools desktop-file-utils \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apt/archives/* # Set the working directory WORKDIR /workspace From 3dc0a80f24ad2b01bc620d0b5735498746bf2a20 Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sat, 15 Aug 2026 11:41:17 +0000 Subject: [PATCH 03/13] Add devcontainer-lock.json for common-utils feature configuration --- .devcontainer/devcontainer-lock.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .devcontainer/devcontainer-lock.json diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 00000000000..b6f196a724a --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,9 @@ +{ + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "version": "2.5.9", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a", + "integrity": "sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a" + } + } +} From 4eca62ac3a9dc855d934a94bdb95016c86dbb4ff Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sat, 15 Aug 2026 16:04:06 +0000 Subject: [PATCH 04/13] Add additional dependencies for image processing and tools in Dockerfile --- .devcontainer/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 747345d20be..206663ea0fb 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -33,6 +33,8 @@ RUN apt-get update && apt-get install -y \ libsqlite3-dev \ libcurl4-openssl-dev \ libpng-dev \ + libpotrace-dev \ + libgmic-dev \ libexiv2-dev \ libpugixml-dev \ liblensfun-dev \ @@ -59,6 +61,7 @@ RUN apt-get update && apt-get install -y \ libopenexr-dev \ libopenjp2-7-dev \ libgraphicsmagick1-dev \ + iso-codes \ # Additional tools clang-format \ vim \ From f6d62f37e83d4fa50bee0819b3424b41b53cf574 Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sat, 15 Aug 2026 17:25:30 +0000 Subject: [PATCH 05/13] Align development container with CI environment by updating base image to Ubuntu 26.04 and installing matching packages. Enhance README with compiler details and CI alignment information. --- .devcontainer/Dockerfile | 131 +++++++++++++++++++++++++-------------- .devcontainer/README.md | 30 ++++++--- 2 files changed, 103 insertions(+), 58 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 206663ea0fb..08e437263a4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,6 @@ -# Use Ubuntu 24.04 LTS as base image -FROM ubuntu:24.04 +# Use Ubuntu 26.04 LTS to match the CI environment +# CI uses ubuntu:26.04 container in .github/workflows/ci.yml +FROM ubuntu:26.04 # Avoid prompts from apt ENV DEBIAN_FRONTEND=noninteractive @@ -7,71 +8,105 @@ ENV DEBIAN_FRONTEND=noninteractive # Set up locale RUN apt-get update && apt-get install -y locales && \ locale-gen en_US.UTF-8 && \ - update-locale LANG=en_US.UTF-8 + update-locale LANG=en_US.UTF-8 && \ + rm -rf /var/lib/apt/lists/* ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 -# Install build dependencies +# Install compilers matching CI: +# - Primary: GNU16 (gcc-16 / g++-16) +# - Alternative: LLVM22 (clang-22 / clang++-22) +RUN apt-get update && apt-get install -y \ + gcc-16 \ + g++-16 \ + clang-22 \ + libomp-22-dev \ + llvm-22-dev \ + libc++-22-dev \ + libc++abi1 \ + lld-22 \ + clang-tools-22 \ + mlir-22-tools \ + libmlir-22-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install base dependencies — exact match with CI +# (see "Install Base Dependencies" step in .github/workflows/ci.yml) RUN apt-get update && apt-get install -y \ - # Build tools build-essential \ cmake \ + appstream-util \ + desktop-file-utils \ + gettext \ git \ - ninja-build \ - pkg-config \ + gdb \ intltool \ - gettext \ - po4a \ - xsltproc \ - libxml2-utils \ - python3-jsonschema \ - # Required dependencies - libgtk-3-dev \ + libarchive-dev \ + libatk1.0-dev \ + libavif-dev \ + libcairo2-dev \ + libcmocka-dev \ + libcolord-dev \ + libcolord-gtk-dev \ + libcups2-dev \ + libcurl4-gnutls-dev \ + libexiv2-dev \ + libgdk-pixbuf-2.0-dev \ libglib2.0-dev \ - libsqlite3-dev \ - libcurl4-openssl-dev \ - libpng-dev \ - libpotrace-dev \ libgmic-dev \ - libexiv2-dev \ - libpugixml-dev \ - liblensfun-dev \ + libgphoto2-dev \ + libgraphicsmagick1-dev \ + libgtk-3-dev \ + libheif-dev \ libjpeg-dev \ - libtiff-dev \ - liblcms2-dev \ - librsvg2-dev \ libjson-glib-dev \ - # Optional dependencies for full functionality - libomp-dev \ - llvm-dev \ - ocl-icd-opencl-dev \ + liblcms2-dev \ + liblensfun-dev \ liblua5.4-dev \ - libgphoto2-dev \ - libimath-dev \ - libavif-dev \ - libheif-dev \ - libjxl-dev \ - libwebp-dev \ - libcolord-dev \ - libportmidi-dev \ - libsdl2-dev \ - libcups2-dev \ + libonnxruntime-dev \ libopenexr-dev \ libopenjp2-7-dev \ - libgraphicsmagick1-dev \ - iso-codes \ - # Additional tools - clang-format \ + libosmgpsmap-1.0-dev \ + libpango1.0-dev \ + libpng-dev \ + libportmidi-dev \ + libpotrace-dev \ + libpugixml-dev \ + libraw-dev \ + librsvg2-dev \ + libsaxon-java \ + libsdl2-dev \ + libsecret-1-dev \ + libsqlite3-dev \ + libtiff5-dev \ + libwebp-dev \ + libx11-dev \ + libxml2-dev \ + libxml2-utils \ + ninja-build \ + perl \ + po4a \ + python3-jsonschema \ + xsltproc \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install additional packages for development (not required by CI) +RUN apt-get update && apt-get install -y \ + # OpenCL support (optional GPU acceleration) + ocl-icd-opencl-dev \ + # JXL image format (available on other platforms in CI) + libjxl-dev \ + # Development conveniences + clang-format-22 \ + sudo \ + curl \ + wget \ vim \ nano \ - wget \ - curl \ - sudo \ - # AppImage building tools - desktop-file-utils \ - && rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apt/archives/* + && rm -rf /var/lib/apt/lists/* # Set the working directory WORKDIR /workspace diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 6e50055bedd..95058395d9d 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -78,11 +78,26 @@ chmod +x Darktable-*.AppImage **Using `--configdir`** creates a separate configuration to avoid conflicts with your production darktable installation. +## CI Environment Alignment + +This container uses `ubuntu:26.04` and the **exact same packages** installed by the CI workflow +(`.github/workflows/ci.yml`), so builds here are directly comparable to CI results. + +Compilers available (matching CI): +- **Primary:** GCC 16 (`gcc-16` / `g++-16`) — default CI compiler +- **Alternative:** Clang 22 (`clang-22` / `clang++-22`) + +To switch compilers: +```bash +export CC=clang-22 CXX=clang++-22 +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo +``` + ## Development Tools Included -- **Compilers:** GCC 13, Clang -- **Build Systems:** CMake, Ninja, Make -- **Libraries:** GTK3, GLib, SQLite, libcurl, Exiv2, libavif, libheif, libjxl, WebP, and more +- **Compilers:** GCC 16, Clang 22 +- **Build Systems:** CMake, Ninja +- **Libraries:** GTK3, GLib, SQLite, libcurl, Exiv2, libavif, libheif, libjxl, WebP, ONNX Runtime, and more - **VS Code Extensions:** C/C++ tools, CMake Tools, clang-format - **Editors:** vim, nano @@ -115,15 +130,10 @@ sudo apt-get update sudo apt-get install ``` -### Want to enable unit tests? - -Tests are disabled by default and require additional dependencies. To enable: +### Want to run unit tests? ```bash -# Install test framework -sudo apt-get install -y libcmocka-dev - -# Build with tests enabled +# Build with tests enabled (libcmocka-dev is already installed) ./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -- -DBUILD_TESTING=ON # Run tests From a9019c52b4d84371fadd3aacbe85393a43357656 Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sat, 15 Aug 2026 23:00:30 +0000 Subject: [PATCH 06/13] Update README to clarify devcontainer purpose and prerequisites, enhancing compatibility details for various IDEs. --- .devcontainer/README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 95058395d9d..5795f882a78 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -5,23 +5,39 @@ A complete development environment for building and testing darktable with all d ## Purpose This devcontainer provides: -- ✅ Build darktable from source +- ✅ Build darktable from source in an environment **identical to the CI compile check** (`ubuntu:26.04`, GCC 16 / Clang 22) - ✅ Create AppImage for GUI testing on host - ✅ Debug with GDB +- ✅ Sandbox AI coding agents so they cannot access host SSH keys, credentials, or private files - ❌ Does NOT run GUI inside container (use AppImage on host) ## Prerequisites -- [Docker](https://www.docker.com/products/docker-desktop/) -- [Visual Studio Code](https://code.visualstudio.com/) with [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +- [Docker](https://www.docker.com/products/docker-desktop/) (or any OCI-compatible runtime) +- Any [Dev Container-compatible tool](https://containers.dev/supporting): + - VS Code with [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + - JetBrains IDEs (CLion, IntelliJ, etc.) via Dev Containers plugin + - Neovim / other editors via [devcontainer CLI](https://github.com/devcontainers/cli) + - Plain terminal: `devcontainer up --workspace-folder .` ## Quick Start +### VS Code + 1. Open this repository in VS Code 2. Click "Reopen in Container" when prompted (or F1 → "Dev Containers: Reopen in Container") 3. Wait for container build (~5-10 minutes first time) 4. Git submodules are initialized automatically -5. You're ready to build! + +### Terminal / other IDEs + +```bash +# Build and start the container +devcontainer up --workspace-folder . + +# Open a shell inside it +devcontainer exec --workspace-folder . bash +``` ## Building Darktable From a9123e5448f2df91aa3e8f3ad747825d8c9d70a2 Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sun, 16 Aug 2026 08:59:57 +0000 Subject: [PATCH 07/13] Remove clang-format extension from VSCode settings in devcontainer configuration --- .devcontainer/devcontainer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a1060bda90d..e7d3730d53b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,7 +18,6 @@ "extensions": [ "ms-vscode.cpptools", "ms-vscode.cmake-tools", - "xaver.clang-format", "ms-vscode.cpptools-extension-pack" ], "settings": { From 9ae218998e76214596232c173e83f7e502f0ab55 Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sun, 16 Aug 2026 13:42:55 +0000 Subject: [PATCH 08/13] Rewrite dev container README, reference container-based build environment for contributors in the main README --- .devcontainer/README.md | 233 ++++++++++++++++++---------------------- README.md | 2 + 2 files changed, 108 insertions(+), 127 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 5795f882a78..15c869d48f2 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -1,195 +1,174 @@ -# Darktable Development Container +# Darktable Container Build Environment -A complete development environment for building and testing darktable with all dependencies pre-installed. +A Docker/Podman image that **exactly mirrors the CI compile check** (ubuntu:26.04, +GCC 16 / Clang 22) with all build dependencies pre-installed. -## Purpose +This is an **optional** complement to building natively. Every contributor can +continue building in their own environment as before. It exists for those who find +it useful — see [Use cases](#use-cases) below. -This devcontainer provides: -- ✅ Build darktable from source in an environment **identical to the CI compile check** (`ubuntu:26.04`, GCC 16 / Clang 22) -- ✅ Create AppImage for GUI testing on host -- ✅ Debug with GDB -- ✅ Sandbox AI coding agents so they cannot access host SSH keys, credentials, or private files -- ❌ Does NOT run GUI inside container (use AppImage on host) +## Use cases -## Prerequisites +- **Immutable/atomic Linux** (Fedora Silverblue, NixOS, SteamOS, etc.): avoids + installing and layering 50+ packages on the host system that break on weekly OS rebuilds. +- **Infrequent contributors**: get a working build environment without permanent setup. +- **Reproducing CI failures**: your local environment matches the CI container exactly, + so a build that passes here passes CI. +- **Sandboxing AI coding agents**: tools running inside the container can only access + the mounted workspace — host SSH keys, credentials, private documents, and other + projects are not visible to them. -- [Docker](https://www.docker.com/products/docker-desktop/) (or any OCI-compatible runtime) -- Any [Dev Container-compatible tool](https://containers.dev/supporting): - - VS Code with [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) - - JetBrains IDEs (CLion, IntelliJ, etc.) via Dev Containers plugin - - Neovim / other editors via [devcontainer CLI](https://github.com/devcontainers/cli) - - Plain terminal: `devcontainer up --workspace-folder .` +## Usage tiers -## Quick Start +| Tier | Requirements | Good for | +| ---- | ------------ | -------- | +| [Docker/Podman CLI](#tier-1-dockerpodman-cli-only) | Docker or Podman | Verify build, create AppImage — no IDE needed | +| [devcontainer CLI](#tier-2-devcontainer-cli-terminal) | Docker + `devcontainer` CLI | Full development from a terminal | +| [IDE integration](#tier-3-ide-integration) | Docker + any Dev Container-capable IDE | Full development with editor | -### VS Code +## Tier 1: Docker/Podman CLI only -1. Open this repository in VS Code -2. Click "Reopen in Container" when prompted (or F1 → "Dev Containers: Reopen in Container") -3. Wait for container build (~5-10 minutes first time) -4. Git submodules are initialized automatically +The most lightweight option. No IDE, no extra tooling. -### Terminal / other IDEs +```bash +# Build the image once (from the repository root) +docker build -t darktable-dev -f .devcontainer/Dockerfile . + +# Verify the build compiles cleanly (same environment as CI) +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$PWD":/workspace -w /workspace \ + darktable-dev bash -lc './build.sh --prefix /tmp/dt --build-type Release' + +# Build an AppImage for GUI testing on the host +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$PWD":/workspace -w /workspace \ + -e APPIMAGE_EXTRACT_AND_RUN=1 \ + darktable-dev bash -lc './tools/appimage-build-script.sh' +``` + +The AppImage appears in `build/Darktable-*.AppImage` and can be run directly on the host. + +> Replace `docker` with `podman` if you use Podman. + +## Tier 2: devcontainer CLI (terminal) ```bash -# Build and start the container +# Start the container devcontainer up --workspace-folder . # Open a shell inside it devcontainer exec --workspace-folder . bash ``` -## Building Darktable +Then build as usual (see [Building](#building)). -### Basic Build (for development) +## Tier 3: IDE integration -```bash -# Build darktable (binaries in ./build/bin/) -./build.sh --prefix /tmp/dt --build-type RelWithDebInfo +The container follows the open [Dev Container specification](https://containers.dev/) +and works with any supporting tool: -# Run from build directory -./build/bin/darktable --version -``` +- **VS Code** — Dev Containers extension → "Reopen in Container" +- **JetBrains IDEs** (CLion, etc.) — Dev Containers plugin +- **Neovim / other editors** — via `devcontainer` CLI above + +The [VS Code extensions listed in `devcontainer.json`](devcontainer.json) are all +from Microsoft (`ms-vscode.*`) or well-established publishers. -### Build with Debug Symbols +## Building ```bash -./build.sh --prefix /tmp/dt --build-type Debug -``` +# Standard development build +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -### Clean Build +# Debug build +./build.sh --prefix /tmp/dt --build-type Debug -```bash -rm -rf build +# Use Clang 22 instead of GCC 16 (matches CI LLVM22 path) +export CC=clang-22 CXX=clang++-22 ./build.sh --prefix /tmp/dt --build-type RelWithDebInfo ``` -## Testing +## Testing with AppImage -### GUI Testing with AppImage - -GUI testing requires building an AppImage and running it on your host system: +The container has no display, so GUI testing uses an AppImage run on the host. ```bash -# 1. Create lensfun directory (avoids warnings) -sudo mkdir -p /var/lib/lensfun-updates - -# 2. Build AppImage (takes ~10-15 minutes) +# Build the AppImage +# APPIMAGE_EXTRACT_AND_RUN=1 is required inside any Docker/devcontainer (no FUSE) APPIMAGE_EXTRACT_AND_RUN=1 ./tools/appimage-build-script.sh - -# 3. The AppImage is created in: build/Darktable-*.AppImage ``` -**To run on your host:** +The AppImage is created in `build/Darktable-*.AppImage`. + +**Run on the host** (outside the container): ```bash -# From host terminal (not in container) -# If workspace is mounted, the AppImage is accessible at: -cd /build +chmod +x build/Darktable-*.AppImage -# Make executable and run -chmod +x Darktable-*.AppImage -./Darktable-*.AppImage --configdir ~/.config/darktable-test +# Use a separate config dir to avoid affecting your production darktable +./build/Darktable-*.AppImage --configdir ~/.config/darktable-test ``` -**Using `--configdir`** creates a separate configuration to avoid conflicts with your production darktable installation. - -## CI Environment Alignment - -This container uses `ubuntu:26.04` and the **exact same packages** installed by the CI workflow -(`.github/workflows/ci.yml`), so builds here are directly comparable to CI results. +## Running unit tests -Compilers available (matching CI): -- **Primary:** GCC 16 (`gcc-16` / `g++-16`) — default CI compiler -- **Alternative:** Clang 22 (`clang-22` / `clang++-22`) +`libcmocka-dev` is already installed: -To switch compilers: ```bash -export CC=clang-22 CXX=clang++-22 -./build.sh --prefix /tmp/dt --build-type RelWithDebInfo +./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -- -DBUILD_TESTING=ON +cd build && ctest ``` -## Development Tools Included +## CI environment details -- **Compilers:** GCC 16, Clang 22 -- **Build Systems:** CMake, Ninja -- **Libraries:** GTK3, GLib, SQLite, libcurl, Exiv2, libavif, libheif, libjxl, WebP, ONNX Runtime, and more -- **VS Code Extensions:** C/C++ tools, CMake Tools, clang-format -- **Editors:** vim, nano +| Item | Value | +| ---- | ----- | +| Base image | `ubuntu:26.04` (same as `.github/workflows/ci.yml`) | +| Primary compiler | GCC 16 (`gcc-16` / `g++-16`) | +| Alt. compiler | Clang 22 (`clang-22` / `clang++-22`) | +| Package list | Exact copy of "Install Base Dependencies" in `ci.yml` | +| Dev extras (not in CI) | `ocl-icd-opencl-dev`, `libjxl-dev`, `clang-format-22`, `vim`, `nano`, `sudo` | ## Troubleshooting -### Build fails with missing dependencies +### AppImage fails with FUSE error -```bash -# Rebuild the container -# F1 → "Dev Containers: Rebuild Container" -``` +Always set `APPIMAGE_EXTRACT_AND_RUN=1` — FUSE is not available inside containers. ### Git submodules not initialized ```bash -git submodule init && git submodule update +git submodule update --init --recursive ``` -### AppImage build fails with FUSE error - -Always use the environment variable: -```bash -APPIMAGE_EXTRACT_AND_RUN=1 ./tools/appimage-build-script.sh -``` +### Git says the mounted repository has dubious ownership inside the container -### Need to install additional packages +Use the same UID/GID as the host when starting Docker, or configure the mounted repo as safe inside the container: ```bash -sudo apt-get update -sudo apt-get install -``` +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$PWD":/workspace -w /workspace \ + darktable-dev bash -lc './build.sh --prefix /tmp/dt --build-type Release' -### Want to run unit tests? - -```bash -# Build with tests enabled (libcmocka-dev is already installed) -./build.sh --prefix /tmp/dt --build-type RelWithDebInfo -- -DBUILD_TESTING=ON - -# Run tests -cd build && ctest +# or, if you keep the default root user inside the container: +git config --global --add safe.directory /workspace ``` -## File Structure - -``` -.devcontainer/ -├── devcontainer.json # Container configuration -├── Dockerfile # Environment setup with all build dependencies -└── README.md # This file -``` - -## Build Options Reference +### Need to install an extra package temporarily ```bash -# Build types ---build-type Release # Optimized, no debug info ---build-type Debug # Debug symbols, no optimization ---build-type RelWithDebInfo # Optimized + debug symbols (recommended) - -# Parallel jobs --j N # Use N parallel jobs (default: all CPUs) - -# Installation ---prefix # Set installation prefix (not required for development) ---install # Actually install files (not recommended in container) +sudo apt-get update && sudo apt-get install ``` -## Notes +### Rebuild the container after Dockerfile changes -- Workspace folder mounted at `/workspaces/darktable` -- Build artifacts go to `build/` directory -- Container runs as user `vscode` (UID 1000) -- Git submodules initialized automatically on container creation +VS Code: F1 → "Dev Containers: Rebuild Container" +CLI: `devcontainer up --workspace-folder . --remove-existing-container` -## Resources +## File structure -- [Darktable Build Instructions](https://github.com/darktable-org/darktable#building) -- [Developer's Guide](https://github.com/darktable-org/darktable/wiki/Developer's-guide) -- [User Manual](https://docs.darktable.org/) +```text +.devcontainer/ +├── Dockerfile # Build environment (mirrors CI ubuntu:26.04) +├── devcontainer.json # IDE/tooling configuration +└── README.md # This file +``` diff --git a/README.md b/README.md index 7134ef5a6b7..20cc4157243 100644 --- a/README.md +++ b/README.md @@ -443,6 +443,8 @@ If you experience crashes at startup, try launching darktable from a terminal wi There is a comprehensive list of build instructions for [Ubuntu/Debian related distributions](https://github.com/darktable-org/darktable/wiki/Build-instructions-for-Ubuntu) or for [Fedora and related distributions](https://github.com/darktable-org/darktable/wiki/Build-Instructions-for-Fedora). These build instructions can be easily adapted to many other Linux distributions. +For contributors who prefer a **container-based build environment** that exactly mirrors CI (ubuntu:26.04 with GCC 16 / Clang 22), see [.devcontainer/README.md](.devcontainer/README.md). It works with Docker or Podman alone (no IDE required), or with any [Dev Container-compatible IDE](https://containers.dev/supporting). This is particularly useful on immutable/atomic Linux systems, for infrequent contributors, or when reproducing a CI failure locally. + Contributing ------------ From 5eef79e0a4266ebc9b0306651a04384573fa6a1c Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sun, 16 Aug 2026 23:48:40 +0000 Subject: [PATCH 09/13] Enhance README with Docker and Podman installation instructions for container-based build environment --- .devcontainer/README.md | 32 ++++++++++++++++++++++++-------- README.md | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 15c869d48f2..3d89e3e187c 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -18,6 +18,25 @@ it useful — see [Use cases](#use-cases) below. the mounted workspace — host SSH keys, credentials, private documents, and other projects are not visible to them. +## Installing Docker or Podman + +Any OCI-compatible runtime works. Install one for your platform: + +| Platform | Command | +| -------- | ------- | +| Debian / Ubuntu | `sudo apt install docker.io` or [Docker Engine docs](https://docs.docker.com/engine/install/ubuntu/) | +| Fedora / RHEL | `sudo dnf install docker` or [Docker Engine docs](https://docs.docker.com/engine/install/fedora/) | +| Arch | `sudo pacman -S docker` | +| openSUSE | `sudo zypper install docker` | +| macOS | `brew install --cask docker` (Docker Desktop) or `brew install podman` | +| Windows | [Docker Desktop](https://docs.docker.com/desktop/setup/install/windows-install/) | + +On Linux, **Podman** is a rootless drop-in replacement (`alias docker=podman`). +See the [Podman installation guide](https://podman.io/docs/installation) for all distros. + +After installing, make sure your user is in the `docker` group (Linux) or that +Docker Desktop is running (macOS/Windows) before running the commands below. + ## Usage tiers | Tier | Requirements | Good for | @@ -118,15 +137,12 @@ chmod +x build/Darktable-*.AppImage cd build && ctest ``` -## CI environment details +## CI environment -| Item | Value | -| ---- | ----- | -| Base image | `ubuntu:26.04` (same as `.github/workflows/ci.yml`) | -| Primary compiler | GCC 16 (`gcc-16` / `g++-16`) | -| Alt. compiler | Clang 22 (`clang-22` / `clang++-22`) | -| Package list | Exact copy of "Install Base Dependencies" in `ci.yml` | -| Dev extras (not in CI) | `ocl-icd-opencl-dev`, `libjxl-dev`, `clang-format-22`, `vim`, `nano`, `sudo` | +The [Dockerfile](Dockerfile) is the single source of truth for the build +environment. It mirrors the "Install Base Dependencies" step in +`.github/workflows/ci.yml` exactly. Check the Dockerfile for the current base +image, compiler versions, and package list. ## Troubleshooting diff --git a/README.md b/README.md index 20cc4157243..35fe3730cd2 100644 --- a/README.md +++ b/README.md @@ -443,7 +443,7 @@ If you experience crashes at startup, try launching darktable from a terminal wi There is a comprehensive list of build instructions for [Ubuntu/Debian related distributions](https://github.com/darktable-org/darktable/wiki/Build-instructions-for-Ubuntu) or for [Fedora and related distributions](https://github.com/darktable-org/darktable/wiki/Build-Instructions-for-Fedora). These build instructions can be easily adapted to many other Linux distributions. -For contributors who prefer a **container-based build environment** that exactly mirrors CI (ubuntu:26.04 with GCC 16 / Clang 22), see [.devcontainer/README.md](.devcontainer/README.md). It works with Docker or Podman alone (no IDE required), or with any [Dev Container-compatible IDE](https://containers.dev/supporting). This is particularly useful on immutable/atomic Linux systems, for infrequent contributors, or when reproducing a CI failure locally. +For contributors who prefer a **container-based build environment** that mirrors CI, see [.devcontainer/README.md](.devcontainer/README.md). It works with Docker or Podman alone (no IDE required), or with any [Dev Container-compatible IDE](https://containers.dev/supporting). This is particularly useful on immutable/atomic Linux systems, for infrequent contributors, or when reproducing a CI failure locally. Contributing From cf552667d1e8c6489f176a8b494595ace6c2639b Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Tue, 18 Aug 2026 16:36:57 +0000 Subject: [PATCH 10/13] Refactor CI Docker setup: remove Dockerfile, update devcontainer to use pre-built image, and create GitHub Actions workflow for image build and publish --- .ci/Dockerfile | 134 ----------------------------- .devcontainer/README.md | 13 +-- .devcontainer/devcontainer.json | 5 +- .github/workflows/build-docker.yml | 38 ++++++++ .github/workflows/ci.yml | 100 ++------------------- 5 files changed, 55 insertions(+), 235 deletions(-) delete mode 100644 .ci/Dockerfile create mode 100644 .github/workflows/build-docker.yml diff --git a/.ci/Dockerfile b/.ci/Dockerfile deleted file mode 100644 index c27f227b1c1..00000000000 --- a/.ci/Dockerfile +++ /dev/null @@ -1,134 +0,0 @@ -# This file is part of darktable. -# copyright (c) 2016-2020 Roman Lebedev. -# -# darktable is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# darktable is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with darktable. If not, see . - -# docker build -t darktable/darktable . - -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# !!! hub.docker.com will not auto-rebuild the image !!! -# !!! after making changes here, or if you just want to manually refresh !!! -# !!! the image, you need to go to: !!! -# https://hub.docker.com/r/darktable/darktable/~/settings/automated-builds/ !!! -# !!! and press the "Trigger" button. !!! -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -FROM debian:testing -MAINTAINER Roman Lebedev - -# needed at least for python-based jsonschema :( -# see https://github.com/Julian/jsonschema/issues/299 -# and https://github.com/docker-library/python/issues/13 -ENV LANG C.UTF-8 -ENV LC_ALL C.UTF-8 -ENV LC_MESSAGES C.UTF-8 -ENV LANGUAGE C.UTF-8 - -ENV DEBIAN_FRONTEND noninteractive - -# Paper over occasional network flakiness of some mirrors. -RUN echo 'Acquire::Retries "10";' > /etc/apt/apt.conf.d/80retry - -# Do not install recommended packages -RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/80recommends - -# Do not install suggested packages -RUN echo 'APT::Install-Suggests "false";' > /etc/apt/apt.conf.d/80suggests - -# Assume yes -RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/80forceyes - -# Fix broken packages -RUN echo 'APT::Get::Fix-Missing "true";' > /etc/apt/apt.conf.d/80fixmissin - -ENV GCC_VER=9 -ENV LLVM_VER=10 - -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install \ - appstream-util \ - clang-$LLVM_VER \ - cmake \ - desktop-file-utils \ - g++-$GCC_VER \ - gcc-$GCC_VER \ - gettext \ - git \ - intltool \ - libatk1.0-dev \ - libc++-$LLVM_VER-dev \ - libcairo2-dev \ - libcolord-dev \ - libcolord-gtk-dev \ - libcmocka-dev \ - libcups2-dev \ - libcurl4-gnutls-dev \ - libexiv2-dev \ - libgdk-pixbuf2.0-dev \ - libglib2.0-dev \ - libgphoto2-dev \ - libgraphicsmagick1-dev \ - libgtk-3-dev \ - libheif-dev \ - libjpeg-dev \ - libjson-glib-dev \ - liblcms2-dev \ - liblensfun-dev \ - liblua5.2-dev \ - liblua5.3-dev \ - libomp-$LLVM_VER-dev \ - libopenexr-dev \ - libopenjp2-7-dev \ - libosmgpsmap-1.0-dev \ - libpango1.0-dev \ - libpng-dev \ - libpugixml-dev \ - librsvg2-dev \ - libsaxon-java \ - libsecret-1-dev \ - libsqlite3-dev \ - libtiff5-dev \ - libwebp-dev \ - libx11-dev \ - libxml2-dev \ - libxml2-utils \ - make \ - ninja-build \ - perl \ - po4a \ - python3-jsonschema \ - xsltproc \ - zlib1g-dev && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# i'd like to explicitly use ld.gold -# while it may be just immeasurably faster, it is known to cause more issues -# than traditional ld.bfd; plus, at this time, ld.gold seems like the future. -RUN dpkg-divert --add --rename --divert /usr/bin/ld.original /usr/bin/ld && \ - ln -s /usr/bin/ld.gold /usr/bin/ld - -# optional: opencl kernels test-compilation -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install clang-$LLVM_VER libclang-common-$LLVM_VER-dev \ - llvm-$LLVM_VER-dev && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# optional: usermanual deps -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install default-jdk-headless default-jre-headless docbook \ - docbook-xml docbook-xsl docbook-xsl-saxon fop gnome-doc-utils imagemagick \ - libsaxon-java xsltproc && apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 3d89e3e187c..5d68c2dcfc9 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -47,22 +47,25 @@ Docker Desktop is running (macOS/Windows) before running the commands below. ## Tier 1: Docker/Podman CLI only -The most lightweight option. No IDE, no extra tooling. +The most lightweight option. No IDE, no extra tooling — just pull the same +image that CI uses. ```bash -# Build the image once (from the repository root) -docker build -t darktable-dev -f .devcontainer/Dockerfile . +# Pull the pre-built CI image +docker pull ghcr.io/darktable-org/darktable-build:latest # Verify the build compiles cleanly (same environment as CI) docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD":/workspace -w /workspace \ - darktable-dev bash -lc './build.sh --prefix /tmp/dt --build-type Release' + ghcr.io/darktable-org/darktable-build:latest \ + bash -lc './build.sh --prefix /tmp/dt --build-type Release' # Build an AppImage for GUI testing on the host docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD":/workspace -w /workspace \ -e APPIMAGE_EXTRACT_AND_RUN=1 \ - darktable-dev bash -lc './tools/appimage-build-script.sh' + ghcr.io/darktable-org/darktable-build:latest \ + bash -lc './tools/appimage-build-script.sh' ``` The AppImage appears in `build/Darktable-*.AppImage` and can be run directly on the host. diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e7d3730d53b..a6cc746fd52 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,6 @@ { "name": "Darktable Development", - "build": { - "dockerfile": "Dockerfile", - "context": ".." - }, + "image": "ghcr.io/darktable-org/darktable-build:latest", "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt=seccomp=unconfined" diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml new file mode 100644 index 00000000000..751fdca3daf --- /dev/null +++ b/.github/workflows/build-docker.yml @@ -0,0 +1,38 @@ +name: Build and publish Docker image + +on: + push: + branches: + - master + paths: + - '.devcontainer/Dockerfile' + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' + name: Build and push darktable-build Docker image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: .devcontainer/Dockerfile + push: true + tags: | + ghcr.io/darktable-org/darktable-build:latest + ghcr.io/darktable-org/darktable-build:${{ github.sha }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f369c4e70bb..74bb0b10b4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,19 +49,17 @@ jobs: Linux: if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' - name: Linux_${{ matrix.distro }}_${{ matrix.compiler.compiler }}_${{ matrix.btype }}${{ matrix.name_suffix }} + name: Linux_${{ matrix.compiler.compiler }}_${{ matrix.btype }}${{ matrix.name_suffix }} runs-on: ubuntu-latest container: - image: ${{ matrix.distro }} + image: ghcr.io/darktable-org/darktable-build:latest options: --tmpfs /tmp:exec --tmpfs /__w/${{ github.event.repository.name }}/${{ github.event.repository.name }}:exec strategy: fail-fast: true matrix: - distro: - - "ubuntu:26.04" compiler: - - { compiler: GNU16, CC: gcc-16, CXX: g++-16, packages: gcc-16 g++-16 } - - { compiler: LLVM22, CC: clang-22, CXX: clang++-22, packages: clang-22 libomp-22-dev llvm-22-dev libc++-22-dev libc++abi1 lld-22 clang-tools-22 mlir-22-tools libmlir-22-dev} + - { compiler: GNU16, CC: gcc-16, CXX: g++-16 } + - { compiler: LLVM22, CC: clang-22, CXX: clang++-22 } btype: - Release target: @@ -71,24 +69,21 @@ jobs: eco: [-DDONT_USE_INTERNAL_LIBRAW=ON] include: # We want one run in CI to be Debug to make sure the Debug build isn't broken - - distro: "ubuntu:26.04" - btype: Debug - compiler: { compiler: GNU16, CC: gcc-16, CXX: g++-16, packages: gcc-16 g++-16 } + - btype: Debug + compiler: { compiler: GNU16, CC: gcc-16, CXX: g++-16 } target: skiptest generator: Ninja eco: -DDONT_USE_INTERNAL_LIBRAW=OFF # The other entries use the skiptest target, which never configures # BUILD_TESTING and so never even compiles the unit tests. This one # builds them and runs ctest. - - distro: "ubuntu:26.04" - btype: Release - compiler: { compiler: GNU16, CC: gcc-16, CXX: g++-16, packages: gcc-16 g++-16 } + - btype: Release + compiler: { compiler: GNU16, CC: gcc-16, CXX: g++-16 } target: build generator: Ninja eco: -DDONT_USE_INTERNAL_LIBRAW=ON name_suffix: _tests env: - DISTRO: ${{ matrix.distro }} CC: ${{ matrix.compiler.CC }} CXX: ${{ matrix.compiler.CXX }} SRC_DIR: ${{ github.workspace }}/src @@ -99,86 +94,7 @@ jobs: GENERATOR: ${{ matrix.generator }} TARGET: ${{ matrix.target }} DARKTABLE_CLI: ${{ github.workspace }}/install/bin/darktable-cli - DEBIAN_FRONTEND: noninteractive steps: - - name: Select fallback Ubuntu mirror if requested - if: startsWith(github.ref_name, 'azure-') - # Sometimes the default Ubuntu mirror is unreliable under overload - # and CI fails because of this. We can use a special branch name - # prefix to switch the mirror to the one on Azure. Always using the - # Azure is not a solution as it can also fail from time to time. - run: | - sed -i 's/archive\.ubuntu/azure\.archive\.ubuntu/' /etc/apt/sources.list.d/ubuntu.sources - - name: Update base packages - timeout-minutes: 15 - run: | - set -xe - rm -rf /var/lib/apt/lists/* - apt-get --yes update - apt-get --yes install eatmydata - eatmydata apt-get --yes upgrade - - name: Install compiler ${{ matrix.compiler.compiler }} - run: | - eatmydata apt-get --yes install ${{ matrix.compiler.packages }} - - name: Install Base Dependencies - run: | - eatmydata apt-get --yes install \ - build-essential \ - cmake \ - appstream-util \ - desktop-file-utils \ - gettext \ - git \ - gdb \ - intltool \ - libarchive-dev \ - libatk1.0-dev \ - libavif-dev \ - libcairo2-dev \ - libcmocka-dev \ - libcolord-dev \ - libcolord-gtk-dev \ - libcups2-dev \ - libcurl4-gnutls-dev \ - libexiv2-dev \ - libgdk-pixbuf-2.0-dev \ - libglib2.0-dev \ - libgmic-dev \ - libgphoto2-dev \ - libgraphicsmagick1-dev \ - libgtk-3-dev \ - libheif-dev \ - libjpeg-dev \ - libjson-glib-dev \ - liblcms2-dev \ - liblensfun-dev \ - liblua5.4-dev \ - libonnxruntime-dev \ - libopenexr-dev \ - libopenjp2-7-dev \ - libosmgpsmap-1.0-dev \ - libpango1.0-dev \ - libpng-dev \ - libportmidi-dev \ - libpotrace-dev \ - libpugixml-dev \ - libraw-dev \ - librsvg2-dev \ - libsaxon-java \ - libsdl2-dev \ - libsecret-1-dev \ - libsqlite3-dev \ - libtiff5-dev \ - libwebp-dev \ - libx11-dev \ - libxml2-dev \ - libxml2-utils \ - ninja-build \ - perl \ - po4a \ - python3-jsonschema \ - xsltproc \ - zlib1g-dev; - uses: actions/checkout@v7 with: submodules: false From 87fc0c84d56d0dd5ebc6e90c5089de648ad196bc Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Fri, 21 Aug 2026 15:33:29 +0000 Subject: [PATCH 11/13] Refactor CI Linux workflow to build from Dockerfile and use GHCH as cache --- .devcontainer/README.md | 54 ++++++++++++++++-------------- .devcontainer/devcontainer.json | 5 +-- .github/workflows/build-docker.yml | 27 ++++++++++----- .github/workflows/ci.yml | 45 ++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 39 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 2a916d987b1..f8d800cc83e 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -43,24 +43,24 @@ See the [Podman installation guide](https://podman.io/docs/installation). No IDE, no extra tooling — just build and run the container directly. ```bash -# Build the image once (from the repository root) -docker build -t darktable-dev -f .devcontainer/Dockerfile . +# Pull the pre-built CI image +docker pull ghcr.io/darktable-org/darktable-build:latest -# Verify the build compiles (same environment as CI) +# Verify the build compiles cleanly (same environment as CI) docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD":/workspace -w /workspace \ - darktable-dev \ + ghcr.io/darktable-org/darktable-build:latest \ bash -lc './build.sh --prefix /tmp/dt --build-type Release' # Build an AppImage for GUI testing on the host docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD":/workspace -w /workspace \ -e APPIMAGE_EXTRACT_AND_RUN=1 \ - darktable-dev \ + ghcr.io/darktable-org/darktable-build:latest \ bash -lc './tools/appimage-build-script.sh' ``` -The AppImage appears in `build/Darktable-*.AppImage` and can be run on the host. +The AppImage appears in `build/Darktable-*.AppImage` and can be run directly on the host. > Replace `docker` with `podman` if you use Podman. @@ -95,10 +95,12 @@ Then: # Start the container devcontainer up --workspace-folder . -# Open a shell +# Open a shell inside it devcontainer exec --workspace-folder . bash ``` +Then build as usual (see [Building](#building)). + > **VS Code and JetBrains bundle their own devcontainer implementation** — you > only need to install the CLI separately when using other editors or working > purely in a terminal. @@ -150,31 +152,30 @@ Using `--configdir` avoids touching your production darktable configuration. cd build && ctest ``` -## CI environment and pre-built images +## CI environment The [Dockerfile](Dockerfile) is the single source of truth for the build -environment. Inspect it for the exact base image, compiler versions, and -package list. +environment. Linux CI jobs build from it on every run, using the published +GHCR image as a BuildKit layer cache — when nothing in the Dockerfile has +changed, all layers are served from cache and the build step completes in +seconds. This means a PR that modifies the Dockerfile is automatically tested +against the updated environment before merge. ### Pre-built images on GHCR -`.github/workflows/build-docker.yml` automatically builds the image and -publishes it to the GitHub Container Registry (GHCR) whenever the `Dockerfile` -changes on the `master` branch. The pre-built image is available at: +The `:latest` tag on `ghcr.io/darktable-org/darktable-build` is updated on +every successful merge to `master`. Each release is also tagged +`YYYY-MM-DD-SHORTSHA` for pinned auditing. -``` -ghcr.io/darktable-org/darktable-build:latest -``` +`.github/workflows/build-docker.yml` provides a manual `workflow_dispatch` +trigger to force a full rebuild — useful when the upstream `ubuntu:26.04` +base image updates without a Dockerfile change. -Using the pre-built image skips the local build step: +### Customising the build environment -```bash -docker pull ghcr.io/darktable-org/darktable-build:latest -docker run --rm --user "$(id -u):$(id -g)" \ - -v "$PWD":/workspace -w /workspace \ - ghcr.io/darktable-org/darktable-build:latest \ - bash -lc './build.sh --prefix /tmp/dt --build-type Release' -``` +To add or remove packages, edit `.devcontainer/Dockerfile` and submit it as a +normal PR. CI will build from the updated Dockerfile automatically, so you can +verify the environment works before the change is merged. ## Troubleshooting @@ -200,7 +201,7 @@ Always set `APPIMAGE_EXTRACT_AND_RUN=1` — FUSE is not available inside contain git submodule update --init --recursive ``` -### Git says the repository has dubious ownership inside the container +### Git says the mounted repository has dubious ownership inside the container Pass `--user "$(id -u):$(id -g)"` to `docker run` (as shown in the examples above), or mark the path as safe inside the container: @@ -228,5 +229,6 @@ CLI: `devcontainer up --workspace-folder . --remove-existing-container` ├── devcontainer.json # IDE/tooling configuration └── README.md # This file .github/workflows/ -└── build-docker.yml # Publishes the image to GHCR on Dockerfile changes +├── ci.yml # Linux jobs build from Dockerfile (with GHCR cache) +└── build-docker.yml # Manual workflow_dispatch to force a :latest rebuild ``` diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e7d3730d53b..a6cc746fd52 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,6 @@ { "name": "Darktable Development", - "build": { - "dockerfile": "Dockerfile", - "context": ".." - }, + "image": "ghcr.io/darktable-org/darktable-build:latest", "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt=seccomp=unconfined" diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 751fdca3daf..4672b5431ee 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -1,11 +1,8 @@ name: Build and publish Docker image on: - push: - branches: - - master - paths: - - '.devcontainer/Dockerfile' + # Manual trigger only — useful when the upstream ubuntu:26.04 base image + # updates without a Dockerfile change. Normal :latest updates happen via ci.yml. workflow_dispatch: permissions: @@ -27,12 +24,26 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Compute image tags + id: tags + run: | + SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) + { + echo 'tags<> "$GITHUB_OUTPUT" + - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . file: .devcontainer/Dockerfile push: true - tags: | - ghcr.io/darktable-org/darktable-build:latest - ghcr.io/darktable-org/darktable-build:${{ github.sha }} + tags: ${{ steps.tags.outputs.tags }} + cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest + cache-to: type=inline diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ec3d0f8d5d..d0b3dde3439 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,15 +44,58 @@ on: permissions: contents: read + packages: write jobs: + prepare-image: + name: Build CI Docker image + if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + outputs: + image: ${{ steps.tags.outputs.image }} + steps: + - uses: actions/checkout@v7 + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Compute image tags + id: tags + run: | + SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) + SHA_TAG="ghcr.io/darktable-org/darktable-build:sha-${GITHUB_SHA}" + echo "image=${SHA_TAG}" >> "$GITHUB_OUTPUT" + { + echo 'tags<> "$GITHUB_OUTPUT" + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: .devcontainer/Dockerfile + push: true + tags: ${{ steps.tags.outputs.tags }} + cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest + cache-to: ${{ github.ref == 'refs/heads/master' && 'type=inline' || '' }} + Linux: + needs: prepare-image if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' name: Linux_${{ matrix.compiler.compiler }}_${{ matrix.btype }}${{ matrix.name_suffix }} runs-on: ubuntu-latest container: - image: ghcr.io/darktable-org/darktable-build:latest + image: ${{ needs.prepare-image.outputs.image }} options: --tmpfs /tmp:exec --tmpfs /__w/${{ github.event.repository.name }}/${{ github.event.repository.name }}:exec strategy: fail-fast: true From 547ba6fbe756514b3bdc945684d3907bb2fc97ba Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Fri, 21 Aug 2026 17:15:19 +0000 Subject: [PATCH 12/13] Revert for using images from GHCR, add publish-image job in CI workflow --- .devcontainer/README.md | 13 ++++--- .github/workflows/ci.yml | 79 ++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index f8d800cc83e..cdb46e32125 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -155,11 +155,14 @@ cd build && ctest ## CI environment The [Dockerfile](Dockerfile) is the single source of truth for the build -environment. Linux CI jobs build from it on every run, using the published -GHCR image as a BuildKit layer cache — when nothing in the Dockerfile has -changed, all layers are served from cache and the build step completes in -seconds. This means a PR that modifies the Dockerfile is automatically tested -against the updated environment before merge. +environment. Linux CI jobs always run against the published `:latest` image. +On every successful merge to `master` the `publish-image` CI job rebuilds +from the Dockerfile (using the published image as a BuildKit layer cache, so +only changed layers are rebuilt) and pushes the new image to GHCR. + +If your PR adds a new package to the Dockerfile alongside code that needs it, +split the work: land the Dockerfile-only change first so `:latest` is updated, +then open the code change PR on top of it. ### Pre-built images on GHCR diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0b3dde3439..5ed53fabfd3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,54 +48,12 @@ permissions: jobs: - prepare-image: - name: Build CI Docker image - if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - outputs: - image: ${{ steps.tags.outputs.image }} - steps: - - uses: actions/checkout@v7 - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Compute image tags - id: tags - run: | - SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) - SHA_TAG="ghcr.io/darktable-org/darktable-build:sha-${GITHUB_SHA}" - echo "image=${SHA_TAG}" >> "$GITHUB_OUTPUT" - { - echo 'tags<> "$GITHUB_OUTPUT" - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - file: .devcontainer/Dockerfile - push: true - tags: ${{ steps.tags.outputs.tags }} - cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest - cache-to: ${{ github.ref == 'refs/heads/master' && 'type=inline' || '' }} - Linux: - needs: prepare-image if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' name: Linux_${{ matrix.compiler.compiler }}_${{ matrix.btype }}${{ matrix.name_suffix }} runs-on: ubuntu-latest container: - image: ${{ needs.prepare-image.outputs.image }} + image: ghcr.io/darktable-org/darktable-build:latest options: --tmpfs /tmp:exec --tmpfs /__w/${{ github.event.repository.name }}/${{ github.event.repository.name }}:exec strategy: fail-fast: true @@ -168,6 +126,41 @@ jobs: --conf plugins/lighttable/export/force_lcms2=FALSE \ --conf plugins/lighttable/export/iccintent=0 + publish-image: + name: Publish CI Docker image + needs: Linux + if: (github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Compute image tags + id: tags + run: | + SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) + { + echo 'tags<> "$GITHUB_OUTPUT" + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: .devcontainer/Dockerfile + push: true + tags: ${{ steps.tags.outputs.tags }} + cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest + cache-to: type=inline + Windows: if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' name: Windows_${{ matrix.msystem }}_${{ matrix.btype }} From a64930a3d59b632f276a70d38e9b8172b737656b Mon Sep 17 00:00:00 2001 From: Aleksandr Kadykov Date: Sun, 23 Aug 2026 16:38:39 +0000 Subject: [PATCH 13/13] Refactor CI Docker workflow: remove legacy Dockerfile, add test-image script, move image publishing to build-docker workflow --- .ci/Dockerfile | 139 ----------------------------- .devcontainer/README.md | 33 ++++--- .github/scripts/test-image.sh | 53 +++++++++++ .github/workflows/build-docker.yml | 44 ++++++--- .github/workflows/ci.yml | 36 -------- .gitignore | 1 + 6 files changed, 104 insertions(+), 202 deletions(-) delete mode 100644 .ci/Dockerfile create mode 100755 .github/scripts/test-image.sh diff --git a/.ci/Dockerfile b/.ci/Dockerfile deleted file mode 100644 index d33c31e652e..00000000000 --- a/.ci/Dockerfile +++ /dev/null @@ -1,139 +0,0 @@ -# This file is part of darktable. -# copyright (c) 2016-2020 Roman Lebedev. -# -# darktable is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# darktable is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with darktable. If not, see . - -# docker build -t darktable/darktable . - -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# !!! hub.docker.com will not auto-rebuild the image !!! -# !!! after making changes here, or if you just want to manually refresh !!! -# !!! the image, you need to go to: !!! -# https://hub.docker.com/r/darktable/darktable/~/settings/automated-builds/ !!! -# !!! and press the "Trigger" button. !!! -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -FROM debian:testing -MAINTAINER Roman Lebedev - -# needed at least for python-based jsonschema :( -# see https://github.com/Julian/jsonschema/issues/299 -# and https://github.com/docker-library/python/issues/13 -ENV LANG C.UTF-8 -ENV LC_ALL C.UTF-8 -ENV LC_MESSAGES C.UTF-8 -ENV LANGUAGE C.UTF-8 - -ENV DEBIAN_FRONTEND noninteractive - -# Paper over occasional network flakiness of some mirrors. -RUN echo 'Acquire::Retries "10";' > /etc/apt/apt.conf.d/80retry - -# Do not install recommended packages -RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/80recommends - -# Do not install suggested packages -RUN echo 'APT::Install-Suggests "false";' > /etc/apt/apt.conf.d/80suggests - -# Assume yes -RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/80forceyes - -# Fix broken packages -RUN echo 'APT::Get::Fix-Missing "true";' > /etc/apt/apt.conf.d/80fixmissin - -ENV GCC_VER=9 -ENV LLVM_VER=10 - -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install \ - appstream-util \ - clang-$LLVM_VER \ - cmake \ - desktop-file-utils \ - g++-$GCC_VER \ - gcc-$GCC_VER \ - gettext \ - git \ - intltool \ - libatk1.0-dev \ - libc++-$LLVM_VER-dev \ - libcairo2-dev \ - libcolord-dev \ - libcolord-gtk-dev \ - libcmocka-dev \ - libcups2-dev \ - libcurl4-gnutls-dev \ - libexiv2-dev \ - libgdk-pixbuf2.0-dev \ - libglib2.0-dev \ - libgphoto2-dev \ - libgraphicsmagick1-dev \ - libgtk-3-dev \ - libheif-dev \ - libjpeg-dev \ - libjson-glib-dev \ - liblcms2-dev \ - liblensfun-dev \ - liblua5.2-dev \ - liblua5.3-dev \ - libomp-$LLVM_VER-dev \ - libopencv-calib3d-dev \ - libopencv-core-dev \ - libopencv-features2d-dev \ - libopencv-flann-dev \ - libopencv-imgproc-dev \ - libopenexr-dev \ - libopenjp2-7-dev \ - libosmgpsmap-1.0-dev \ - libpango1.0-dev \ - libpng-dev \ - libpugixml-dev \ - librsvg2-dev \ - libsaxon-java \ - libsecret-1-dev \ - libsqlite3-dev \ - libtiff5-dev \ - libwebp-dev \ - libx11-dev \ - libxml2-dev \ - libxml2-utils \ - make \ - ninja-build \ - perl \ - po4a \ - python3-jsonschema \ - xsltproc \ - zlib1g-dev && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# i'd like to explicitly use ld.gold -# while it may be just immeasurably faster, it is known to cause more issues -# than traditional ld.bfd; plus, at this time, ld.gold seems like the future. -RUN dpkg-divert --add --rename --divert /usr/bin/ld.original /usr/bin/ld && \ - ln -s /usr/bin/ld.gold /usr/bin/ld - -# optional: opencl kernels test-compilation -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install clang-$LLVM_VER libclang-common-$LLVM_VER-dev \ - llvm-$LLVM_VER-dev && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# optional: usermanual deps -# pls keep sorted :) -RUN rm -rf /var/lib/apt/lists/* && apt-get update && \ - apt-get install default-jdk-headless default-jre-headless docbook \ - docbook-xml docbook-xsl docbook-xsl-saxon fop gnome-doc-utils imagemagick \ - libsaxon-java xsltproc && apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/.devcontainer/README.md b/.devcontainer/README.md index cdb46e32125..89c9e027e74 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -155,30 +155,29 @@ cd build && ctest ## CI environment The [Dockerfile](Dockerfile) is the single source of truth for the build -environment. Linux CI jobs always run against the published `:latest` image. -On every successful merge to `master` the `publish-image` CI job rebuilds -from the Dockerfile (using the published image as a BuildKit layer cache, so -only changed layers are rebuilt) and pushes the new image to GHCR. - -If your PR adds a new package to the Dockerfile alongside code that needs it, -split the work: land the Dockerfile-only change first so `:latest` is updated, -then open the code change PR on top of it. +environment. The `.github/workflows/build-docker.yml` workflow implements a +**build → test → push** sequence: it builds a candidate image from the +Dockerfile, runs a smoke-test build of darktable inside it, and only pushes +to GHCR if the build succeeds. Linux CI jobs always pull the last tested +`:latest` image. ### Pre-built images on GHCR -The `:latest` tag on `ghcr.io/darktable-org/darktable-build` is updated on -every successful merge to `master`. Each release is also tagged +The `:latest` tag on `ghcr.io/darktable-org/darktable-build` is updated +whenever `.devcontainer/Dockerfile` changes on `master`, after the candidate +image passes a smoke-test build of darktable. Each release is also tagged `YYYY-MM-DD-SHORTSHA` for pinned auditing. -`.github/workflows/build-docker.yml` provides a manual `workflow_dispatch` -trigger to force a full rebuild — useful when the upstream `ubuntu:26.04` -base image updates without a Dockerfile change. +`workflow_dispatch` on `build-docker.yml` lets maintainers trigger a manual +rebuild — useful when the upstream `ubuntu:26.04` base image gains security +patches without any change to the Dockerfile. ### Customising the build environment To add or remove packages, edit `.devcontainer/Dockerfile` and submit it as a -normal PR. CI will build from the updated Dockerfile automatically, so you can -verify the environment works before the change is merged. +normal PR. When the change merges to `master`, `build-docker.yml` runs +automatically, builds and smoke-tests the new image, and pushes it to GHCR +only if the build succeeds. ## Troubleshooting @@ -232,6 +231,6 @@ CLI: `devcontainer up --workspace-folder . --remove-existing-container` ├── devcontainer.json # IDE/tooling configuration └── README.md # This file .github/workflows/ -├── ci.yml # Linux jobs build from Dockerfile (with GHCR cache) -└── build-docker.yml # Manual workflow_dispatch to force a :latest rebuild +├── ci.yml # Linux jobs run against the published :latest image +└── build-docker.yml # Build → test → push :latest (on Dockerfile changes or workflow_dispatch) ``` diff --git a/.github/scripts/test-image.sh b/.github/scripts/test-image.sh new file mode 100755 index 00000000000..56355e5734a --- /dev/null +++ b/.github/scripts/test-image.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Run all Linux CI matrix configurations against a candidate Docker image. +# Used by build-docker.yml; can also be called locally to validate a new image. +# Usage: test-image.sh +set -euo pipefail + +IMAGE="${1:?Usage: $0 }" +SRC_DIR="${2:?Usage: $0 }" + +run_config() { + local name="$1"; shift + local build_dir="${SRC_DIR}/build/${name}" + local install_dir="${SRC_DIR}/install/${name}" + mkdir -p "${build_dir}" "${install_dir}" + printf '\n=== Testing configuration: %s ===\n\n' "${name}" + docker run --rm \ + --tmpfs /tmp:exec \ + -v "${SRC_DIR}:${SRC_DIR}" \ + -e SRC_DIR="${SRC_DIR}" \ + -e BUILD_DIR="${build_dir}" \ + -e INSTALL_PREFIX="${install_dir}" \ + -e GENERATOR=Ninja \ + "$@" \ + "${IMAGE}" \ + "${SRC_DIR}/.ci/ci-script.sh" +} + +# Mirror all Linux matrix configurations from .github/workflows/ci.yml +run_config GNU16_Release \ + -e CC=gcc-16 -e CXX=g++-16 \ + -e CMAKE_BUILD_TYPE=Release \ + -e TARGET=skiptest \ + -e ECO="-DDONT_USE_INTERNAL_LIBRAW=ON" + +run_config LLVM22_Release \ + -e CC=clang-22 -e CXX=clang++-22 \ + -e CMAKE_BUILD_TYPE=Release \ + -e TARGET=skiptest \ + -e ECO="-DDONT_USE_INTERNAL_LIBRAW=ON" + +run_config GNU16_Debug \ + -e CC=gcc-16 -e CXX=g++-16 \ + -e CMAKE_BUILD_TYPE=Debug \ + -e TARGET=skiptest \ + -e ECO="-DDONT_USE_INTERNAL_LIBRAW=OFF" + +run_config GNU16_Release_tests \ + -e CC=gcc-16 -e CXX=g++-16 \ + -e CMAKE_BUILD_TYPE=Release \ + -e TARGET=build \ + -e ECO="-DDONT_USE_INTERNAL_LIBRAW=ON" + +printf '\n=== All configurations passed ===\n' diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 4672b5431ee..3147b2d6f81 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -1,23 +1,34 @@ name: Build and publish Docker image on: - # Manual trigger only — useful when the upstream ubuntu:26.04 base image - # updates without a Dockerfile change. Normal :latest updates happen via ci.yml. + push: + branches: + - master + paths: + - '.devcontainer/Dockerfile' workflow_dispatch: -permissions: - contents: read - packages: write - jobs: - build-and-push: + build-test-push: + name: Build, test and push CI Docker image if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' - name: Build and push darktable-build Docker image runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - uses: actions/checkout@v7 + with: + submodules: false + fetch-depth: 1 + + - name: Get build submodules + run: | + git submodule init + git config submodule.src/tests/integration.update none + git submodule update - - name: Log in to GitHub Container Registry + - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io @@ -27,6 +38,19 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Build candidate image + uses: docker/build-push-action@v6 + with: + context: . + file: .devcontainer/Dockerfile + load: true + push: false + tags: darktable-build:candidate + cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest + + - name: Run CI matrix checks with candidate image + run: .github/scripts/test-image.sh darktable-build:candidate "$GITHUB_WORKSPACE" + - name: Compute image tags id: tags run: | @@ -38,7 +62,7 @@ jobs: echo 'EOF' } >> "$GITHUB_OUTPUT" - - name: Build and push Docker image + - name: Push tested image to GHCR uses: docker/build-push-action@v6 with: context: . diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ed53fabfd3..1ec3d0f8d5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,6 @@ on: permissions: contents: read - packages: write jobs: @@ -126,41 +125,6 @@ jobs: --conf plugins/lighttable/export/force_lcms2=FALSE \ --conf plugins/lighttable/export/iccintent=0 - publish-image: - name: Publish CI Docker image - needs: Linux - if: (github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Compute image tags - id: tags - run: | - SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) - { - echo 'tags<> "$GITHUB_OUTPUT" - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - file: .devcontainer/Dockerfile - push: true - tags: ${{ steps.tags.outputs.tags }} - cache-from: type=registry,ref=ghcr.io/darktable-org/darktable-build:latest - cache-to: type=inline - Windows: if: github.repository == 'darktable-org/darktable' || github.event_name == 'workflow_dispatch' name: Windows_${{ matrix.msystem }}_${{ matrix.btype }} diff --git a/.gitignore b/.gitignore index 8582dca57be..dac963ce743 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ workspace/ cmake-build-debug/ .idea/ AppDir/ +install/