INTO-CPS-Association / INTO-CPS-Association/workspace

[FEATURE]Multi-platform builds with Python, Java, and TypeScript toolchains

Open
#89 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
0
Forks
5
PR merge metrics
No merged PRs in 30d

Description

### Describe the feature

As a **workspace user on either x86-64 or ARM64 hardware (including Apple Silicon and ARM cloud instances)**, I want to **run natively built workspace images that ship with Python, Java, and TypeScript development toolchains** so that **digital-twin development works out of the box on both architectures without emulation**.

### Describe the problems your feature request solves

1. Multi-platform builds are a stated requirement. The Dockerfile already declares `TARGETARCH`/`TARGETPLATFORM`/`BUILDPLATFORM` build args, but the install scripts must be verified arch-clean: any script that downloads a prebuilt binary with a hard-coded architecture string will silently produce a broken arm64 image (or break the build).
2. The workspace currently ships no managed language toolchains beyond what the base image provides. Users install compilers/runtimes by hand inside their session, which does not survive image rebuilds and diverges between users.
3. Toolchain installers are exactly the scripts most likely to break multi-arch, because vendors encode the architecture differently (`amd64`/`arm64` vs `x64`/`aarch64` vs `x86_64`), so this belongs in one shared helper rather than per-script ad-hoc logic.

### Describe the solution you'd like

**(a) One shared arch-mapping helper**, sourced by every install script:

```bash
# workspaces/src/install/common/arch.sh
#!/bin/bash
set -euo pipefail

# Docker buildx sets TARGETARCH (amd64|arm64); fall back to dpkg for
# non-buildx local builds.
ARCH="${TARGETARCH:-$(dpkg --print-architecture)}"

case "${ARCH}" in
amd64) NODE_ARCH="x64"; JAVA_ARCH="x64"; GO_STYLE_ARCH="amd64" ;;
arm64) NODE_ARCH="arm64"; JAVA_ARCH="aarch64"; GO_STYLE_ARCH="arm64" ;;
*) echo "ERROR: unsupported architecture: ${ARCH}" >&2; exit 1 ;;
esac
export ARCH NODE_ARCH JAVA_ARCH GO_STYLE_ARCH
```

**(b) Python toolchain** (apt-based → inherently multi-arch):

```bash
# workspaces/src/install/toolchains/install_python.sh
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/../common/arch.sh"

export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
python3 python3-venv python3-pip python3-dev build-essential
rm -rf /var/lib/apt/lists/*

# Fast, arch-aware installer/resolver for per-user environments.
# uv publishes native amd64 and arm64 builds; its installer auto-detects.
curl -LsSf https://astral.sh/uv/install.sh | \
UV_INSTALL_DIR=/usr/local/bin sh

python3 --version && pip3 --version && uv --version
```

**(c) Java toolchain** (Eclipse Temurin; per-arch tarball):

```bash
# workspaces/src/install/toolchains/install_java.sh
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/../common/arch.sh"

JDK_MAJOR=21
JDK_URL="https://api.adoptium.net/v3/binary/latest/${JDK_MAJOR}/ga/linux/${JAVA_ARCH}/jdk/hotspot/normal/eclipse"

mkdir -p /opt/java
curl -fsSL "${JDK_URL}" | tar -xz -C /opt/java --strip-components=1

# System-wide, layer-safe PATH (survives .docker_set_envs snapshot):
ln -s /opt/java/bin/java /usr/local/bin/java
ln -s /opt/java/bin/javac /usr/local/bin/javac
cat > /etc/profile.d/java.sh <<'EOF'
export JAVA_HOME=/opt/java
export PATH="${JAVA_HOME}/bin:${PATH}"
EOF

java -version
```

**(d) TypeScript toolchain** (Node.js per-arch tarball + global npm packages):

```bash
# workspaces/src/install/toolchains/install_typescript.sh
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/../common/arch.sh"

NODE_VERSION=22.12.0 # pin; update deliberately
NODE_DIST="node-v${NODE_VERSION}-linux-${NODE_ARCH}"
NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_DIST}.tar.xz"

curl -fsSL "${NODE_URL}" -o /tmp/node.tar.xz
# TODO: verify against SHASUMS256.txt for the pinned version
tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1
rm /tmp/node.tar.xz

npm install -g typescript ts-node @types/node

node --version && npm --version && tsc --version
```

**(e) Dockerfile wiring** — add a toolchain stage/lines to the `full`
target (or a new `INSTALLATION=devel` target to keep `full` lean):

```dockerfile
FROM configure AS install-full
# ...existing installs...
RUN bash ${INST_DIR}/toolchains/install_python.sh
RUN bash ${INST_DIR}/toolchains/install_java.sh
RUN bash ${INST_DIR}/toolchains/install_typescript.sh
```

All installs go to system locations (`/usr/local`, `/opt`) rather than
`$HOME`, so they survive the profile-clone mechanism and the
`.docker_set_envs` PATH snapshot (see the PATH lessons from issue #87).

**(f) CI: build and test both platforms** with buildx + QEMU:

```yaml
# .github/workflows/docker-build.yml (fragment)
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: ./workspaces
file: ./workspaces/Dockerfile.ubuntu.noble.xfce
platforms: linux/amd64,linux/arm64
build-args: INSTALLATION=full
push: ${{ github.event_name != 'pull_request' }}
```

plus a smoke-test job per platform that runs `python3 --version && java -version && tsc --version` inside the built image.

### Describe alternatives you've considered

- **nvm / SDKMAN / pyenv (per-user version managers)** — flexible, but they install into `$HOME` and rely on shell-rc PATH edits, which is exactly the
pattern that broke `workspace-admin` (build-time `.bashrc` edits do not survive into runtime layers). System-wide pinned installs are the
layer-safe choice; version managers can still be offered *inside* the running workspace for users who need multiple versions.
- **apt for everything** — simplest and automatically multi-arch, but Ubuntu noble's packaged Node.js and JDK lag; acceptable fallback if pinned
upstream tarballs are considered too much maintenance.
- **Per-arch Dockerfiles** — rejected; `TARGETARCH` + a single mapping helper keeps one Dockerfile and one code path.
- **Emulated (QEMU) images for arm64 users** — rejected as a product answer; desktop-in-browser under emulation is unusably slow. QEMU is used only in CI to *build* the arm64 image.

### Additional context

- The three vendor arch vocabularies covered by `arch.sh`: Docker `amd64/arm64`, Node `x64/arm64`, Adoptium `x64/aarch64`.
- All downloads must be version-pinned with checksum verification to keep builds reproducible (same policy as proposed for Filebrowser in the
file-transfer feature request).
- Image-size impact should be measured; if `full` grows too large, introduce `INSTALLATION=devel` as a separate target rather than bloating `full`.
- Interacts with the VS Code extension pre-installation work: language extensions (Python, Java, TypeScript) are only useful if the matching
toolchains exist in the image — these two features should be sequenced together.

### Success Criterion

Checklist:

- [ ] `docker buildx build --platform linux/amd64,linux/arm64` succeeds for both `full` and `minimal` targets
- [ ] `python3`, `pip`, `uv` functional on both architectures
- [ ] `java`, `javac` (Temurin, pinned major) functional on both architectures
- [ ] `node`, `npm`, `tsc`, `ts-node` functional on both architectures
- [ ] All toolchains on PATH for the runtime user (verified after profile-clone and `.docker_set_envs` restore, not just at build time)
- [ ] Shared `arch.sh` helper used by every arch-sensitive install script; no hard-coded architecture strings remain
- [ ] CI builds both platforms and runs per-platform smoke tests
- [ ] Downloads version-pinned with checksum verification
- [ ] Image size impact measured and documented
- [ ] Documentation Updated

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading the existing install scripts under workspaces/src/install and workspaces/Dockerfile.ubuntu.noble.xfce, then inspect .github/workflows/docker-build.yml and the profile-clone environment handling. The work is done when both targets build for amd64 and arm64, all three toolchains work at runtime, architecture-sensitive downloads are shared and pinned, smoke tests pass, and image-size impact is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, docker, github-actions, java, python, typescript
Domain
build-system, ci-cd, developer-experience, devops, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.