Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
45a880e
VSCode dev container setup and workspace config
greenc-FNAL Oct 28, 2025
b91b621
Assorted improvements
greenc-FNAL Oct 28, 2025
118ec55
Remove VSCode user nonsense from `Dockerfile`
greenc-FNAL Jan 6, 2026
164d4d7
Streamline `ci` container for current workflows
greenc-FNAL Jan 6, 2026
141c6bc
Remove development environment-specific workspace configuration
greenc-FNAL Jan 6, 2026
960c98c
Improve VSCode shell integration in devcontainers
greenc-FNAL Jan 6, 2026
393444d
Improve image creation instructions
greenc-FNAL Jan 6, 2026
e84a02d
Enable Spack modification by user `vscode` within a devcontainer
greenc-FNAL Jan 6, 2026
48efcc7
Remove unneeded bind mount from devcontainer
greenc-FNAL Jan 6, 2026
05156df
Disable unneeded/unhelpful message
greenc-FNAL Jan 6, 2026
4bb4dfc
Remove `codecov.codecov` from devcontainer config due to conflicts
greenc-FNAL Jan 6, 2026
4b345d1
Apply suggestions from code review
greenc-FNAL Jan 7, 2026
22de26f
Ensure `parallelism` `ARG` is available in base and dev targets.
greenc-FNAL Jan 7, 2026
856bcbf
Initial plan (#226)
Copilot Jan 7, 2026
6645128
Confirm executable permissions on devcontainer wrapper scripts #227
Copilot Jan 7, 2026
a6d80c7
Confirm executable permissions on devcontainer wrapper scripts #228
Copilot Jan 7, 2026
1dd7849
Validate Python site-packages symlink in devcontainer build (#229)
Copilot Jan 7, 2026
3f6fd15
Update ci/Dockerfile comment
greenc-FNAL Jan 7, 2026
d4f7f0a
Add gersemi to dev container
greenc-FNAL Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
FROM ghcr.io/framework-r-d/phlex-dev:latest

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=1000
ARG SPACK_GID=2000

# Validate Python site-packages symlink
RUN <<'VALIDATE_PYTHON_SYMLINK'
set -euo pipefail
shopt -s nullglob

SPACK_VIEW_LIB=/opt/spack-environments/phlex-ci/.spack-env/view/lib

# Find all versioned Python site-packages directories
python_dirs=("$SPACK_VIEW_LIB"/python3.*)
count=${#python_dirs[@]}

# Ensure exactly one versioned Python site-packages directory exists
if [ $count -eq 0 ]; then
echo "ERROR: No versioned Python site-packages directory found in $SPACK_VIEW_LIB" >&2
exit 1
elif [ $count -gt 1 ]; then
echo "ERROR: Multiple versioned Python site-packages directories found in $SPACK_VIEW_LIB:" >&2
printf ' %s\n' "${python_dirs[@]}" >&2
exit 1
fi

# Get the single Python directory and its basename
python_dir="${python_dirs[0]}"
python_basename=$(basename "$python_dir")

# Create the symlink if it doesn't exist or update it if it's incorrect
python_link="$SPACK_VIEW_LIB/python"
if [ -L "$python_link" ]; then
current_target=$(readlink "$python_link")
if [ "$current_target" != "$python_basename" ]; then
echo "Updating $python_link -> $python_basename"
ln -sfn "$python_basename" "$python_link"
fi
elif [ -e "$python_link" ]; then
echo "ERROR: $python_link exists but is not a symlink" >&2
exit 1
else
echo "Creating $python_link -> $python_basename"
ln -sn "$python_basename" "$python_link"
fi

# Verify the symlink is correct
if [ ! -L "$python_link" ]; then
echo "ERROR: Failed to create symlink at $python_link" >&2
exit 1
fi

# Verify the symlink target is a valid directory
if [ ! -d "$python_link" ]; then
echo "ERROR: Symlink $python_link does not point to a valid directory" >&2
exit 1
fi

echo "Python symlink validated: $python_link -> $(readlink "$python_link")"
VALIDATE_PYTHON_SYMLINK

# Create the user and add to spack group
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID --create-home $USERNAME \
&& usermod -aG $SPACK_GID $USERNAME \
&& echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME

# Setup entrypoint usage in bashrc
RUN echo '. /entrypoint.sh' >> /home/$USERNAME/.bashrc
3 changes: 3 additions & 0 deletions .devcontainer/cmake_wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
. /entrypoint.sh
exec cmake "$@"
3 changes: 3 additions & 0 deletions .devcontainer/ctest_wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
. /entrypoint.sh
exec ctest "$@"
94 changes: 94 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"name": "Phlex CI Dev Container",
"build": {
"dockerfile": "Dockerfile",
"options": [
"--format=docker"
]
},
"workspaceFolder": "/workspaces/phlex",
"remoteUser": "vscode",
"containerEnv": {
"GH_CONFIG_DIR": "/home/vscode/.config/gh"
},
"mounts": [
"source=${env:HOME}/.config/gh,target=/home/vscode/.config/gh,type=bind,readonly,required=false"
],
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash",
"args": [
"-i"
],
"icon": "terminal-bash"
}
},
"terminal.integrated.shellIntegration.suggestEnablement": false,
"python.defaultInterpreterPath": "/opt/spack-environments/phlex-ci/.spack-env/view/bin/python",
"python.analysis.extraPaths": [
"${workspaceFolder}/build",
"/opt/spack-environments/phlex-ci/.spack-env/view/lib/root",
"/opt/spack-environments/phlex-ci/.spack-env/view/lib/python/site-packages"
],
"cmake.cmakePath": "${workspaceFolder}/.devcontainer/cmake_wrapper.sh",
"cmake.ctestPath": "${workspaceFolder}/.devcontainer/ctest_wrapper.sh",
"cmake.generator": "Ninja",
"C_Cpp.default.cStandard": "c17",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.default.intelliSenseMode": "linux-gcc-x64",
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
"python.languageServer": "Pylance",
"python.analysis.typeCheckingMode": "basic",
"python.analysis.diagnosticMode": "workspace"
},
"extensions": [
"charliermarsh.ruff",
"cheshirekow.cmake-format",
"chrisjsewell.myst-tml-syntax",

"davidanson.vscode-markdownlint",
"donjayamanne.githistory",
"dotjoshjohnson.xml",
"eamodio.gitlens",
"github.copilot",
"github.copilot-chat",
"github.vscode-github-actions",
"github.vscode-pull-request-github",
"jebbs.plantuml",
"lextudio.iis",
"lextudio.restructuredtext",
"lextudio.restructuredtext-pack",
"lfs.vscode-emacs-friendly",
"links-req-tracer.links-requirement-tracer",

"ms-python.debugpy",
"ms-python.mypy-type-checker",
"ms-python.pylint",

"ms-python.vscode-pylance",
"ms-python.vscode-python-envs",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools",
"ms-vscode.cpptools-extension-pack",
"ms-vscode.cpptools-themes",
"ms-vscode.hexeditor",
"ms-vscode.live-server",
"ms-vscode.makefile-tools",
"ms-vscode.vscode-websearchforcopilot",
"redhat.vscode-yaml",

"shd101wyy.markdown-preview-enhanced",
"swyddfa.esbonio",
"trond-snekvik.simple-rst",
"twxs.cmake",
"vadimcn.vscode-lldb",
"wequick.coverage-gutters",
"xaver.clang-format"
]
}
}
}
80 changes: 38 additions & 42 deletions ci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
# Multi-target Dockerfile for building the Phlex CI and development images.

# Podman instructions for building tagged images with this file:
# $ podman build --target ci --tag phlex-ci:<tag> .
# $ podman build --target dev --tag phlex-dev:<tag> .
#
# $ podman build --format docker [-v <local-spack-cache>:/build-cache] --target ci --tag phlex-ci:<tag> .
# $ podman build --format docker [-v <local-spack-cache>:/build-cache] --target dev --tag phlex-dev:<tag> .
# $ podman login ghcr.io --username <username> -p <token>
# $ podman push phlex-ci:<tag> ghcr.io/framework-r-d/phlex-ci:<tag>
# $ podman push phlex-dev:<tag> ghcr.io/framework-r-d/phlex-dev:<tag>
# ... and optionally push either image as "latest".

# where <tag> is the date (e.g. "2025-08-12").

FROM gcc:15.2.0 AS base
ARG parallelism=18

FROM gcc:15.2.0 AS base
ARG parallelism

ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENV SPACK_USER_CONFIG_PATH=/dev/null
Expand Down Expand Up @@ -72,8 +76,6 @@ COPY entrypoint.sh /entrypoint.sh
RUN <<'CONFIGURE_SPACK_DEFAULTS'
set -euo pipefail

. /spack/share/spack/setup-env.sh

SPACK_REPO_ROOT=/opt/spack-repos
rm -rf "$SPACK_REPO_ROOT/fnal_art" "$SPACK_REPO_ROOT/phlex-spack-recipes"
mkdir -p "$SPACK_REPO_ROOT"
Expand All @@ -83,12 +85,11 @@ chgrp -R spack "$SPACK_REPO_ROOT"
chmod -R g+rwX "$SPACK_REPO_ROOT"
find "$SPACK_REPO_ROOT" -type d -exec chmod g+s {} +

spack --timestamp repo remove phlex >/dev/null 2>&1 || true
spack --timestamp repo remove fnal_art >/dev/null 2>&1 || true
spack --timestamp repo add --scope site /opt/spack-repos/phlex-spack-recipes/spack_repo/phlex
spack --timestamp repo add --scope site /opt/spack-repos/fnal_art/spack_repo/fnal_art
spack --timestamp repo set --scope site --destination /spack/var/spack/repos/builtin builtin
. /spack/share/spack/setup-env.sh

spack --timestamp repo add --scope site $SPACK_REPO_ROOT/phlex-spack-recipes/spack_repo/phlex
spack --timestamp repo add --scope site $SPACK_REPO_ROOT/fnal_art/spack_repo/fnal_art
spack --timestamp repo set --scope site --destination $SPACK_REPO_ROOT builtin
spack --timestamp compiler find


Expand Down Expand Up @@ -154,7 +155,7 @@ set -euo pipefail

spack --timestamp install --fail-fast -j $parallelism -p 1 \
--no-add --only-concrete --no-check-signature \
cmake lcov ninja py-cmake-format py-gcovr py-pip
cmake lcov ninja py-gcovr py-pip

spack clean -dfs
INSTALL_TOOLING_CORE
Expand Down Expand Up @@ -223,19 +224,6 @@ if [ -d "/build-cache" ]; then
fi
EXPORT_BUILDCACHE

########################################################################
# Install ancillary Python tools (ruff) outside Spack

RUN <<'INSTALL_PYTHON_TOOLS'
set -euo pipefail

# Use pip to install tooling that is not packaged in Spack
. /entrypoint.sh

PYTHONDONTWRITEBYTECODE=1 pip --isolated --no-input --disable-pip-version-check --no-cache-dir install --prefix /usr/local ruff
rm -rf ~/.spack
INSTALL_PYTHON_TOOLS

########################################################################
# Remove transient files used during build

Expand All @@ -257,12 +245,32 @@ USER root
# Dev image additions (tooling and dev user configuration)

FROM base AS dev
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=1000
ENV HOME=/home/$USERNAME
ARG parallelism
ENV SPACK_GROUP=spack

########################################################################
# Install developer tooling (py-cmake-format, ruff)

RUN <<'INSTALL_DEV_TOOLING'
set -euo pipefail

# Install developer tooling not needed for CI
. /entrypoint.sh

# Install py-cmake-format via Spack
spack --timestamp install --fail-fast -j $parallelism -p 1 \
--no-add --only-concrete --no-check-signature \
py-cmake-format

spack clean -dfs

# Install ruff and gersemi via pip
PYTHONDONTWRITEBYTECODE=1 \
pip --isolated --no-input --disable-pip-version-check --no-cache-dir install \
--prefix /usr/local ruff gersemi
rm -rf ~/.spack
INSTALL_DEV_TOOLING

########################################################################
# Install additional system packages needed for developer tooling

Expand All @@ -283,16 +291,7 @@ INSTALL_DEV_PACKAGES
########################################################################
# Create developer user and grant access to the shared spack group

RUN <<'CREATE_DEV_USER'
set -euo pipefail

# Create developer user and grant access to the shared spack group
groupadd --gid $USER_GID $USERNAME
useradd --uid $USER_UID --gid $USER_GID --create-home $USERNAME
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
usermod -aG $SPACK_GROUP $USERNAME
CREATE_DEV_USER
# User creation moved to .devcontainer/Dockerfile to support flexible runtime environments

########################################################################
# Prepare workspace directory writable by the developer group
Expand All @@ -301,8 +300,7 @@ RUN <<'PREP_DEV_WORKSPACE'
set -euo pipefail

# Prepare workspace directory writable by the developer group
mkdir -p /workspaces/phlex
chown $USERNAME:$USERNAME /workspaces
mkdir -p /workspaces
chgrp $SPACK_GROUP /workspaces
chmod g+rwX /workspaces
PREP_DEV_WORKSPACE
Expand Down Expand Up @@ -343,7 +341,5 @@ apt-get clean
rm -rf /var/lib/apt/lists/*
INSTALL_GH_CLI

USER $USERNAME
WORKDIR /workspaces/phlex
SHELL ["/bin/bash", "-c"]
HEALTHCHECK CMD curl -f https://github.com || exit 1
Loading
Loading