Skip to content

Commit 36d35fe

Browse files
Development setup script and analogous Dockerfile (#36)
* 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. * Prelims for container definition * 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. * 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. * 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. * Dockerfile tweaks and documentation * Add missing system requirements * 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. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 8d5fcd8 commit 36d35fe

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/build
2+
/build.log
3+
/venv

dev/container/.dummy

Whitespace-only changes.

dev/container/Dockerfile

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Dockerfile for building Cetmodules development image.
2+
3+
# Podman instructions for building and uploading tagged images:
4+
# $ DATE="$(date +"%Y-%m-%d")"
5+
# $ podman build --tag cetmodules-dev:$DATE .
6+
# $ podman login ghcr.io --username <username> -p $(gh auth token)
7+
# $ podman push cetmodules-dev:$DATE ghcr.io/fnalssi/cetmodules-dev:$DATE
8+
# ... and optionally push with destination tag "latest"
9+
10+
# Base image
11+
FROM ubuntu:latest
12+
13+
# Set non-interactive frontend to avoid prompts
14+
ENV DEBIAN_FRONTEND=noninteractive
15+
16+
# Install system dependencies
17+
RUN apt-get update && \
18+
apt-get install -y --no-install-recommends \
19+
build-essential \
20+
git \
21+
doxygen \
22+
graphviz \
23+
m4 \
24+
ninja-build \
25+
python3 \
26+
python3-pip \
27+
sudo && \
28+
rm -rf /var/lib/apt/lists/*
29+
30+
# Install Python packages
31+
RUN pip3 install --no-cache-dir --break-system-packages \
32+
cmake \
33+
sphinx \
34+
sphinxcontrib-moderncmakedomain \
35+
sphinx-design \
36+
sphinx-toolbox \
37+
sphinxcontrib-jquery
38+
39+
# Install Catch2
40+
RUN git clone https://github.com/catchorg/Catch2.git /tmp/Catch2 && \
41+
cmake -S /tmp/Catch2 -B /tmp/Catch2/build -DBUILD_TESTING=OFF && \
42+
cmake --build /tmp/Catch2/build --target install && \
43+
rm -rf /tmp/Catch2
44+
45+
# Create source and build directories and make them world-writable
46+
RUN mkdir /source /build && \
47+
chmod 777 /source /build
48+
49+
# Set working directory
50+
WORKDIR /build
51+
52+
# Set default command
53+
CMD ["/bin/bash"]

dev/container/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Cetmodules Development Container
2+
3+
This directory contains a `Dockerfile` to create a containerized development environment for `cetmodules`.
4+
5+
## Building the Image
6+
7+
To build the image, run the following command from the root of the repository:
8+
9+
```bash
10+
# For Docker or Podman
11+
docker build -t cetmodules-dev dev/container
12+
```
13+
14+
## Running the Container
15+
16+
The command to run the container differs between Docker and Podman due to differences in how they handle user namespaces.
17+
18+
First, create a local `build` directory if it does not already exist:
19+
20+
```bash
21+
mkdir -p build
22+
```
23+
24+
### For Docker Users
25+
26+
Docker users should map their host user ID directly to the container to ensure correct file ownership on mounted volumes.
27+
28+
```bash
29+
docker run -it --rm \
30+
--user "$(id -u):$(id -g)" \
31+
-v "$(pwd):/source" \
32+
-v "$(pwd)/build:/build" \
33+
cetmodules-dev
34+
```
35+
36+
### For Podman Users (Rootless)
37+
38+
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.
39+
40+
```bash
41+
podman run -it --rm \
42+
-v "$(pwd):/source" \
43+
-v "$(pwd)/build:/build" \
44+
cetmodules-dev
45+
```
46+
*(Note: Running as `root` is the intended usage for rootless Podman and is safe because you are in an unprivileged user namespace.)*
47+
48+
49+
### Usage
50+
51+
Once inside the container, you can perform an out-of-source build like this:
52+
53+
```bash
54+
cmake -S /source -B . -DBUILD_DOCS=ON
55+
cmake --build .
56+
ctest
57+
```

dev/setup_cetmodules_dev.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/bash
2+
3+
# Exit immediately if a command exits with a non-zero status.
4+
set -e
5+
6+
# --- OS Detection ---
7+
if [ -f /etc/os-release ]; then
8+
. /etc/os-release
9+
if [[ "$ID" == "ubuntu" ]]; then
10+
PACKAGE_MANAGER="apt-get"
11+
BUILD_DEPS="build-essential"
12+
elif [[ "$ID" == "almalinux" ]]; then
13+
PACKAGE_MANAGER="dnf"
14+
BUILD_DEPS="gcc-c++"
15+
else
16+
echo "Unsupported operating system: $ID"
17+
exit 1
18+
fi
19+
else
20+
echo "/etc/os-release not found. Cannot determine operating system."
21+
exit 1
22+
fi
23+
24+
# --- System Dependency Installation ---
25+
echo "Updating package lists..."
26+
sudo $PACKAGE_MANAGER update -y
27+
28+
echo "Installing system dependencies..."
29+
sudo $PACKAGE_MANAGER install -y git doxygen graphviz python3-venv $BUILD_DEPS
30+
31+
# --- Python Environment Setup ---
32+
echo "Setting up Python virtual environment..."
33+
python3 -m venv venv
34+
source venv/bin/activate
35+
36+
echo "Installing Python packages (CMake, Sphinx, etc.)..."
37+
pip install cmake sphinx sphinxcontrib-moderncmakedomain sphinx-design sphinx-toolbox sphinxcontrib-jquery
38+
39+
# --- Catch2 Installation ---
40+
echo "Cloning and installing Catch2..."
41+
git clone https://github.com/catchorg/Catch2.git
42+
cd Catch2
43+
cmake -S . -B build -DBUILD_TESTING=OFF
44+
sudo cmake --build build --target install
45+
cd ..
46+
rm -rf Catch2
47+
48+
# --- cetmodules Build and Test ---
49+
echo "Cloning, building, and testing cetmodules..."
50+
git clone https://github.com/FNALssi/cetmodules.git
51+
cd cetmodules
52+
cmake -S . -B build -DBUILD_DOCS=ON
53+
cmake --build build
54+
ctest --test-dir build
55+
56+
# --- Documentation Build ---
57+
echo "Building cetmodules documentation..."
58+
cmake --build build --target doc-cetmodules-reference
59+
cd ..
60+
61+
# --- Completion ---
62+
echo ""
63+
echo "----------------------------------------------------"
64+
echo "Development environment setup for cetmodules is complete!"
65+
echo "To activate the Python virtual environment, run:"
66+
echo "source venv/bin/activate"
67+
echo "----------------------------------------------------"

0 commit comments

Comments
 (0)