Files
dify/cli/scripts/install-cli.sh

133 lines
4.5 KiB
Bash
Executable File

#!/bin/sh
# install-cli.sh — one-line difyctl installer for Linux and macOS.
#
# usage:
# curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh
#
# env: DIFYCTL_VERSION (default latest), DIFYCTL_PREFIX (default $HOME/.local),
# DIFYCTL_REPO (default langgenius/dify).
# requires: curl, tar (xz), uname, jq, sha256sum or shasum.
set -eu
REPO="${DIFYCTL_REPO:-langgenius/dify}"
VERSION="${DIFYCTL_VERSION:-latest}"
PREFIX="${DIFYCTL_PREFIX:-${HOME}/.local}"
err() { printf '%s\n' "install-cli: $*" >&2; }
die() { err "$*"; exit 1; }
need() { command -v "$1" >/dev/null 2>&1 || die "$1 is required"; }
need curl
need tar
need uname
need jq
if command -v sha256sum >/dev/null 2>&1; then
HASH="sha256sum"
elif command -v shasum >/dev/null 2>&1; then
HASH="shasum -a 256"
else
die "need sha256sum or shasum"
fi
case "$(uname -s)" in
Linux*) os=linux ;;
Darwin*) os=darwin ;;
*) die "unsupported OS: $(uname -s)" ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch=x64 ;;
arm64|aarch64) arch=arm64 ;;
*) die "unsupported arch: $(uname -m)" ;;
esac
target="${os}-${arch}"
if [ "$VERSION" = "latest" ]; then
api="https://api.github.com/repos/${REPO}/releases/latest"
else
api="https://api.github.com/repos/${REPO}/releases/tags/${VERSION}"
fi
release=$(curl -fsSL "$api") || die "could not fetch release metadata from ${api}"
tag=$(printf '%s' "$release" | jq -r '.tag_name')
[ -n "$tag" ] && [ "$tag" != "null" ] || die "release has no tag_name"
matches=$(printf '%s' "$release" \
| jq -r --arg t "$target" '.assets[].name | select(test("^difyctl-v[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?-\($t)\\.tar\\.xz$"))')
count=$(printf '%s' "$matches" | grep -c . || true)
case "$count" in
0) die "no difyctl asset for ${target} on ${tag}" ;;
1) asset="$matches" ;;
*) die "expected exactly 1 difyctl asset for ${target} on ${tag}, found ${count}: ${matches}" ;;
esac
no_target="${asset%-${target}.tar.xz}"
cli_v="${no_target#difyctl-}"
checksums="difyctl-${cli_v}-checksums.txt"
printf '%s' "$release" | jq -e --arg c "$checksums" '.assets[] | select(.name == $c)' >/dev/null \
|| die "checksum file ${checksums} missing on ${tag}; refusing to install unverified binary"
url="https://github.com/${REPO}/releases/download/${tag}/${asset}"
sums_url="https://github.com/${REPO}/releases/download/${tag}/${checksums}"
tmp=$(mktemp -d 2>/dev/null || mktemp -d -t difyctl-install)
trap 'rm -rf "$tmp"' EXIT INT TERM
printf 'downloading %s\n from %s\n' "$asset" "$url"
curl -fsSL --retry 3 "$url" -o "${tmp}/${asset}"
curl -fsSL --retry 3 "$sums_url" -o "${tmp}/${checksums}"
(
cd "$tmp"
grep " ${asset}\$" "$checksums" | $HASH -c -
) || die "checksum mismatch for ${asset}"
if command -v cosign >/dev/null 2>&1; then
sig_url="${url}.sig"
pem_url="${url}.pem"
curl -fsSL --retry 3 "$sig_url" -o "${tmp}/${asset}.sig" \
|| die "tarball signature missing on ${tag}; refusing to install (cosign present)"
curl -fsSL --retry 3 "$pem_url" -o "${tmp}/${asset}.pem" \
|| die "tarball cert missing on ${tag}; refusing to install (cosign present)"
COSIGN_EXPERIMENTAL=1 cosign verify-blob \
--certificate "${tmp}/${asset}.pem" \
--signature "${tmp}/${asset}.sig" \
--certificate-identity-regexp '^https://github.com/langgenius/dify/' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${tmp}/${asset}" \
|| die "cosign verification failed for ${asset}"
printf 'cosign: verified %s\n' "$asset"
else
printf 'note: cosign not installed; skipping signature verification (sha256 still enforced)\n' >&2
fi
share_dir="${PREFIX}/share/difyctl"
bin_dir="${PREFIX}/bin"
mkdir -p "$share_dir" "$bin_dir"
printf 'extracting to %s\n' "$share_dir"
tar -xJf "${tmp}/${asset}" -C "$share_dir" --strip-components=1
target_bin="${share_dir}/bin/difyctl"
[ -x "$target_bin" ] || die "expected binary at ${target_bin} after extract"
ln -sf "$target_bin" "${bin_dir}/difyctl"
printf '\ndifyctl %s installed: %s/difyctl\n' "$cli_v" "$bin_dir"
case ":${PATH}:" in
*":${bin_dir}:"*)
"${bin_dir}/difyctl" version >/dev/null 2>&1 \
&& printf 'verify: run "difyctl version"\n' \
|| err "binary present but failed to execute; check ${bin_dir}/difyctl"
;;
*)
printf '\n%s is not on your PATH. Add this to your shell profile:\n' "$bin_dir"
printf ' export PATH="%s:$PATH"\n' "$bin_dir"
;;
esac