#!/bin/sh # CoCalc Plus installer: release 1792224176 (version 0.2.90) from https://software.cocalc.ai/software/plus. # # This installs CoCalc Plus for your user only, under # ${XDG_DATA_HOME:-~/.local/share}/cocalc/plus with a launcher in # ~/.local/bin/cocalc-plus. Your existing CoCalc Plus data is kept. # Installing it gives https://software.cocalc.ai/software/plus full code execution as your user, now and on # every update, and updates come only from there. set -eu origin='https://software.cocalc.ai/software/plus' release=1792224176 version='0.2.90' manifest=776790544ae506973d199463f87897bef99746bd01eb97fef2a469984ecb2ceb manifest_size=2823 bootstrap=505103cac2c6c2455b548268cf607a963d92a988537e7f5fb23ed10c52fe8fa3 bootstrap_size=5154 launcher_sha=884736ffaf87b1a29f76a64465443d6304bf79323594ea970575244a60bfe731 launcher_size=2582 say() { printf '%s\n' "$*"; } die() { printf 'cocalc-plus install: %s\n' "$*" >&2 exit 1 } os=$(uname -s) arch=$(uname -m) case "$os" in Linux) os=linux ;; Darwin) os=darwin ;; *) die "unsupported operating system: $os (Linux and macOS are supported)" ;; esac case "$arch" in x86_64 | amd64) arch=x64 ;; aarch64 | arm64) arch=arm64 ;; *) die "unsupported processor: $arch" ;; esac # The official Node needs glibc. A glibc system may also have the musl package # (/lib/ld-musl-*, as on many Ubuntu images), so refuse only without glibc. if [ "$os" = linux ] && ! getconf GNU_LIBC_VERSION >/dev/null 2>&1 && ls /lib/ld-musl-* >/dev/null 2>&1; then die "musl-based Linux (such as Alpine) is not supported yet" fi platform="$os-$arch" case "$platform" in linux-x64) node_sha=15fc043a51a5783f2f4b634561091658f5a7f0e3db03f997dca3a8033a33e45b node_size=62798625 node_dir='node-v26.11.1-linux-x64' node_bin_sha=5a7b8a3cf5ccb57d297519754fd73238f64cf560afd0ef19a2f9bf7384cbb657 node_bin_size=150047368 app_sha=f0f502a77e418857d2026a084e8d7dc02a3cfeeac1ff044fbd0fa606b2974bfb app_size=12393859 ;; linux-arm64) node_sha=170454fb022f5e9b5f6cc76c25fa32ef5100895be44eb04e92f9780591491bbf node_size=62559273 node_dir='node-v26.11.1-linux-arm64' node_bin_sha=71ad0706e6867350d477c15a2fb5548d3232b76adbf492952c5d9911680d3d6e node_bin_size=150232832 app_sha=c74f60385c2a03b743e71461d9f3df4661e44faaba3ab664acea0659c31b5912 app_size=11775377 ;; darwin-arm64) node_sha=d916511b55965e91be7a88e17f88d895b6793ceaba3e6c9b194aefe51c2c65ac node_size=58283153 node_dir='node-v26.11.1-darwin-arm64' node_bin_sha=72661776a737f5bbd7bc66af9dc5a5ef324819a53df518fdc7143127927c1378 node_bin_size=147222576 app_sha=181817c6c4e99ec2af3f03af8ea14f8f31ee2dd96b26d62ca6be5267baa7c217 app_size=11648270 ;; *) die "no CoCalc Plus build for $platform yet" ;; esac command -v curl >/dev/null 2>&1 || die "curl is required" command -v tar >/dev/null 2>&1 || die "tar is required" if command -v sha256sum >/dev/null 2>&1; then sha256() { sha256sum "$1" | cut -d' ' -f1; } elif command -v shasum >/dev/null 2>&1; then sha256() { shasum -a 256 "$1" | cut -d' ' -f1; } else die "sha256sum or shasum is required" fi root="${COCALC_PLUS_DIST_ROOT:-${XDG_DATA_HOME:-$HOME/.local/share}/cocalc/plus}" bindir="${XDG_BIN_HOME:-$HOME/.local/bin}" launcher="$bindir/cocalc-plus" [ -L "$root" ] && die "$root is a symbolic link; refusing to install there" say "Installing CoCalc Plus $version (release $release) from $origin." say "This gives $origin full code execution as your user, now and on every update." umask 077 mkdir -p "$root/staging" "$root/node" "$root/targets" "$root/manifests" "$root/blobs" (umask 022 && mkdir -p "$bindir") staging=$(mktemp -d "$root/staging/install.XXXXXX") trap 'rm -rf "$staging"' EXIT INT TERM # fetch : from the store only, never redirected. fetch() { curl -fsS --retry 2 --connect-timeout 20 -o "$2" "$origin$1" || die "download failed: $origin$1" got_size=$(wc -c <"$2" | tr -d ' ') [ "$got_size" = "$3" ] || die "$origin$1 has the wrong size ($got_size, expected $3)" [ "$(sha256 "$2")" = "$4" ] || die "$origin$1 does not match its sha256" } intact() { [ -f "$1" ] && [ ! -L "$1" ] && [ "$(wc -c <"$1" | tr -d ' ')" = "$2" ] && [ "$(sha256 "$1")" = "$3" ] } if ! intact "$root/node/$node_sha/bin/node" "$node_bin_size" "$node_bin_sha"; then say "Downloading Node for $platform..." fetch "/files/$node_sha" "$staging/node.tar.gz" "$node_size" "$node_sha" mkdir "$staging/node" tar -xzf "$staging/node.tar.gz" -C "$staging/node" "$node_dir/bin/node" "$node_dir/LICENSE" || die "could not unpack Node" intact "$staging/node/$node_dir/bin/node" "$node_bin_size" "$node_bin_sha" || die "the Node binary does not match the release manifest" mkdir -p "$staging/node-tree/bin" mv "$staging/node/$node_dir/bin/node" "$staging/node-tree/bin/node" mv "$staging/node/$node_dir/LICENSE" "$staging/node-tree/LICENSE" chmod 700 "$staging/node-tree/bin/node" rm -rf "$root/node/$node_sha" mv "$staging/node-tree" "$root/node/$node_sha" fi node="$root/node/$node_sha/bin/node" # The official Node needs a few system libraries, e.g. libatomic.so.1, which # minimal container images lack: name the missing ones instead of failing later. if ! env -u NODE_OPTIONS "$node" --version >/dev/null 2>&1; then missing=$(ldd "$node" 2>/dev/null | awk '/not found/ { printf "%s ", $1 }') [ -n "$missing" ] || die "Node does not run on this system" hint="" case " $missing" in *" libatomic.so.1 "*) hint=" (on Debian or Ubuntu: sudo apt-get install libatomic1; on Fedora or RHEL: sudo dnf install libatomic)" ;; esac die "Node needs system libraries that are missing: $missing$hint. Install them and run this again." fi say "Downloading CoCalc Plus..." if ! intact "$root/targets/$bootstrap/bootstrap.js" "$bootstrap_size" "$bootstrap"; then mkdir "$staging/bootstrap" fetch "/files/$bootstrap" "$staging/bootstrap/bootstrap.js" "$bootstrap_size" "$bootstrap" rm -rf "$root/targets/$bootstrap" mv "$staging/bootstrap" "$root/targets/$bootstrap" fi fetch "/manifests/$manifest.json" "$staging/manifest.json" "$manifest_size" "$manifest" fetch "/files/$launcher_sha" "$staging/launcher" "$launcher_size" "$launcher_sha" if ! intact "$root/blobs/$app_sha" "$app_size" "$app_sha"; then fetch "/files/$app_sha" "$staging/app.tar.zst" "$app_size" "$app_sha" mv "$staging/app.tar.zst" "$root/blobs/$app_sha" fi # Unpack the app with Node's own zstd (no xz or zstd tools needed). mkdir "$staging/app" "$node" -e 'const fs=require("fs"),z=require("zlib");fs.createReadStream(process.argv[1]).pipe(z.createZstdDecompress()).pipe(process.stdout)' \ "$root/blobs/$app_sha" | tar -xf - -C "$staging/app" || die "could not unpack CoCalc Plus" [ -f "$staging/app/bundle/index.js" ] || die "the app part has no bundle/index.js" # The new CoCalc Plus finishes the install: it fetches the remaining parts, # assembles the release, installs the launcher and switches `active`. unset NODE_OPTIONS NODE_PATH NODE_REPL_EXTERNAL_MODULE COCALC_PLUS_DIST_ROOT="$root" "$node" "$staging/app/bundle/index.js" \ update --finish-install \ --origin "$origin" \ --manifest-file "$staging/manifest.json" \ --launcher-file "$staging/launcher" \ --launcher-path "$launcher" /dev/null; then mkdir -p "$(dirname "$rc")" printf '%s\n' "$line" >>"$rc" say "Added $bindir to PATH in $rc." fi say "Done. Open a new shell (or run: export PATH=\"$bindir:\$PATH\"), then start it with: cocalc-plus" ;; esac