Files
cmake/.devcontainer/devcontainer.json
Taylor Braun-Jones f1b6b3a6f0 devcontainer: Run local customization hooks through the container's life
The container ran a developer's own `hooks/root.sh` and `hooks/user.sh`
while the image was built, and nothing of theirs afterwards.  A
customization that has to start something, or to reach the source tree,
had nowhere to run: the tree is not mounted during the build, and the one
lifecycle command the configuration used was spoken for by the status
report.

Run an optional script per phase through `run-hooks.sh`, and offer five:
`initialize` on the host, `build` in the image, and `post-create`,
`post-start` and `post-attach` in the container.  A failing `build` hook
fails the image build, because an image whose customizations did not
apply is quietly wrong; the rest are reported and otherwise ignored, so
that a typo in a personal hook cannot leave its author unable to open the
container in order to fix it.

The two build hooks become one, running as the container user, who may
`sudo`: one hook that reaches either user is simpler to write against
than two that each reach one.  Every hook is told where it lives, and
every hook but the build one is given a directory to keep state in,
beside the hooks rather than among them because state is written by
whatever they start rather than by hand.  `.dockerignore` keeps that
directory out of the build context, which state written as `root` would
otherwise make unreadable.
2026-09-09 18:35:57 -04:00

86 lines
2.6 KiB
JSON

{
"name": "CMake",
"build": {
"dockerfile": "Dockerfile"
},
"remoteUser": "cmake-dev",
// Name the workspace path explicitly rather than take the default a tool
// picks for itself, so that the path is the same under every tool and in
// the CI job of `.gitlab/ci/devcontainer-run.sh`, which mounts the source
// tree itself. `create_user.sh` creates the directory and gives it to the
// container user.
"workspaceFolder": "/home/cmake-dev/workspace",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/cmake-dev/workspace,type=bind",
"containerEnv": {
"GITLAB_HOST": "gitlab.kitware.com"
},
"remoteEnv": {
"GITLAB_CLIENT_ID": "${localEnv:GITLAB_CLIENT_ID}",
"GITLAB_TOKEN": "${localEnv:GITLAB_TOKEN}"
},
"mounts": [
{
"type": "volume",
"source": "cmake-dev-ccache",
"target": "/home/cmake-dev/.cache/ccache"
},
{
"type": "volume",
"source": "cmake-dev-glab-cli",
"target": "/home/cmake-dev/.config/glab-cli"
}
],
// Run the optional local customization hooks. Each phase is a no-op unless
// the developer has written that hook. See `Help/dev/devcontainer.rst`.
//
// Each is written as a named entry, the form that runs entries concurrently
// and says which one is speaking. Only `postAttachCommand` has two, but
// naming the hook everywhere keeps its output labeled the same way, and
// leaves room for a second entry beside it.
//
// `initializeCommand` runs on the host, so unlike the others it needs a
// POSIX shell there; naming `sh` explicitly, in the form that starts no
// shell of its own, is what makes that work outside a Unix host.
"initializeCommand": {
"hooks": [
"sh",
"${localWorkspaceFolder}/.devcontainer/run-hooks.sh",
"initialize"
]
},
"postCreateCommand": {
"hooks": [
"${containerWorkspaceFolder}/.devcontainer/run-hooks.sh",
"post-create"
]
},
"postStartCommand": {
"hooks": [
"${containerWorkspaceFolder}/.devcontainer/run-hooks.sh",
"post-start"
]
},
"postAttachCommand": {
"setup-status": ["${containerWorkspaceFolder}/.devcontainer/setup-status.sh"],
"hooks": [
"${containerWorkspaceFolder}/.devcontainer/run-hooks.sh",
"post-attach"
]
},
"customizations": {
"vscode": {
"extensions": [
"EditorConfig.EditorConfig",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools",
"lextudio.restructuredtext",
"llvm-vs-code-extensions.vscode-clangd"
],
"settings": {
"C_Cpp.clang_format_path": "/usr/bin/clang-format-18",
"cmake.configureOnOpen": false
}
}
}
}