Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f34a5d1
ci: migrate protobuf install to vcpkg in CI
Kybxd May 28, 2026
6cdd153
feat: replace protobuf submodule with vcpkg
Kybxd May 28, 2026
0fe37c1
fix: export ACTIONS_RESULTS_URL in CI workflow
Kybxd May 28, 2026
632b81f
ci: replace vcpkg binary cache with actions/cache
Kybxd May 28, 2026
0021723
ci: update protobuf versions and restructure matrix config
Kybxd May 28, 2026
e2d9243
ci: update protoc setup to use v3 for all configs
Kybxd May 28, 2026
f7f7f14
ci: use setup-protoc v1 for legacy-v3 builds
Kybxd May 28, 2026
8061774
ci: update legacy protobuf version and unify setup-protoc
Kybxd May 28, 2026
145574e
docs: warn against RHEL protobuf packages
Kybxd May 28, 2026
47deb0c
fix: address PR review feedback for vcpkg migration
wenchy May 29, 2026
60885c3
docs: design spec for devcontainer
wenchy May 29, 2026
e8d4d10
docs: implementation plan for devcontainer
wenchy May 29, 2026
40e4328
feat(devcontainer): add base Dockerfile (Ubuntu 24.04 cpp image)
wenchy May 29, 2026
181863f
feat(devcontainer): add architecture detection
wenchy May 29, 2026
8a104df
feat(devcontainer): add Go 1.24.0
wenchy May 29, 2026
b18a038
feat(devcontainer): add buf 1.67.0
wenchy May 29, 2026
037f69d
feat(devcontainer): add vcpkg + protobuf via manifest mode
wenchy May 29, 2026
871a20d
feat(devcontainer): add .NET SDK 8.0 and Node.js 20 LTS
wenchy May 29, 2026
8541f94
feat(devcontainer): finalize CMAKE_PREFIX_PATH
wenchy May 29, 2026
04d2e09
feat(devcontainer): add devcontainer.json
wenchy May 29, 2026
841e727
docs(devcontainer): add .devcontainer/README.md
wenchy May 29, 2026
00bcb38
docs: recommend the devcontainer in repo README
wenchy May 29, 2026
8a583ba
docs(devcontainer): document stale-codegen trap
wenchy May 29, 2026
5fdb0da
fix(devcontainer): correct stale-codegen rm paths; drop stale README …
wenchy May 29, 2026
4f106f1
feat: add CLAUDE.md
wenchy May 29, 2026
384612c
chore: upgrade tableau to v0.16.0
wenchy Jun 1, 2026
6486e90
chore(devcontainer): fix GOPATH volume ownership and ignore dotnet ru…
Kybxd Jun 1, 2026
5813f69
chore(deps): bump buf.build/tableauio/tableau from v0.15.1 to v0.16.0
Kybxd Jun 1, 2026
e073d46
fix: permisions
wenchy Jun 1, 2026
3195ad5
feat(devcontainer): add Windows-container variant + centralize toolch…
wenchy Jun 1, 2026
c110c05
fix(ci): drop ${{ env.KEY }} from load-versions action description
wenchy Jun 1, 2026
09dc729
fix(ci): switch Docker daemon via dockerd --register-service, not Doc…
wenchy Jun 1, 2026
7f5ba11
fix(devcontainer): switch Windows base to mcr.microsoft.com/visualstu…
wenchy Jun 1, 2026
4e35924
fix(devcontainer): use dotnet-framework base for Windows container
wenchy Jun 1, 2026
f549d5a
fix(devcontainer): Windows Dockerfile aligns with Linux versions.env …
wenchy Jun 2, 2026
30a4567
fix(ci): resolve dockerd.exe via service registry, not Program Files …
wenchy Jun 2, 2026
bae2377
revert(devcontainer): drop Windows-container variant
wenchy Jun 2, 2026
23a38bf
refactor(devcontainer): flatten layout - one container, no subdirs
wenchy Jun 2, 2026
355aceb
perf(devcontainer): cache vcpkg binaries across builds
wenchy Jun 3, 2026
fcc3af1
feat: replace prepare.bat with cross-platform make.py
wenchy Jun 4, 2026
1c1eb09
fix(ci): drop standalone Vet step + legacy-v3 C# matrix
wenchy Jun 4, 2026
2e67189
fix: cpp manifest mode — toolchain flags on every host + dry-run safety
wenchy Jun 4, 2026
c421b9d
fix(vcpkg): use commit SHA, not tag SHA, for VCPKG_BASELINE_COMMIT
wenchy Jun 4, 2026
8f704ce
feat(make.py): pin protobuf via vcpkg on macOS/Linux too (vcpkg-every…
wenchy Jun 4, 2026
4547917
feat(vcpkg): pair vcpkg builtin-baseline with protobuf version
Kybxd Jun 5, 2026
aeb6ae1
fix(ci): disable x-gha binary cache for legacy vcpkg snapshot
Kybxd Jun 5, 2026
23ad629
fix(ci): exclude legacy-v3 on Windows (dead MSYS2 distfiles)
Kybxd Jun 5, 2026
0ee7c3b
docs(spec): remove TS from make.py + fix /.dockerenv heuristic
wenchy Jun 5, 2026
6dbf469
fix(make.py): tighten devcontainer detection to /opt/vcpkg/active
wenchy Jun 5, 2026
c8bfe19
refactor(make.py): drop TypeScript support from the tool surface
wenchy Jun 5, 2026
25a2931
chore(versions): drop NODE_VERSION pin
wenchy Jun 5, 2026
a78ef17
chore(devcontainer): drop Node.js install
wenchy Jun 5, 2026
059d4a5
chore(devcontainer): drop node from postcreate banner
wenchy Jun 5, 2026
d460045
docs(CLAUDE.md): drop TS commands and _lab/ts pointer
wenchy Jun 5, 2026
69ae0ca
chore: remove docs
wenchy Jun 5, 2026
a190a91
fix(test_make): use as_posix() for cross-platform path comparison
wenchy Jun 5, 2026
7607fdf
fix(devcontainer): apt-get update after adding Microsoft repo
wenchy Jun 5, 2026
b5b985e
feat(versions): variant-prefixed protobuf+vcpkg matrix in versions.env
wenchy Jun 5, 2026
273e648
chore: clean code and docs
wenchy Jun 5, 2026
698dc59
feat(cpp-loader): add util::GetExtension wrapper for protobuf v3.15.0…
Kybxd Jun 8, 2026
1d71db8
docs: specify language for command code block
Kybxd Jun 8, 2026
6d6541b
fix(setup): prepend buf dir to PATH after install
Kybxd Jun 8, 2026
a286f3d
feat(cpp): support older protobuf runtimes in tableau loader util
Kybxd Jun 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
241 changes: 241 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
# syntax=docker/dockerfile:1.7
# tableauio/loader devcontainer
#
# Single-stage, multi-arch (amd64 + arm64) image bringing the full
# C++/Go/.NET toolchain plus protobuf at the exact versions CI uses.
#
# All version pins are read from ./versions.env (the single source of
# truth shared with make.py and the CI workflows). To bump Go / buf /
# protobuf / .NET / vcpkg-baseline, edit that file — not this one.
#
# Build context is .devcontainer/ (the directory containing this file),
# so `COPY versions.env ...` resolves directly.

FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04

# ---------------------------------------------------------------------------
# Pull pinned versions from the shared file. We `COPY` it into a build-stage
# location and `source` it in every RUN that needs the values; ARG/ENV alone
# don't survive across RUN boundaries in BuildKit, so we re-source per layer.
# ---------------------------------------------------------------------------
COPY versions.env /opt/versions.env

# ---------------------------------------------------------------------------
# Architecture detection. BuildKit auto-populates TARGETARCH; we resolve it
# into per-arch download-name fragments (Go's tarball, buf's release asset,
# vcpkg triplet) and persist them to /opt/buildargs.env so later RUN layers
# can `source` them — Dockerfile ARGs don't survive across RUN boundaries.
# ---------------------------------------------------------------------------
ARG TARGETARCH
RUN <<EOF
set -eux
case "${TARGETARCH}" in
amd64) GO_ARCH=amd64; BUF_ARCH=x86_64; TRIPLET=x64-linux ;;
arm64) GO_ARCH=arm64; BUF_ARCH=aarch64; TRIPLET=arm64-linux ;;
*) echo "unsupported TARGETARCH: ${TARGETARCH}"; exit 1 ;;
esac
mkdir -p /opt
printf 'GO_ARCH=%s\nBUF_ARCH=%s\nVCPKG_TRIPLET=%s\n' \
"${GO_ARCH}" "${BUF_ARCH}" "${TRIPLET}" > /opt/buildargs.env
EOF

# ---------------------------------------------------------------------------
# Go — official tarball into /usr/local/go.
#
# PATH is set via ENV (not /etc/profile.d/) so non-interactive shells like
# the postCreateCommand and downstream RUNs see Go without sourcing profile.
# /home/vscode/go/bin lands `go install`-placed binaries on PATH automatically.
# ---------------------------------------------------------------------------
RUN <<EOF
set -eux
. /opt/versions.env
. /opt/buildargs.env
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" \
| tar -C /usr/local -xz
EOF
ENV PATH=/usr/local/go/bin:/home/vscode/go/bin:${PATH}

# ---------------------------------------------------------------------------
# buf — single-binary release on PATH.
# ---------------------------------------------------------------------------
RUN <<EOF
set -eux
. /opt/versions.env
. /opt/buildargs.env
curl -fsSL -o /usr/local/bin/buf \
"https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-Linux-${BUF_ARCH}"
chmod +x /usr/local/bin/buf
EOF

# ---------------------------------------------------------------------------
# vcpkg + protobuf via manifest mode.
#
# Pins (all from /opt/versions.env):
# VCPKG_BASELINE_COMMIT — same commit testing-cpp.yml's VCPKG_COMMIT and
# make.py's vcpkg setup use. Bumping vcpkg = bump that
# one line in versions.env.
# PROTOBUF_VERSION — defaults to versions.env's value (CI's primary).
# Override at build time:
# docker build --build-arg PROTOBUF_VERSION=3.21.12 ...
# devcontainer.json wires this to the LOADER_PROTOBUF_VERSION host env var.
#
# Why manifest mode: classic-mode `vcpkg install --x-version=...` is silently
# a no-op; only manifest mode + overrides actually pin the port version. The
# post-install assertion catches the case where vcpkg's resolution still picks
# a different port revision than requested.
# ---------------------------------------------------------------------------
ARG DEFAULT_VARIANT=
ARG PROTOBUF_VERSION=
ENV VCPKG_ROOT=/opt/vcpkg
# Tell vcpkg to share its compiled binaries via /vcpkg-binarycache. The
# directory is mounted from BuildKit's persistent cache via
# `RUN --mount=type=cache,...` below; that cache survives across
# `docker build` invocations on the same host (and across CI runs when
# `cache-to=type=gha,mode=max` is configured in the smoke workflow).
#
# The win: when an unrelated layer earlier in the Dockerfile changes
# (e.g. you bump BUF_VERSION in versions.env), Docker re-runs the vcpkg
# layer because its inputs changed, but vcpkg itself short-circuits the
# expensive ~15-30 min compile and just relinks the protobuf binaries
# from cache. First build pays the full cost; every later build with the
# same VCPKG_BASELINE_COMMIT + PROTOBUF_VERSION is fast.
ENV VCPKG_DEFAULT_BINARY_CACHE=/vcpkg-binarycache

# `_ARG_PROTOBUF_VERSION` captures the Dockerfile ARG via Dockerfile-level
# variable expansion BEFORE we source versions.env in the heredoc body
# (otherwise the file default would clobber the build-arg). Empty string
# means "no override; use file default".
#
# `--mount=type=cache,target=/vcpkg-binarycache` is a BuildKit cache
# mount: a directory whose contents persist across `docker build`
# invocations on this host (or, on CI, in the GHA cache when
# `cache-to=type=gha,mode=max` is set on the build action). vcpkg writes
# every compiled package into this dir, keyed by ABI hash; on a later
# build it skips the compile and uses the cached .zip directly. The
# directory is empty at the start of every fresh build — only its
# *contents* persist, not its mountpoint state — which is exactly what
# we want.
#
# `sharing=locked` serializes concurrent builds against the same cache
# (matters only on multi-builder hosts; safe default).
RUN --mount=type=cache,target=/vcpkg-binarycache,sharing=locked <<EOF
set -eux
_ARG_DEFAULT_VARIANT="${DEFAULT_VARIANT}"
_ARG_PROTOBUF_VERSION="${PROTOBUF_VERSION}"
. /opt/versions.env
. /opt/buildargs.env

# Prefer the build-arg variant when non-empty; otherwise versions.env's
# DEFAULT_VARIANT wins. Empty means "no override".
if [ -n "${_ARG_DEFAULT_VARIANT:-}" ]; then
DEFAULT_VARIANT="${_ARG_DEFAULT_VARIANT}"
fi

# Resolve the (PROTOBUF_VERSION, VCPKG_BASELINE_COMMIT) pair from the active
# variant. versions.env declares one row per variant (MODERN_*, LEGACY_V3_*);
# DEFAULT_VARIANT picks which one is in effect for this image build.
case "${DEFAULT_VARIANT:-modern}" in
modern)
PROTOBUF_VERSION="${MODERN_PROTOBUF_VERSION}"
VCPKG_BASELINE_COMMIT="${MODERN_VCPKG_BASELINE_COMMIT}"
;;
legacy-v3|legacy_v3)
PROTOBUF_VERSION="${LEGACY_V3_PROTOBUF_VERSION}"
VCPKG_BASELINE_COMMIT="${LEGACY_V3_VCPKG_BASELINE_COMMIT}"
;;
*)
echo "[error] unknown DEFAULT_VARIANT: ${DEFAULT_VARIANT}" >&2
exit 1
;;
esac

# Surgical override: when LOADER_PROTOBUF_VERSION is set, use it for the
# protobuf pin only — keep the variant's vcpkg baseline. Mostly useful for
# bisecting protobuf releases against a known-good vcpkg snapshot.
if [ -n "${_ARG_PROTOBUF_VERSION:-}" ]; then
PROTOBUF_VERSION="${_ARG_PROTOBUF_VERSION}"
fi

# 1. Bring up vcpkg pinned to the baseline commit.
git clone https://github.com/microsoft/vcpkg.git "${VCPKG_ROOT}"
git -C "${VCPKG_ROOT}" checkout "${VCPKG_BASELINE_COMMIT}"
"${VCPKG_ROOT}/bootstrap-vcpkg.sh" -disableMetrics

# Make sure the binary-cache dir exists. The RUN's --mount=type=cache
# creates it, but vcpkg can be picky about owner/perms on first use.
mkdir -p "${VCPKG_DEFAULT_BINARY_CACHE}"

# 2. Render a minimal manifest with builtin-baseline + the protobuf override.
mkdir -p /opt/vcpkg-manifest
cat > /opt/vcpkg-manifest/vcpkg.json <<MANIFEST
{
"name": "loader-devcontainer",
"version": "0.1.0",
"dependencies": ["protobuf"],
"overrides": [{ "name": "protobuf", "version": "${PROTOBUF_VERSION}" }],
"builtin-baseline": "${VCPKG_BASELINE_COMMIT}"
}
MANIFEST

# 3. Manifest-mode install. Triplet comes from /opt/buildargs.env
# (x64-linux on amd64, arm64-linux on arm64).
cd /opt/vcpkg-manifest
"${VCPKG_ROOT}/vcpkg" install \
--triplet="${VCPKG_TRIPLET}" \
--x-install-root=/opt/vcpkg-manifest/vcpkg_installed

# 4. Post-install assertion: vcpkg writes a per-port file whose name encodes
# the resolved version. If the prefix doesn't match what we asked for,
# fail loudly — silently producing a wrong-version image is the bug we
# are explicitly defending against.
INFO_FILE=$(ls /opt/vcpkg-manifest/vcpkg_installed/vcpkg/info/protobuf_*_${VCPKG_TRIPLET}.list 2>/dev/null | head -n1)
case "$(basename "${INFO_FILE:-/missing}" 2>/dev/null)" in
protobuf_${PROTOBUF_VERSION}*)
;;
*)
echo "ERROR: installed protobuf does not match requested version ${PROTOBUF_VERSION}."
echo " vcpkg installed-file marker: ${INFO_FILE:-<none>}"
echo " Bump VCPKG_BASELINE_COMMIT in .devcontainer/versions.env"
echo " (and make.py + testing-cpp.yml will pick it up automatically)"
echo " to a commit that knows about the requested version."
exit 1
;;
esac

# 5. Stable symlinks so ENV CMAKE_PREFIX_PATH (last layer) doesn't have to
# care about the underlying triplet.
ln -s /opt/vcpkg-manifest/vcpkg_installed/${VCPKG_TRIPLET} /opt/vcpkg/active
ln -s /opt/vcpkg/active/tools/protobuf/protoc /usr/local/bin/protoc
EOF

# ---------------------------------------------------------------------------
# .NET SDK — apt-based install from the official Microsoft repository.
# Version is read from /opt/versions.env.
# apt-get clean + rm /var/lib/apt/lists at the end keeps the layer small.
# ---------------------------------------------------------------------------
RUN <<EOF
set -eux
. /opt/versions.env
curl -fsSL https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb \
-o /tmp/ms.deb
dpkg -i /tmp/ms.deb
rm /tmp/ms.deb
apt-get update
apt-get install -y --no-install-recommends \
"dotnet-sdk-${DOTNET_VERSION}"
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF

# ---------------------------------------------------------------------------
# Final environment: with CMAKE_PREFIX_PATH pointing at vcpkg's installed
# tree, find_package(Protobuf CONFIG) resolves automatically — the existing
# README's "Dev at Linux → CMake (system protobuf)" recipe works as written
# inside the container.
# ---------------------------------------------------------------------------
ENV CMAKE_PREFIX_PATH=/opt/vcpkg/active

# Copy the post-create banner script into a stable on-image path so
# devcontainer.json can call it without needing the workspace mount.
COPY postcreate-banner.sh /usr/local/bin/loader-devcontainer-banner
RUN chmod +x /usr/local/bin/loader-devcontainer-banner
72 changes: 72 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Dev Container

The recommended way to develop on `tableauio/loader`. One container, all four target languages (C++17, Go, .NET, Node) plus protobuf via vcpkg, pinned to the same toolchain CI uses. Version pins live in [`./versions.env`](./versions.env), consumed by the Dockerfile, [`make.py`](../make.py), and the CI workflows.

For native dev (no Docker, no WSL2), use [`make.py`](../make.py) directly.

## Prerequisites

- Docker Desktop (Windows / macOS) or Docker Engine (Linux)
- VS Code with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)

## Open the container

```sh
code .
```

Then **Dev Containers: Reopen in Container** from the command palette. First build is one-time ~25 min (vcpkg compiles protobuf); reopens are near-instant.

Inside the container, `python make.py setup` is a no-op. Use `python make.py test --lang <X>` for any language.

## Pin a different protobuf version

```sh
LOADER_PROTOBUF_VERSION=3.21.12 code .
```

Then **Rebuild Container**. Only the vcpkg layer rebuilds.

## Host-OS caveats

- **Windows.** WSL2 backend required. Check the workspace out under WSL2 (`\\wsl.localhost\Ubuntu\home\<user>\loader`) — not `/mnt/c/...` — for good bind-mount performance.
- **Apple Silicon.** Docker builds the image natively as arm64. Confirm with `docker info | grep Architecture`.
- **Linux (native Docker Engine).** No special configuration.

## Architecture

Single-stage Dockerfile on `mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04`:

1. Architecture detection (`TARGETARCH` → Go arch, buf arch, vcpkg triplet)
2. Go — version from `versions.env`
3. buf — version from `versions.env`
4. vcpkg pinned to `VCPKG_BASELINE_COMMIT`, protobuf installed via manifest mode (asserts version)
5. .NET SDK — version from `versions.env`
6. Node.js LTS — version from `versions.env`
7. `ENV CMAKE_PREFIX_PATH=/opt/vcpkg/active` so `find_package(Protobuf CONFIG)` resolves automatically

Build context is `.devcontainer/`, so `COPY versions.env …` resolves directly.

## `versions.env` format

- One `KEY=VALUE` per line.
- No quotes, no spaces around `=`, no inline comments.
- Comments at column 0 with `#`. Blank lines ignored. No shell expansion.

Consumers: Dockerfile (sourced as a shell file), [`make.py`](../make.py) (`Versions.load()`), and `.github/actions/load-versions` (exports to `$GITHUB_ENV`).

Use `python make.py env` for a JSON dump of resolved values.

## Troubleshooting

### Stale-codegen errors after `buf generate`

Symptoms:
- C++: `fatal error: google/protobuf/generated_message_table_driven.h: No such file or directory`
- C#: hundreds of `error CS0101: The namespace already contains a definition for ...`

The host workspace has gitignored `*.pb.*` from a previous protobuf version that `git pull` didn't remove. Wipe with `python make.py clean --lang cpp` (or `--lang csharp`), then rerun the test.

## Falling back

No Docker? Use [`make.py`](../make.py) directly: `python make.py setup --lang all` then `python make.py test --lang <X>`. Works on macOS / Linux / Windows native.
67 changes: 67 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
// The loader's only devcontainer. Multi-arch: builds linux/amd64 on
// x64 hosts, linux/arm64 on Apple Silicon and Windows-on-ARM. Use
// this on every host that can run Docker Desktop or Docker Engine.
// Native users (no Docker) bootstrap via `python make.py setup` at
// the repo root.
//
// See ./versions.env for all toolchain pins.
"name": "tableauio/loader",
// Build args wire host env to Dockerfile ARGs:
// LOADER_DEFAULT_VARIANT on the host -> DEFAULT_VARIANT inside.
// Switches both protobuf AND vcpkg baseline atomically; values come
// from versions.env's MODERN_*/LEGACY_V3_* rows.
// LOADER_PROTOBUF_VERSION on the host -> PROTOBUF_VERSION inside.
// Surgical: overrides ONLY the protobuf version, vcpkg baseline
// stays at the variant's pin. For a clean variant switch, prefer
// LOADER_DEFAULT_VARIANT.
// Both default empty (versions.env's DEFAULT_VARIANT row wins). Example:
// LOADER_DEFAULT_VARIANT=legacy-v3 code . # then Reopen in Container.
//
// "context" defaults to the directory holding this devcontainer.json
// (.devcontainer/), so the Dockerfile's `COPY versions.env ...`
// resolves directly.
"build": {
"dockerfile": "Dockerfile",
"args": {
"DEFAULT_VARIANT": "${localEnv:LOADER_DEFAULT_VARIANT:}",
"PROTOBUF_VERSION": "${localEnv:LOADER_PROTOBUF_VERSION:}"
}
},
// Persist the Go module cache across container rebuilds. Workspace itself
// uses VS Code's default bind-mount so edits sync to the host.
"mounts": [
"source=loader-go-mod,target=/home/vscode/go,type=volume"
],
"remoteUser": "vscode",
"workspaceFolder": "/workspaces/loader",
"customizations": {
"vscode": {
"extensions": [
"golang.go",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools",
"ms-dotnettools.csharp",
"bufbuild.vscode-buf",
"DrBlury.protobuf-vsc"
],
"settings": {
// Don't auto-install gopls and friends on first open — let the user
// do it explicitly from the Go extension's command palette.
"go.toolsManagement.autoUpdate": false,
// Don't auto-cmake-configure on workspace open; we run cmake manually
// per the existing README recipes.
"cmake.configureOnOpen": false
}
}
},
// Ready banner so the developer knows the container is healthy.
// Script is baked into the image at build time (see Dockerfile).
"postCreateCommand": "/usr/local/bin/loader-devcontainer-banner",
// The loader-go-mod named volume is mounted at /home/vscode/go (see "mounts"
// above). Docker creates named volumes root-owned by default, masking any
// ownership set in the Dockerfile. Re-chown on every start so `go install`
// (e.g. gopls auto-install from the Go extension) can write into GOPATH.
// Idempotent and ~50ms on an already-correct tree.
"postStartCommand": "sudo chown -R vscode:vscode /home/vscode/go"
}
11 changes: 11 additions & 0 deletions .devcontainer/postcreate-banner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh
# Post-create banner for the Linux devcontainer.
# Pure echo — no installs, no version-pinning at runtime, no surprises.
# Four-line summary that prints when the container becomes ready, so the
# developer can confirm at a glance which toolchain versions landed.
set -e
printf 'tableauio/loader devcontainer ready (linux).\n'
printf ' go: %s\n' "$(go version | cut -d' ' -f3)"
printf ' buf: %s\n' "$(buf --version 2>&1)"
printf ' protoc: %s\n' "$(protoc --version)"
printf ' dotnet: %s\n' "$(dotnet --version)"
Loading
Loading