#!/bin/sh # build-code-server.sh # downloads the official code-server release and packages it as a portable AppImage. # the resulting AppImage bundles everything and requires no system installation. # usage: # sh build-code-server.sh # PKGVER=4.420.0 sh build-code-server.sh # override version # # running the output AppImage: # regular: ./code-server-VERSION-ARCH.AppImage [args] # docker: APPIMAGE_EXTRACT_AND_RUN=1 ./code-server-VERSION-ARCH.AppImage [args] set -e PKGVER="${PKGVER:-4.118.0}" PKGNAME="code-server" GITHUB_URL="https://github.com/coder/code-server" # - check required tools for _cmd in curl tar; do if ! command -v "$_cmd" > /dev/null 2>&1; then printf 'error: required tool not found: %s\n' "$_cmd" >&2 exit 1 fi done # - detect host architecture UNAME_ARCH="$(uname -m)" case "$UNAME_ARCH" in x86_64) RELEASE_ARCH="amd64" ;; aarch64) RELEASE_ARCH="arm64" ;; *) printf 'error: unsupported architecture: %s\n' "$UNAME_ARCH" >&2 exit 1 ;; esac RELEASE_NAME="${PKGNAME}-${PKGVER}-linux-${RELEASE_ARCH}" TARBALL="${RELEASE_NAME}.tar.gz" TARBALL_URL="${GITHUB_URL}/releases/download/v${PKGVER}/${TARBALL}" APPIMAGETOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${UNAME_ARCH}.AppImage" # - icon urls: try versioned tag, fall back to main branch ICON_URL="https://raw.githubusercontent.com/coder/code-server/v${PKGVER}/src/browser/media/pwa-icon-512.png" ICON_FALLBACK_URL="https://raw.githubusercontent.com/coder/code-server/main/src/browser/media/pwa-icon-512.png" OUTPUT_DIR="$(pwd)" WORKDIR="$(mktemp -d)" APPDIR="${WORKDIR}/AppDir" # - always clean up temp workdir on exit cleanup() { rm -rf "$WORKDIR" } trap cleanup EXIT INT TERM printf '==> setting up build directory...\n' mkdir -p \ "${APPDIR}/usr/lib" \ "${APPDIR}/usr/bin" \ "${APPDIR}/usr/share/icons/hicolor/512x512/apps" cd "$WORKDIR" # - download the official pre-built release tarball (same source as PKGBUILD) printf '==> downloading code-server v%s (%s)...\n' "$PKGVER" "$RELEASE_ARCH" curl -fL --progress-bar -o "$TARBALL" "$TARBALL_URL" printf '==> extracting tarball...\n' tar -xzf "$TARBALL" printf '==> populating AppDir...\n' cp -a "${RELEASE_NAME}" "${APPDIR}/usr/lib/${PKGNAME}" # - AppRun is the entrypoint; resolves paths relative to the AppImage mount cat > "${APPDIR}/AppRun" << 'APPRUN_EOF' #!/bin/sh # apprun - entrypoint for code-server AppImage SELF="$(readlink -f "$0")" HERE="$(dirname "$SELF")" export PATH="${HERE}/usr/bin:${PATH}" exec "${HERE}/usr/lib/code-server/bin/code-server" "$@" APPRUN_EOF chmod +x "${APPDIR}/AppRun" # - .desktop file is required by the AppImage spec cat > "${APPDIR}/${PKGNAME}.desktop" << DESKTOP_EOF [Desktop Entry] Name=code-server Comment=VS Code in the browser Exec=code-server Icon=code-server Type=Application Categories=Development;IDE; DESKTOP_EOF # - fetch icon; fall back to main branch if the versioned tag path differs printf '==> downloading icon...\n' if ! curl -fsSL -o "${APPDIR}/usr/share/icons/hicolor/512x512/apps/${PKGNAME}.png" "$ICON_URL"; then printf ' versioned icon not found, trying main branch...\n' curl -fL --progress-bar \ -o "${APPDIR}/usr/share/icons/hicolor/512x512/apps/${PKGNAME}.png" \ "$ICON_FALLBACK_URL" fi # - appimage spec also requires the icon at the AppDir root cp "${APPDIR}/usr/share/icons/hicolor/512x512/apps/${PKGNAME}.png" \ "${APPDIR}/${PKGNAME}.png" # - download appimagetool (itself an AppImage; APPIMAGE_EXTRACT_AND_RUN avoids FUSE dependency) printf '==> downloading appimagetool (%s)...\n' "$UNAME_ARCH" curl -fL --progress-bar -o "${WORKDIR}/appimagetool" "$APPIMAGETOOL_URL" chmod +x "${WORKDIR}/appimagetool" # - build the AppImage # - APPIMAGE_EXTRACT_AND_RUN=1 lets appimagetool run without FUSE (required in Docker) # - ARCH must be set so appimagetool embeds the correct ELF architecture tag OUTPUT="${OUTPUT_DIR}/${PKGNAME}-${PKGVER}-${UNAME_ARCH}.AppImage" printf '==> building AppImage...\n' ARCH="$UNAME_ARCH" APPIMAGE_EXTRACT_AND_RUN=1 \ "${WORKDIR}/appimagetool" --comp gzip \ "${APPDIR}" "${OUTPUT}" chmod +x "${OUTPUT}" printf '\n==> done!\n' printf ' output: %s\n\n' "$OUTPUT" printf 'usage:\n' printf ' regular system: ./%s-%s-%s.AppImage\n' "$PKGNAME" "$PKGVER" "$UNAME_ARCH" printf ' docker/no-fuse: APPIMAGE_EXTRACT_AND_RUN=1 ./%s-%s-%s.AppImage\n' "$PKGNAME" "$PKGVER" "$UNAME_ARCH" printf '\nmove %s to /opt/code-server-appimage/ within your environment and use the code-server wrapper script to run it\n\n' "$OUTPUT"