#!/bin/sh # danio installer, served by a workspace's host (05-WORKSPACE §5) and by # danio.app (01-ARCHITECTURE §10), one file for both: # # curl -fsSL /install.sh | sh -s -- -e -t <设备令牌> [--from official] [--auto-update] [--cache-dir <目录>] [--work-dir <目录>] # curl -fsSL https://danio.app/install.sh | sh # # With a host: downloads the host's danio for this machine from the host # (with --from official, from the official releases: the host gives the # address and the checksum) and joins the workspace with the token. # Without one (the site's script): the newest release, through the site. # Either way it checks the download against its SHA-256, puts it in /opt/danio (root) or # ~/.local/share/danio, sets the machine config it was given, starts it # with the computer (systemd; without systemd, as in a container, in the # background now). Run it again to update danio (to the host's version). set -eu # the person's language, as danio picks it (10-TEXT §6): Chinese where the # system says zh, else English. m says its first words or its second. lang_tag="" for v in "${LC_ALL:-}" "${LC_MESSAGES:-}" "${LANG:-}"; do case "$v" in ""|C|POSIX) ;; *) lang_tag="$v"; break ;; esac done case "$lang_tag" in zh*|ZH*) zh=1 ;; *) zh=0 ;; esac m() { if [ "$zh" = 1 ]; then printf '%s' "$1"; else printf '%s' "$2"; fi; } # how it looks: danio's mark and colours on a terminal (as danio tui), # plain words in a log or with NO_COLOR if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-}" != dumb ]; then e=$(printf '\033') A="$e[1;38;5;147m" B="$e[1m" D="$e[90m" G="$e[32m" Y="$e[33m" R="$e[31m" N="$e[0m" else A="" B="" D="" G="" Y="" R="" N="" fi step() { printf ' %s▸%s %s\n' "$A" "$N" "$*"; } ok() { printf ' %s✓%s %s\n' "$G" "$N" "$*"; } warn() { printf ' %s!%s %s\n' "$Y" "$N" "$*"; } # note: another command's words, indented and dimmed note() { printf '%s\n' "$*" | while IFS= read -r l; do [ -z "$l" ] || printf ' %s%s%s\n' "$D" "$l" "$N"; done; } die() { printf ' %s✗%s %s\n' "$R" "$N" "$*" >&2; exit 1; } # mark: danio's fish (internal/banner), the name and $1 beside it mark() { printf '\n' printf ' %s\n' " ▀▀▀▀▀" printf ' %s %sdanio%s\n' " ▀▀▀▀▀▀▀▀▀ ▀▀▀" "$A" "$N" printf ' %s %s%s%s\n' "▀▀▀▀▀▀▀▀▀▀ ▀▀ " "$D" "$1" "$N" printf ' %s\n' " ▀▀▀▀▀▀▀▀▀ ▀▀▀" " ▀▀▀▀▀" printf '\n' } endpoint="" token="${DANIO_JOIN_TOKEN:-}" service=1 auto_update=0 from=host dir="" cache_dir="" work_dir="" shared_cache_dir="" while [ $# -gt 0 ]; do case "$1" in -e|--endpoint) endpoint="$2"; shift 2 ;; -t|--token) token="$2"; shift 2 ;; --from) from="$2"; shift 2 ;; --auto-update) auto_update=1; shift ;; --no-service) service=0; shift ;; --dir) dir="$2"; shift 2 ;; --cache-dir) cache_dir="$2"; shift 2 ;; --work-dir) work_dir="$2"; shift 2 ;; --shared-cache-dir) shared_cache_dir="$2"; shift 2 ;; *) die "$(m 不认识的参数 'unknown option') $1" ;; esac done endpoint="${endpoint%/}" case "$from" in host) q="" ;; official) q="?from=official" ;; *) die "$(m '--from 只能是 host 或 official' '--from can only be host or official')" ;; esac # no host: the newest release, from the site src="$endpoint" if [ -z "$endpoint" ]; then [ -z "$token" ] || die "$(m '有令牌时要用 -e 给出主机地址' 'with a token, give the host address with -e')" src=https://danio.app from=official q="" fi [ "$(uname -s)" = Linux ] || die "$(m '这个脚本只用于 Linux;Windows 用 install.ps1' 'this script is for Linux; on Windows use install.ps1')" case "$(uname -m)" in x86_64|amd64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) die "$(m "不支持的 CPU:$(uname -m)" "CPU not supported: $(uname -m)")" ;; esac file="danio-linux-$arch" command -v curl >/dev/null || die "$(m '需要 curl' 'curl is needed')" if [ "$(id -u)" = 0 ]; then dir="${dir:-/opt/danio}"; bin=/usr/local/bin else dir="${dir:-${XDG_DATA_HOME:-$HOME/.local/share}/danio}"; bin="$HOME/.local/bin" fi tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT mark "$(m 安装程序 installer)" if [ "$from" = official ]; then step "$(m "从官方源下载 $file" "Downloading $file from the official releases")"; else step "$(m "从 $src 下载 $file" "Downloading $file from $src")"; fi # not through a pipe: its status would be cut's, hiding a failed fetch sum=$(curl -fsSL "$src/download/$file.sha256$q") && sum=${sum%% *} && [ -n "$sum" ] || die "$(m "取不到 $file 的校验值($src)" "can't get the checksum of $file ($src)")" curl -fSL --progress-bar -o "$tmp/danio" "$src/download/$file$q" || die "$(m 下载失败 'the download failed')" if command -v sha256sum >/dev/null; then got=$(sha256sum "$tmp/danio" | cut -d' ' -f1) else got=$(shasum -a 256 "$tmp/danio" | cut -d' ' -f1); fi [ "$got" = "$sum" ] || die "$(m "$file 与校验值不符" "$file doesn't match its checksum")" mkdir -p "$dir" "$bin" install -m 755 "$tmp/danio" "$dir/danio.new" mv -f "$dir/danio.new" "$dir/danio" ln -sf "$dir/danio" "$bin/danio" ver=$("$dir/danio" version) ver=${ver#danio } ver=${ver%% *} ok "$(m "已安装 $dir/danio($ver)" "Installed $dir/danio ($ver)")" # setting runs danio config set, showing danio's words only when it fails setting() { out=$("$dir/danio" config set "$1" "$2" 2>&1) || { note "$out"; die "$3"; } ok "$(m "已设置 $1 = $2" "Set $1 = $2")" } # the machine config before danio first starts: it reads it then if [ "$auto_update" = 1 ]; then setting auto_update true "$(m 设不了自动更新 "can't turn on auto update")" fi if [ -n "$cache_dir" ]; then mkdir -p "$cache_dir" || die "$(m "建不了缓存目录 $cache_dir" "can't make the cache folder $cache_dir")" setting cache_dir "$cache_dir" "$(m "设不了缓存目录 $cache_dir" "can't set the cache folder $cache_dir")" fi if [ -n "$work_dir" ]; then mkdir -p "$work_dir" || die "$(m "建不了工作目录 $work_dir" "can't make the working folder $work_dir")" setting work_dir "$work_dir" "$(m "设不了工作目录 $work_dir" "can't set the working folder $work_dir")" fi if [ -n "$shared_cache_dir" ]; then mkdir -p "$shared_cache_dir" || die "$(m "建不了共享缓存目录 $shared_cache_dir" "can't make the shared cache folder $shared_cache_dir")" setting shared_cache_dir "$shared_cache_dir" "$(m "设不了共享缓存目录 $shared_cache_dir" "can't set the shared cache folder $shared_cache_dir")" fi # the system libraries Blender draws with: a server or a container has # few, and a pack's Blender won't start without them. Installed as root, # else said libs=$("$dir/danio" doctor --libs 2>/dev/null) || libs="" if [ -n "$libs" ]; then if [ "$(id -u)" = 0 ]; then step "$(m '安装 Blender 需要的系统库' 'Installing the system libraries Blender needs')" if out=$(DEBIAN_FRONTEND=noninteractive sh -c "$libs" 2>&1); then ok "$(m 已安装系统库 'System libraries installed')" else note "$(printf '%s\n' "$out" | tail -n 5)" warn "$(m "系统库没装上,之后运行:$libs" "The system libraries didn't install; run later: $libs")" fi else warn "$(m "Blender 需要的系统库没装全,运行:$libs" "Blender lacks system libraries; run: $libs")" fi fi if [ "$service" = 1 ]; then step "$(m 设为随电脑启动 'Making it start with the computer')" if [ "$(id -u)" = 0 ] && [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then # systemd runs it: a failure is the service's, not a missing systemd out=$("$dir/danio" service install 2>&1) || { note "$out"; die "$(m '后台服务没有起来:看 systemctl status danio 和 journalctl -u danio' "the background service didn't start: see systemctl status danio and journalctl -u danio")"; } note "$out" elif out=$("$dir/danio" service install 2>&1); then note "$out" else # no systemd (a container): run it now; after a reboot, run danio serve again nohup "$dir/danio" serve >"$dir/serve.log" 2>&1 & sleep 2 warn "$(m "没有 systemd:已在后台运行 danio serve(日志 $dir/serve.log);机器重启后要再运行一次" "No systemd: danio serve runs in the background now (log $dir/serve.log); run it again after a reboot")" fi fi if [ -n "$token" ]; then step "$(m "加入工作区 $endpoint" "Joining the workspace at $endpoint")" DANIO_JOIN_TOKEN="$token" "$dir/danio" workspace join "$endpoint" fi # what next: the commands, by the name that works here cmd=danio case ":$PATH:" in *":$bin:"*) ;; *) cmd="$dir/danio" ;; esac printf '\n' ok "$B$(m "danio 已就绪" "danio is ready")$N" [ "$cmd" = danio ] || warn "$(m "把 $bin 加进 PATH 后可以直接运行 danio" "Add $bin to PATH to run danio directly")" printf '\n' w=$((${#cmd} + 11)) row() { printf " %s%-${w}s%s %s%s%s\n" "$B" "$cmd $1" "$N" "$D" "$2" "$N"; } row tui "$(m 在终端中打开界面 'the interface in this terminal')" row web "$(m 在浏览器中打开界面 'the interface in a browser')" row status "$(m 查看运行状态和目录 'whether it runs, and where its files are')" row uninstall "$(m 卸载 'uninstall it')" printf '\n'