From 6f0e643dc9cd0775888e4cff06af93aa4eed83c8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 16:47:42 +0000 Subject: [PATCH 1/8] feat: Create script to set up cetmodules development environment This script automates the setup of a development environment for cetmodules on Ubuntu and AlmaLinux. It performs the following steps: - Detects the operating system (Ubuntu or AlmaLinux) and uses the appropriate package manager. - Installs system dependencies such as git, doxygen, graphviz, and build tools. - Sets up a Python virtual environment and installs CMake, Sphinx, and other required Python packages. - Clones the Catch2 repository, builds it, and installs it. - Clones the cetmodules repository, configures the build with documentation enabled, builds the project, and runs the tests. - Builds the cetmodules documentation. --- .gitignore | 2 ++ setup_cetmodules_dev.sh | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 .gitignore create mode 100644 setup_cetmodules_dev.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c8e59e43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build/ +/venv/ diff --git a/setup_cetmodules_dev.sh b/setup_cetmodules_dev.sh new file mode 100644 index 00000000..f850a954 --- /dev/null +++ b/setup_cetmodules_dev.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +# --- OS Detection --- +if [ -f /etc/os-release ]; then + . /etc/os-release + if [[ "$ID" == "ubuntu" ]]; then + PACKAGE_MANAGER="apt-get" + BUILD_DEPS="build-essential" + elif [[ "$ID" == "almalinux" ]]; then + PACKAGE_MANAGER="dnf" + BUILD_DEPS="gcc-c++" + else + echo "Unsupported operating system: $ID" + exit 1 + fi +else + echo "/etc/os-release not found. Cannot determine operating system." + exit 1 +fi + +# --- System Dependency Installation --- +echo "Updating package lists..." +sudo $PACKAGE_MANAGER update -y + +echo "Installing system dependencies..." +sudo $PACKAGE_MANAGER install -y git doxygen graphviz python3-venv $BUILD_DEPS + +# --- Python Environment Setup --- +echo "Setting up Python virtual environment..." +python3 -m venv venv +source venv/bin/activate + +echo "Installing Python packages (CMake, Sphinx, etc.)..." +pip install cmake sphinx sphinxcontrib-moderncmakedomain sphinx-design sphinx-toolbox sphinxcontrib-jquery + +# --- Catch2 Installation --- +echo "Cloning and installing Catch2..." +git clone https://github.com/catchorg/Catch2.git +cd Catch2 +cmake -S . -B build -DBUILD_TESTING=OFF +sudo cmake --build build --target install +cd .. +rm -rf Catch2 + +# --- cetmodules Build and Test --- +echo "Cloning, building, and testing cetmodules..." +git clone https://github.com/FNALssi/cetmodules.git +cd cetmodules +cmake -S . -B build -DBUILD_DOCS=ON +cmake --build build +ctest --test-dir build + +# --- Documentation Build --- +echo "Building cetmodules documentation..." +cmake --build build --target doc-cetmodules-reference +cd .. + +# --- Completion --- +echo "" +echo "----------------------------------------------------" +echo "Development environment setup for cetmodules is complete!" +echo "To activate the Python virtual environment, run:" +echo "source venv/bin/activate" +echo "----------------------------------------------------" From c4abbb24613ed1ee1cc5a79ee71134dad7e6b455 Mon Sep 17 00:00:00 2001 From: Chris Green Date: Wed, 10 Dec 2025 09:57:28 -0600 Subject: [PATCH 2/8] Prelims for container definition --- dev/container/.dummy | 0 setup_cetmodules_dev.sh => dev/setup_cetmodules_dev.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 dev/container/.dummy rename setup_cetmodules_dev.sh => dev/setup_cetmodules_dev.sh (100%) diff --git a/dev/container/.dummy b/dev/container/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/setup_cetmodules_dev.sh b/dev/setup_cetmodules_dev.sh similarity index 100% rename from setup_cetmodules_dev.sh rename to dev/setup_cetmodules_dev.sh From 009f695ce98aa5cd73de8394b1dd867a19d85350 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 16:28:16 +0000 Subject: [PATCH 3/8] feat(dev): Add Docker-based development environment Adds a Dockerfile and instructions for building and running a containerized development environment for cetmodules. The new configuration, located in `dev/container/`, provides a consistent and reproducible environment with all necessary dependencies installed. It is configured to support an out-of-source build workflow and includes a non-root user to avoid file ownership issues when mounting the source directory. A `README.md` is included with detailed instructions for building the image and running the container. --- .gitignore | 1 + dev/container/Dockerfile | 49 ++++++++++++++++++++++++++++++++++++++++ dev/container/README.md | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 dev/container/Dockerfile create mode 100644 dev/container/README.md diff --git a/.gitignore b/.gitignore index c8e59e43..2674d21c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build/ /venv/ +venv diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile new file mode 100644 index 00000000..ab536c41 --- /dev/null +++ b/dev/container/Dockerfile @@ -0,0 +1,49 @@ +# Base image +FROM ubuntu:latest + +# Set non-interactive frontend to avoid prompts +ENV DEBIAN_FRONTEND=noninteractive + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + git \ + doxygen \ + graphviz \ + python3 \ + python3-pip \ + sudo && \ + rm -rf /var/lib/apt/lists/* + +# Install Python packages +RUN pip3 install --no-cache-dir \ + cmake \ + sphinx \ + sphinxcontrib-moderncmakedomain \ + sphinx-design \ + sphinx-toolbox \ + sphinxcontrib-jquery + +# Install Catch2 +RUN git clone https://github.com/catchorg/Catch2.git /tmp/Catch2 && \ + cmake -S /tmp/Catch2 -B /tmp/Catch2/build -DBUILD_TESTING=OFF && \ + cmake --build /tmp/Catch2/build --target install && \ + rm -rf /tmp/Catch2 + +# Create a non-root user +RUN useradd -m -u 1000 -s /bin/bash developer && \ + echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Create source and build directories +RUN mkdir /source && \ + chown developer:developer /source && \ + mkdir /build && \ + chown developer:developer /build + +# Set user and working directory +USER developer +WORKDIR /build + +# Set default command +CMD ["/bin/bash"] diff --git a/dev/container/README.md b/dev/container/README.md new file mode 100644 index 00000000..91da334c --- /dev/null +++ b/dev/container/README.md @@ -0,0 +1,40 @@ +# Cetmodules Development Container + +This directory contains a `Dockerfile` to create a containerized development environment for `cetmodules`. + +## Building the Image + +To build the Docker image, run the following command from the root of the repository: + +```bash +docker build -t cetmodules-dev dev/container +``` + +## Running the Container + +To run the container with the `cetmodules` source code mounted, execute the following command from the root of the repository: + +```bash +docker run -it --rm \ + --user "$(id -u):$(id -g)" \ + -v "$(pwd):/source" \ + cetmodules-dev +``` + +This command will start an interactive shell inside the container. + +### Command Explanation: + +* `-it`: Runs the container in interactive mode with a TTY. +* `--rm`: Automatically removes the container when it exits. +* `--user "$(id -u):$(id -g)"`: Runs the container with your host user and group ID. This ensures that files created in the mounted volume have the correct ownership on your host machine. +* `-v "$(pwd):/source"`: Mounts the current directory (the `cetmodules` source) into the `/source` directory inside the container. +* `cetmodules-dev`: The name of the image to run. + +Once inside the container, you can perform an out-of-source build like this: + +```bash +cmake -S /source -B . -DBUILD_DOCS=ON +cmake --build . +ctest +``` From 67b9fdcf84137ca4e4612dab94cdaca22fdb8063 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 16:39:11 +0000 Subject: [PATCH 4/8] fix(dev): Add --break-system-packages to Dockerfile This commit resolves a build failure in the development container. Recent versions of Python in Ubuntu/Debian images prevent `pip` from installing packages globally to avoid conflicts with the system's package manager. This change adds the `--break-system-packages` flag to the `pip3 install` command in the `Dockerfile` to override this protection, which is a safe and necessary step within a self-contained container. --- build.log | 1 + dev/container/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 build.log diff --git a/build.log b/build.log new file mode 100644 index 00000000..34fc6ea6 --- /dev/null +++ b/build.log @@ -0,0 +1 @@ +ERROR: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping": dial unix /var/run/docker.sock: connect: permission denied diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile index ab536c41..b954d0c2 100644 --- a/dev/container/Dockerfile +++ b/dev/container/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # Install Python packages -RUN pip3 install --no-cache-dir \ +RUN pip3 install --no-cache-dir --break-system-packages \ cmake \ sphinx \ sphinxcontrib-moderncmakedomain \ From 891258426e02e0ea6336d60f1912a3646592b507 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 16:45:01 +0000 Subject: [PATCH 5/8] fix(dev): Avoid UID conflict in Dockerfile This commit resolves a build failure in the development container caused by a UID conflict. The `useradd` command failed because UID 1000 was already in use in the base Ubuntu image. This change modifies the UID for the `developer` user to 5000 to avoid this conflict. --- dev/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile index b954d0c2..041f5928 100644 --- a/dev/container/Dockerfile +++ b/dev/container/Dockerfile @@ -32,7 +32,7 @@ RUN git clone https://github.com/catchorg/Catch2.git /tmp/Catch2 && \ rm -rf /tmp/Catch2 # Create a non-root user -RUN useradd -m -u 1000 -s /bin/bash developer && \ +RUN useradd -m -u 5000 -s /bin/bash developer && \ echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers # Create source and build directories From 45d7ae904e84e9240ce959d17cb299fb2a443317 Mon Sep 17 00:00:00 2001 From: Chris Green Date: Wed, 10 Dec 2025 11:29:54 -0600 Subject: [PATCH 6/8] Dockerfile tweaks and documentation --- .gitignore | 6 +++--- build.log | 1 - dev/container/Dockerfile | 9 +++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) delete mode 100644 build.log diff --git a/.gitignore b/.gitignore index 2674d21c..9b28b8e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/build/ -/venv/ -venv +/build +/build.log +/venv diff --git a/build.log b/build.log deleted file mode 100644 index 34fc6ea6..00000000 --- a/build.log +++ /dev/null @@ -1 +0,0 @@ -ERROR: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping": dial unix /var/run/docker.sock: connect: permission denied diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile index 041f5928..60535867 100644 --- a/dev/container/Dockerfile +++ b/dev/container/Dockerfile @@ -1,3 +1,12 @@ +# Dockerfile for building Cetmodules development image. + +# Podman instructions for building and uploading tagged images: +# $ DATE="$(date +"%Y-%m-%d")" +# $ podman build --tag cetmodules-dev:$DATE . +# $ podman login ghcr.io --username -p $(gh auth token) +# $ podman push cetmodules-dev:$DATE ghcr.io/fnalssi/cetmodules-dev:$DATE +# ... and optionally push with destination tag "latest" + # Base image FROM ubuntu:latest From b7561f9bbdc79d4d98cf8c3eae088691c2aeec69 Mon Sep 17 00:00:00 2001 From: Chris Green Date: Fri, 12 Dec 2025 11:55:30 -0600 Subject: [PATCH 7/8] Add missing system requirements --- dev/container/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile index 60535867..0ca8128d 100644 --- a/dev/container/Dockerfile +++ b/dev/container/Dockerfile @@ -20,6 +20,8 @@ RUN apt-get update && \ git \ doxygen \ graphviz \ + m4 \ + ninja-build \ python3 \ python3-pip \ sudo && \ From 05c27d589071c42fddb6180bec0d5043105ea17d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 18:20:39 +0000 Subject: [PATCH 8/8] feat(devcontainer): Improve UID/GID handling and volume mounts This commit introduces a more robust and user-friendly development container setup. It replaces the previous mechanism of relying on the `--user` flag with an entrypoint script that dynamically adjusts the in-container `developer` user's UID and GID to match the host user's. This is a best-practice pattern for pre-built images that solves file ownership issues on mounted volumes. The key changes include: - An `entrypoint.sh` script to manage user mapping at runtime. - Use of `gosu` for secure privilege dropping. - An updated `Dockerfile` to incorporate the entrypoint. - Revised `README.md` with clear instructions for running the container with both `/source` and `/build` volumes mounted. fix(devcontainer): Use non-reserved variable names in entrypoint This commit fixes a bug in the `entrypoint.sh` script that caused the container to fail on startup. The script was using the reserved bash variable `UID`, which is readonly. This resulted in an error when the script attempted to assign a new value to it. The fix renames the conflicting variables from `UID` and `GID` to `TARGET_UID` and `TARGET_GID` respectively, resolving the runtime error. fix(devcontainer): Prevent entrypoint from changing host source permissions This commit corrects a critical bug in the `entrypoint.sh` script that caused it to recursively change the ownership of the mounted `/source` directory, altering the user's project files on the host. The `chown -R` command in the script is now restricted to only the `/build` and `/home/developer` directories. This ensures that the container has correct write permissions for build artifacts and its home directory, while leaving the ownership of the user's source code untouched. This change makes the development container safe to use and prevents it from having unintended and destructive side effects on the host system. revert(devcontainer): Remove entrypoint and use --user for UID/GID This commit reverts the entrypoint-based approach and returns to a simpler, more compatible method for handling user permissions that works correctly with both Docker and Podman. The previous entrypoint-based solution, while a common pattern for Docker, is incompatible with Podman's user namespace mapping (`--userns=keep-id`). This incompatibility led to incorrect file ownership on the host's build directory. The corrected approach is to: 1. Remove the `entrypoint.sh` script entirely. 2. Simplify the `Dockerfile` by removing the `gosu` dependency and entrypoint logic. 3. Make the `/source` and `/build` directories inside the container world-writable (`chmod 777`). 4. Use the standard `--user "$(id -u):$(id -g)"` flag when running the container. This method allows the user specified on the command line to write to the mounted volumes without permission errors and ensures that the created files have the correct ownership on the host, which is the desired behavior for both Podman and Docker. The `README.md` has been updated to reflect this final, correct usage. fix(devcontainer): Remove developer user for Podman compatibility This commit provides the final, correct implementation for the development container, ensuring compatibility with Podman's user namespace features. The previous approach of creating a `developer` user inside the `Dockerfile` conflicted with Podman's user mapping when the `--user` flag was used. This resulted in the user inside the container not having the expected ownership of the mounted `/build` volume. The solution is to remove the `developer` user entirely from the `Dockerfile`. The image is now prepared with world-writable `/source` and `/build` directories, making it a generic environment ready to be used by any user ID passed via the `--user` flag. This is the simplest and most robust solution, guaranteeing correct file ownership on mounted volumes for both Docker and Podman users. docs(devcontainer): Add correct run instructions for Docker and Podman This commit updates the `README.md` to provide clear and distinct instructions for running the development container with Docker and rootless Podman. The previous instructions were a source of confusion and permission errors due to fundamental differences in how Docker and rootless Podman handle user namespaces. The new documentation clarifies that: - Docker users should continue to use `--user "$(id -u):$(id -g)"` to ensure correct file ownership. - Rootless Podman users should run as the default `root` user inside the container. Podman's user namespace will safely map this to their user on the host, ensuring correct file ownership on mounted volumes. This change, combined with the simplified `Dockerfile`, provides a robust and easy-to-use solution for all users. --- dev/container/Dockerfile | 17 +++++------------ dev/container/README.md | 35 ++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/dev/container/Dockerfile b/dev/container/Dockerfile index 0ca8128d..ba90f986 100644 --- a/dev/container/Dockerfile +++ b/dev/container/Dockerfile @@ -42,18 +42,11 @@ RUN git clone https://github.com/catchorg/Catch2.git /tmp/Catch2 && \ cmake --build /tmp/Catch2/build --target install && \ rm -rf /tmp/Catch2 -# Create a non-root user -RUN useradd -m -u 5000 -s /bin/bash developer && \ - echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - -# Create source and build directories -RUN mkdir /source && \ - chown developer:developer /source && \ - mkdir /build && \ - chown developer:developer /build - -# Set user and working directory -USER developer +# Create source and build directories and make them world-writable +RUN mkdir /source /build && \ + chmod 777 /source /build + +# Set working directory WORKDIR /build # Set default command diff --git a/dev/container/README.md b/dev/container/README.md index 91da334c..09f244e7 100644 --- a/dev/container/README.md +++ b/dev/container/README.md @@ -4,32 +4,49 @@ This directory contains a `Dockerfile` to create a containerized development env ## Building the Image -To build the Docker image, run the following command from the root of the repository: +To build the image, run the following command from the root of the repository: ```bash +# For Docker or Podman docker build -t cetmodules-dev dev/container ``` ## Running the Container -To run the container with the `cetmodules` source code mounted, execute the following command from the root of the repository: +The command to run the container differs between Docker and Podman due to differences in how they handle user namespaces. + +First, create a local `build` directory if it does not already exist: + +```bash +mkdir -p build +``` + +### For Docker Users + +Docker users should map their host user ID directly to the container to ensure correct file ownership on mounted volumes. ```bash docker run -it --rm \ --user "$(id -u):$(id -g)" \ -v "$(pwd):/source" \ + -v "$(pwd)/build:/build" \ cetmodules-dev ``` -This command will start an interactive shell inside the container. +### For Podman Users (Rootless) + +Rootless Podman uses user namespaces to map your host user to the `root` user (UID 0) inside the container. To ensure you have permission to write to mounted volumes, you should run as `root` inside the container. Any files created in the mounted volumes will be correctly owned by your user on the host. + +```bash +podman run -it --rm \ + -v "$(pwd):/source" \ + -v "$(pwd)/build:/build" \ + cetmodules-dev +``` +*(Note: Running as `root` is the intended usage for rootless Podman and is safe because you are in an unprivileged user namespace.)* -### Command Explanation: -* `-it`: Runs the container in interactive mode with a TTY. -* `--rm`: Automatically removes the container when it exits. -* `--user "$(id -u):$(id -g)"`: Runs the container with your host user and group ID. This ensures that files created in the mounted volume have the correct ownership on your host machine. -* `-v "$(pwd):/source"`: Mounts the current directory (the `cetmodules` source) into the `/source` directory inside the container. -* `cetmodules-dev`: The name of the image to run. +### Usage Once inside the container, you can perform an out-of-source build like this: