From a4745ad3bd156c1a8a5d4217e80c69b7a91529c8 Mon Sep 17 00:00:00 2001 From: Xuehao Xu Date: Thu, 16 Jul 2026 14:19:18 +0800 Subject: [PATCH] feat: add Alpine 3.22 runtime --- .../operating-systems/alpine/3.22/Dockerfile | 50 +++++++ .../operating-systems/alpine/3.22/build.sh | 49 +++++++ .../operating-systems/alpine/3.22/Dockerfile | 25 ++++ .../operating-systems/alpine/3.22/build.sh | 34 +++++ .../3.22/project-template/README.en_US.md | 61 ++++++++ .../3.22/project-template/README.zh_CN.md | 61 ++++++++ .../3.22/project-template/entrypoint.sh | 32 ++++ tests/runtime-conformance/README.md | 1 + tests/runtime-conformance/run.sh | 29 ++++ .../operating-systems/alpine/3.22/smoke.sh | 137 ++++++++++++++++++ tooling/scripts/install-base-pkg-apk.sh | 47 ++++++ .../zh_CN/configure-alpine-repositories.sh | 43 ++++++ tooling/scripts/l10n/zh_CN/configure.sh | 5 +- 13 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 base-images/operating-systems/alpine/3.22/Dockerfile create mode 100755 base-images/operating-systems/alpine/3.22/build.sh create mode 100644 runtime-images/operating-systems/alpine/3.22/Dockerfile create mode 100755 runtime-images/operating-systems/alpine/3.22/build.sh create mode 100644 runtime-images/operating-systems/alpine/3.22/project-template/README.en_US.md create mode 100644 runtime-images/operating-systems/alpine/3.22/project-template/README.zh_CN.md create mode 100755 runtime-images/operating-systems/alpine/3.22/project-template/entrypoint.sh create mode 100755 tests/runtime-smoke/operating-systems/alpine/3.22/smoke.sh create mode 100755 tooling/scripts/install-base-pkg-apk.sh create mode 100755 tooling/scripts/l10n/zh_CN/configure-alpine-repositories.sh diff --git a/base-images/operating-systems/alpine/3.22/Dockerfile b/base-images/operating-systems/alpine/3.22/Dockerfile new file mode 100644 index 00000000..e9b14f7e --- /dev/null +++ b/base-images/operating-systems/alpine/3.22/Dockerfile @@ -0,0 +1,50 @@ +# These ARGs can be overridden at build time to customize the image +ARG REGISTRY=ghcr.io +ARG TOOLING_REPO=labring-actions/devbox-tooling +ARG L10N=en_US +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER=devbox +ARG ALPINE_IMAGE=alpine:3.22 +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG BASE_TOOLS_VERSION=v0.0.1-alpha.1 + +FROM ${REGISTRY}/${TOOLING_REPO}/tooling:${BASE_TOOLS_VERSION} AS tooling +FROM ${ALPINE_IMAGE} +ARG L10N +ARG TARGETARCH +ARG ARCH=${TARGETARCH:-amd64} +ARG DEFAULT_DEVBOX_USER +LABEL org.opencontainers.image.authors="The Devbox Authors" +# Define some environment variables +## BASE_TOOLS_DIR: Directory where base tools are installed +ENV BASE_TOOLS_DIR=/opt/base-tools +## L10N: Internationalization setting +ENV L10N=${L10N} +## ARCH: System architecture (from build-arg) +ENV ARCH=${ARCH} +## DEFAULT_DEVBOX_USER: Default user for the devbox environment +ENV DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER} +## PROJECT_DIR: Default devbox project directory inside the container +ENV PROJECT_DIR=/home/devbox/project +## S6_STAGE2_HOOK: Hook script executed BEFORE s6-rc compilation +## This allows us to dynamically disable services based on DEVBOX_ENV +ENV S6_STAGE2_HOOK=/etc/s6-overlay-hook/pre-rc-init.d/pre-rc-init.sh +## S6_KILL_GRACETIME: Time to wait before forcefully killing all processes during shutdown +ENV S6_KILL_GRACETIME=500 + +# Copy tooling assets from the tooling stage +COPY --from=tooling ${BASE_TOOLS_DIR} ${BASE_TOOLS_DIR} +# Bash is required to execute the shared tooling scripts. +COPY build.sh /build.sh +RUN apk add --no-cache bash && \ + chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${BASE_TOOLS_DIR} +## Alpine uses musl; export UTF-8 defaults for non-login processes. +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 +ENTRYPOINT [ "/init" ] diff --git a/base-images/operating-systems/alpine/3.22/build.sh b/base-images/operating-systems/alpine/3.22/build.sh new file mode 100755 index 00000000..374f195a --- /dev/null +++ b/base-images/operating-systems/alpine/3.22/build.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Current BASE_TOOLS_DIR: $BASE_TOOLS_DIR" +echo "Current L10N: $L10N" +echo "Current ARCH: $ARCH" +echo "Current DEFAULT_DEVBOX_USER: $DEFAULT_DEVBOX_USER" + +chmod +x "$BASE_TOOLS_DIR/scripts/"*.sh + +# Install base packages for the Alpine/APK family. +"$BASE_TOOLS_DIR/scripts/install-base-pkg-apk.sh" + +# Install cron, s6, and the SDK server from the shared tooling scripts. +"$BASE_TOOLS_DIR/scripts/install-crond.sh" +"$BASE_TOOLS_DIR/scripts/install-s6.sh" +"$BASE_TOOLS_DIR/scripts/install-sdk-server.sh" + +# Configure svc. +"$BASE_TOOLS_DIR/scripts/configure-svc.sh" + +# Product-provided startup scripts can remain active for the DevBox lifetime +# (for example, while serving VS Code Web). Core services must not wait for +# that startup oneshot to exit before they are allowed to run. +rm -f \ + /etc/s6-overlay/s6-rc.d/sshd/dependencies.d/startup \ + /etc/s6-overlay/s6-rc.d/crond/dependencies.d/startup + +# Configure other utilities. +"$BASE_TOOLS_DIR/scripts/configure-logrotate.sh" +"$BASE_TOOLS_DIR/scripts/configure-login.sh" + +# Configure localization (L10N). +"$BASE_TOOLS_DIR/scripts/configure-l10n.sh" + +# Configure user devbox. +"$BASE_TOOLS_DIR/scripts/configure-user.sh" "$DEFAULT_DEVBOX_USER" + +# Install user-facing runtime docs (single source from the shared tooling bundle). +if [ -d "$BASE_TOOLS_DIR/docs" ]; then + install -d /usr/share/devbox/docs + cp "$BASE_TOOLS_DIR"/docs/README.s6-user-guide*.md /usr/share/devbox/docs/ + chmod 644 /usr/share/devbox/docs/README.s6-user-guide*.md +else + echo "No docs directory found in $BASE_TOOLS_DIR; skipping s6 user-guide install" +fi + +# Cleanup. +"$BASE_TOOLS_DIR/scripts/cleanup.sh" diff --git a/runtime-images/operating-systems/alpine/3.22/Dockerfile b/runtime-images/operating-systems/alpine/3.22/Dockerfile new file mode 100644 index 00000000..dbbe3787 --- /dev/null +++ b/runtime-images/operating-systems/alpine/3.22/Dockerfile @@ -0,0 +1,25 @@ +# These ARGs can be overridden at build time to customize the image +ARG REPO=labring-actions/devbox-base-images +ARG REGISTRY=ghcr.io +ARG L10N=en_US +ARG L10N_NORMALIZED=en-us +ARG DEFAULT_DEVBOX_USER=devbox + +# These ARGs are not recommended to be overridden at build time. +# Instead, update the Dockerfile directly for consistent builds, +# and release new versions as needed. +ARG OS_IMAGE_VERSION=v0.0.1-alpha.1-${L10N_NORMALIZED} + +FROM ${REGISTRY}/${REPO}/alpine-3.22:${OS_IMAGE_VERSION} +ARG L10N +ARG DEFAULT_DEVBOX_USER +ENV L10N=${L10N} +ENV PROJECT_TEMPLATE_DIR=/project-template +COPY ./project-template ${PROJECT_TEMPLATE_DIR} +COPY ./build.sh /build.sh +RUN chmod +x /build.sh && \ + /build.sh && \ + rm -f /build.sh && \ + rm -rf ${PROJECT_TEMPLATE_DIR} +# Set the working directory to the default devbox user's project directory +WORKDIR /home/${DEFAULT_DEVBOX_USER}/project diff --git a/runtime-images/operating-systems/alpine/3.22/build.sh b/runtime-images/operating-systems/alpine/3.22/build.sh new file mode 100755 index 00000000..0653a52f --- /dev/null +++ b/runtime-images/operating-systems/alpine/3.22/build.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +L10N=${L10N:-en_US} +DEFAULT_DEVBOX_USER=${DEFAULT_DEVBOX_USER:-devbox} +PROJECT_TEMPLATE_DIR=${PROJECT_TEMPLATE_DIR:-/project-templates} +DOCS_DIR=${DOCS_DIR:-/usr/share/devbox/docs} + +if ! id -u "$DEFAULT_DEVBOX_USER" &>/dev/null; then + echo "User $DEFAULT_DEVBOX_USER does not exist" + exit 1 +fi + +TARGET_DIR="/home/$DEFAULT_DEVBOX_USER/project" +mkdir -p "$TARGET_DIR" + +if [ -f "$PROJECT_TEMPLATE_DIR/README.$L10N.md" ]; then + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md exists. Copying to $TARGET_DIR/README.md" + cp "$PROJECT_TEMPLATE_DIR/README.$L10N.md" "$TARGET_DIR/README.md" +else + echo "README $PROJECT_TEMPLATE_DIR/README.$L10N.md does not exist. Skipping copy." +fi + +if [ -f "$DOCS_DIR/README.s6-user-guide.$L10N.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.$L10N.md" "$TARGET_DIR/README.s6-user-guide.md" +elif [ -f "$DOCS_DIR/README.s6-user-guide.en_US.md" ]; then + cp "$DOCS_DIR/README.s6-user-guide.en_US.md" "$TARGET_DIR/README.s6-user-guide.md" +fi + +cp "$PROJECT_TEMPLATE_DIR/"*.sh "$TARGET_DIR/" +chmod 0755 "$TARGET_DIR/"*.sh + +# Set ownership to default devbox user. +chown -R "$DEFAULT_DEVBOX_USER:$DEFAULT_DEVBOX_USER" "$TARGET_DIR" diff --git a/runtime-images/operating-systems/alpine/3.22/project-template/README.en_US.md b/runtime-images/operating-systems/alpine/3.22/project-template/README.en_US.md new file mode 100644 index 00000000..8955c2c1 --- /dev/null +++ b/runtime-images/operating-systems/alpine/3.22/project-template/README.en_US.md @@ -0,0 +1,61 @@ +# Alpine 3.22 Runtime Template + +This template provides a minimal **operating-system runtime** based on Alpine Linux 3.22. +Use it when you want a compact Linux environment and full control of your language, framework, or application stack. + +## Runtime Summary + +- OS version: `Alpine Linux 3.22` +- Base runtime image: `alpine-3.22` +- Package manager: `apk` +- C library: `musl` +- Entrypoint script: `entrypoint.sh` +- Default service port: `8080` + +## Template Files + +- `entrypoint.sh`: creates a static `index.html` and starts a lightweight HTTP server + +## Run in DevBox + +Run commands from `/home/devbox/project`. + +```bash +bash entrypoint.sh +``` + +Behavior: + +- Uses the `PORT` environment variable when provided, and defaults to `8080`. +- Serves files from `/home/devbox/project/www`. +- Prefers BusyBox `httpd` and falls back to `python3 -m http.server` when that applet is unavailable. + +## Verify Service + +```bash +curl http://127.0.0.1:8080 +``` + +Expected output: + +```text +Hello, World! +``` + +## Package Management + +Install application dependencies with `apk`: + +```bash +sudo apk add --no-cache file +``` + +## Compatibility + +Alpine uses musl instead of the glibc used by Debian, Ubuntu, and Fedora. The image includes `gcompat`, `libgcc`, and `libstdc++` for practical compatibility, but these packages do not make every glibc-only binary or native extension compatible. Validate third-party development tools against Alpine before relying on them. + +## Customization + +- Replace `entrypoint.sh` with your own process startup script. +- Use `apk` to install application dependencies. +- Align container exposed ports with your service port. diff --git a/runtime-images/operating-systems/alpine/3.22/project-template/README.zh_CN.md b/runtime-images/operating-systems/alpine/3.22/project-template/README.zh_CN.md new file mode 100644 index 00000000..c06968a4 --- /dev/null +++ b/runtime-images/operating-systems/alpine/3.22/project-template/README.zh_CN.md @@ -0,0 +1,61 @@ +# Alpine 3.22 运行时模板 + +该模板提供一个基于 Alpine Linux 3.22 的最小化**操作系统运行时**。 +适用于需要轻量 Linux 环境,并在其上自行安装语言、框架或业务依赖的场景。 + +## 运行时概览 + +- 系统版本:`Alpine Linux 3.22` +- 基础运行时镜像:`alpine-3.22` +- 包管理器:`apk` +- C 标准库:`musl` +- 启动脚本:`entrypoint.sh` +- 默认服务端口:`8080` + +## 模板文件 + +- `entrypoint.sh`:生成静态 `index.html` 并启动轻量 HTTP 服务 + +## 在 DevBox 中运行 + +以下命令在 `/home/devbox/project` 目录执行。 + +```bash +bash entrypoint.sh +``` + +行为说明: + +- 支持通过 `PORT` 环境变量覆盖端口,默认值为 `8080`。 +- 默认从 `/home/devbox/project/www` 目录提供静态内容。 +- 优先使用 BusyBox `httpd`,不可用时回退到 `python3 -m http.server`。 + +## 验证服务 + +```bash +curl http://127.0.0.1:8080 +``` + +预期输出: + +```text +Hello, World! +``` + +## 包管理 + +使用 `apk` 安装业务依赖: + +```bash +sudo apk add --no-cache file +``` + +## 兼容性说明 + +Alpine 使用 musl,而 Debian、Ubuntu 和 Fedora 通常使用 glibc。镜像包含 `gcompat`、`libgcc` 和 `libstdc++` 以提供常见兼容能力,但这些软件包不能保证所有仅支持 glibc 的二进制文件或原生扩展都能运行。依赖第三方开发工具时,应先单独验证其 Alpine 兼容性。 + +## 自定义建议 + +- 可将 `entrypoint.sh` 替换为你的进程启动脚本。 +- 使用 `apk` 安装业务依赖。 +- 保持容器暴露端口与服务监听端口一致。 diff --git a/runtime-images/operating-systems/alpine/3.22/project-template/entrypoint.sh b/runtime-images/operating-systems/alpine/3.22/project-template/entrypoint.sh new file mode 100755 index 00000000..4b675bb9 --- /dev/null +++ b/runtime-images/operating-systems/alpine/3.22/project-template/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -euo pipefail + +if [ "$(id -u)" -eq 0 ] && [ "${DEVBOX_ENTRYPOINT_AS_DEVBOX:-1}" = "1" ] && id devbox >/dev/null 2>&1; then + export DEVBOX_ENTRYPOINT_AS_DEVBOX=0 + SCRIPT_PATH=$(readlink -f "$0") + exec runuser -u devbox -- bash "$SCRIPT_PATH" "$@" +fi + +# Serve a simple "Hello, World!" page. +PORT=${PORT:-8080} +PROJECT_DIR=${PROJECT_DIR:-/home/devbox/project} +ROOT_DIR="$PROJECT_DIR/www" +mkdir -p "$ROOT_DIR" + +cat >"$ROOT_DIR/index.html" <<'HTML' +Hello, World! +HTML + +echo "Starting HTTP server on port $PORT (serving $ROOT_DIR)" + +if command -v busybox >/dev/null 2>&1 && busybox --list 2>/dev/null | grep -qx httpd; then + exec busybox httpd -f -p "$PORT" -h "$ROOT_DIR" +fi + +if command -v python3 >/dev/null 2>&1; then + cd "$ROOT_DIR" + exec python3 -m http.server "$PORT" --bind 0.0.0.0 +fi + +echo "No supported HTTP server found (busybox httpd or python3 http.server)." >&2 +exit 1 diff --git a/tests/runtime-conformance/README.md b/tests/runtime-conformance/README.md index 034e3805..ac14bbd9 100644 --- a/tests/runtime-conformance/README.md +++ b/tests/runtime-conformance/README.md @@ -32,6 +32,7 @@ Runtime-specific checks: | Runtime | Checks | | --- | --- | | `operating-systems/anolis/23.4` | Anolis identity, busybox, localized README, root/devbox entrypoint order | +| `operating-systems/alpine/3.22` | Alpine 3.22 identity, `apk`, busybox, Bash, sudo, network/archive tools, OpenSSH without embedded host keys, musl compatibility packages (`gcompat`, `libstdc++`, `libgcc`), localized README, root/devbox entrypoint order | | `operating-systems/debian/12.6` | Debian identity, busybox, localized README, root/devbox entrypoint order | | `operating-systems/kylin/v10-sp3` | Kylin identity, busybox, localized README, root/devbox entrypoint order | | `operating-systems/ubuntu/22.04` | Ubuntu identity, busybox, localized README, root/devbox entrypoint order | diff --git a/tests/runtime-conformance/run.sh b/tests/runtime-conformance/run.sh index db3fc132..06adaac9 100755 --- a/tests/runtime-conformance/run.sh +++ b/tests/runtime-conformance/run.sh @@ -404,6 +404,32 @@ check_os_runtime() { assert_command busybox } +check_alpine_runtime() { + check_os_runtime alpine + grep -Eq 'VERSION_ID="?3[.]22"?' /etc/os-release || fail "expected Alpine 3.22 in /etc/os-release" + assert_command apk + assert_command bash + assert_command sudo + assert_command curl + assert_command wget + assert_command git + assert_command python3 + assert_command tar + assert_command gzip + assert_command unzip + assert_command zip + assert_command ssh + assert_executable /usr/sbin/sshd + for package_name in gcompat libstdc++ libgcc openssh openssh-client openssh-server bash sudo; do + apk info -e "$package_name" >/dev/null 2>&1 || fail "missing Alpine package: $package_name" + done + for service_name in sshd crond; do + if [ -e "/etc/s6-overlay/s6-rc.d/$service_name/dependencies.d/startup" ]; then + fail "$service_name must not wait for the long-running DevBox startup service" + fi + done +} + check_cuda_runtime() { log "check CUDA runtime" if command -v nvcc >/dev/null 2>&1; then @@ -599,6 +625,9 @@ check_runtime_specifics() { operating-systems/anolis/23.4) check_os_runtime anolis ;; + operating-systems/alpine/3.22) + check_alpine_runtime + ;; operating-systems/debian/12.6) check_os_runtime debian ;; diff --git a/tests/runtime-smoke/operating-systems/alpine/3.22/smoke.sh b/tests/runtime-smoke/operating-systems/alpine/3.22/smoke.sh new file mode 100755 index 00000000..ce0b5717 --- /dev/null +++ b/tests/runtime-smoke/operating-systems/alpine/3.22/smoke.sh @@ -0,0 +1,137 @@ +#!/bin/bash +set -eu + +project_dir=/home/devbox/project + +if [ ! -d "$project_dir" ]; then + echo "Missing project dir: $project_dir" >&2 + exit 1 +fi + +# Load profile env (best effort). +set +u +[ -f /etc/profile ] && . /etc/profile || true +if [ -d /etc/profile.d ]; then + for f in /etc/profile.d/*.sh; do + [ -r "$f" ] && . "$f" || true + done +fi +[ -f /home/devbox/.bashrc ] && . /home/devbox/.bashrc || true +set -u + +if [ "${SMOKE_DEBUG:-}" = "1" ]; then + echo "SMOKE_DEBUG=1" + echo "user=$(id -un) uid=$(id -u) gid=$(id -g)" + echo "HOME=$HOME" + echo "SHELL=${SHELL:-}" + echo "PATH=$PATH" + for cmd in apk busybox bash sudo curl wget git python3 tar gzip unzip zip ssh sshd; do + if command -v "$cmd" >/dev/null 2>&1; then + echo "cmd:$cmd=$(command -v "$cmd")" + else + echo "cmd:$cmd=missing" + fi + done +fi + +if ! grep -qi alpine /etc/os-release; then + echo "Expected Alpine in /etc/os-release" >&2 + exit 1 +fi + +if ! grep -Eq 'VERSION_ID="?3[.]22"?' /etc/os-release; then + echo "Expected Alpine 3.22 in /etc/os-release" >&2 + exit 1 +fi + +if ! id devbox >/dev/null 2>&1; then + echo "User devbox not found" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/README.md" ]; then + echo "Missing README.md in $project_dir" >&2 + exit 1 +fi + +if [ ! -f "$project_dir/entrypoint.sh" ]; then + echo "Missing entrypoint.sh in $project_dir" >&2 + exit 1 +fi + +for cmd in apk busybox bash sudo curl wget git python3 tar gzip unzip zip ssh; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "$cmd not found" >&2 + exit 1 + fi +done + +if [ ! -x /usr/sbin/sshd ]; then + echo "sshd not found" >&2 + exit 1 +fi + +for pkg in gcompat libstdc++ libgcc openssh openssh-client openssh-server bash sudo; do + if ! apk info -e "$pkg" >/dev/null 2>&1; then + echo "$pkg package not installed" >&2 + exit 1 + fi +done + +if [ "${L10N:-en_US}" = "zh_CN" ]; then + if ! grep -q 'mirrors.tuna.tsinghua.edu.cn/alpine/v3.22/main' /etc/apk/repositories; then + echo "zh_CN Alpine package mirror is not configured" >&2 + exit 1 + fi +fi + +for nologin_file in /run/nologin /etc/nologin; do + if [ -e "$nologin_file" ]; then + echo "$nologin_file blocks non-root SSH logins" >&2 + exit 1 + fi +done + +# Host keys must be generated by the s6 sshd service when the container starts, +# never baked into the reusable image. +if find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key' -print -quit | grep -q .; then + echo "SSH host private keys must not be embedded in the image" >&2 + exit 1 +fi + +sshd_config_dump() { + local tmp_dir + tmp_dir="$(mktemp -d)" + trap 'rm -rf "$tmp_dir"' RETURN + ssh-keygen -q -t ed25519 -N "" -f "$tmp_dir/ssh_host_ed25519_key" + + if [ "$(id -u)" -eq 0 ]; then + /usr/sbin/sshd -T -h "$tmp_dir/ssh_host_ed25519_key" + elif command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then + sudo /usr/sbin/sshd -T -h "$tmp_dir/ssh_host_ed25519_key" + else + echo "root privileges are required to inspect sshd configuration" >&2 + return 1 + fi +} + +if ! sshd_config_dump | grep -qx 'allowtcpforwarding yes'; then + echo "sshd AllowTcpForwarding is not enabled" >&2 + exit 1 +fi + +# Entrypoint smoke. +entrypoint="$project_dir/entrypoint.sh" +( cd "$project_dir" && bash "$entrypoint" ) >/tmp/entrypoint.log 2>&1 & +pid=$! +sleep 3 +if ! kill -0 "$pid" >/dev/null 2>&1; then + echo "entrypoint exited early" >&2 + echo "---- entrypoint log ----" >&2 + cat /tmp/entrypoint.log >&2 || true + exit 1 +fi +kill "$pid" >/dev/null 2>&1 || true +wait "$pid" >/dev/null 2>&1 || true + +echo "ok" diff --git a/tooling/scripts/install-base-pkg-apk.sh b/tooling/scripts/install-base-pkg-apk.sh new file mode 100755 index 00000000..0c1173d7 --- /dev/null +++ b/tooling/scripts/install-base-pkg-apk.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +if ! command -v apk >/dev/null 2>&1; then + echo "apk is not available" >&2 + exit 1 +fi + +apk add --no-cache \ + bash \ + binutils \ + busybox \ + ca-certificates \ + coreutils \ + cpio \ + curl \ + diffutils \ + findutils \ + gawk \ + gcompat \ + git \ + grep \ + gzip \ + iproute2 \ + libgcc \ + libstdc++ \ + logrotate \ + openssh \ + openssh-client \ + openssh-server \ + openssl \ + procps \ + python3 \ + sed \ + shadow \ + sudo \ + tar \ + tzdata \ + unzip \ + util-linux \ + vim \ + wget \ + which \ + xz \ + zip + +update-ca-certificates diff --git a/tooling/scripts/l10n/zh_CN/configure-alpine-repositories.sh b/tooling/scripts/l10n/zh_CN/configure-alpine-repositories.sh new file mode 100755 index 00000000..90052f4e --- /dev/null +++ b/tooling/scripts/l10n/zh_CN/configure-alpine-repositories.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +TARGET=/etc/apk/repositories +MIRROR="https://mirrors.tuna.tsinghua.edu.cn/alpine" + +if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run as root" >&2 + exit 1 +fi + +if [ -f /etc/os-release ]; then + # shellcheck source=/dev/null + . /etc/os-release +else + echo "Cannot read /etc/os-release" >&2 + exit 1 +fi + +VERSION="${VERSION_ID:-}" +if [ -z "$VERSION" ]; then + echo "VERSION_ID not set in /etc/os-release" >&2 + exit 1 +fi + +MAJOR_MINOR="$(printf '%s\n' "$VERSION" | awk -F. '{ printf "%s.%s", $1, $2 }')" +BRANCH="v${MAJOR_MINOR}" + +if [ -f "$TARGET" ]; then + ts=$(date -u +%Y%m%dT%H%M%SZ) + backup="$TARGET.bak-$ts" + echo "Backing up existing $TARGET -> $backup" + cp -a "$TARGET" "$backup" +fi + +cat > "$TARGET" < $TARGET" +cat "$TARGET" || true diff --git a/tooling/scripts/l10n/zh_CN/configure.sh b/tooling/scripts/l10n/zh_CN/configure.sh index 4d5a4e32..46ce8c52 100644 --- a/tooling/scripts/l10n/zh_CN/configure.sh +++ b/tooling/scripts/l10n/zh_CN/configure.sh @@ -3,11 +3,14 @@ set -euo pipefail SOURCE_DIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") chmod +x "$SOURCE_DIR/"*.sh -# Configure APT source list by distro: Debian -> USTC mirror; Ubuntu -> Tsinghua Ubuntu mirror +# Configure package sources by distro. if [ -f /etc/os-release ]; then # shellcheck source=/dev/null . /etc/os-release case "${ID:-}" in + alpine) + "$SOURCE_DIR/configure-alpine-repositories.sh" + ;; debian) "$SOURCE_DIR/configure-debian-source.sh" ;;