#!/bin/bash # shellcheck shell=bash # updateOllama: Lädt und installiert die aktuelle Ollama-Version (stable oder beta). set -euo pipefail shopt -s nullglob readonly GITHUB_API="https://api.github.com/repos/ollama/ollama" readonly INSTALL_URL="https://ollama.com/install.sh" PROG_NAME=$(basename "$0") || { printf 'Fehler: basename fehlgeschlagen\n' >&2; exit 1; } readonly PROG_NAME usage() { printf 'Verwendung: %s [--beta|-b] [--force|-f]\n' "$PROG_NAME" >&2 exit 2 } check_dependencies() { local cmd for cmd in curl grep sed sort mktemp chmod; do if ! command -v "$cmd" >/dev/null 2>&1; then die "Benötigtes Kommando '$cmd' nicht gefunden." fi done } die() { printf 'Fehler: %s\n' "$1" >&2 exit "${2:-1}" } parse_args() { local use_beta_ref=$1 local force_ref=$2 local use_beta_value=false local force_value=false shift 2 while [[ $# -gt 0 ]]; do case "$1" in --beta|-b) use_beta_value=true ;; --force|-f) force_value=true ;; -h|--help) usage ;; *) usage ;; esac shift done printf -v "$use_beta_ref" '%s' "$use_beta_value" printf -v "$force_ref" '%s' "$force_value" } get_local_version() { local version_output # stdout und stderr erfassen; einige Ollama-Versionen geben die # Versionszeile auf stderr aus, das sonst verworfen wuerde. if ! version_output=$(ollama --version 2>&1); then return 0 fi printf '%s\n' "$version_output" | grep -oEm1 '[0-9]+\.[0-9]+\.[0-9]+[^[:space:]]*' || true } # Helfer: GitHub-API abrufen und sicherstellen, dass die Antwort nicht leer ist. fetch_github_json() { local url=$1 local response if ! response=$(curl -fsSL "$url"); then die "API-Anfrage fehlgeschlagen: $url" fi if [[ -z "$response" ]]; then die "API-Antwort war leer: $url" fi printf '%s\n' "$response" } get_latest_version() { local url=$1 local json json=$(fetch_github_json "$url") printf '%s\n' "$json" | sed -nE 's/.*"tag_name": *"v?([^"]+)".*/\1/p' | head -n1 } # Vergleicht zwei Versionsstrings (SemVer-ähnlich, Suffixe alphabetisch). # Gibt -1, 0 oder 1 aus. cmp_versions() { local a=${1#v} b=${2#v} local a_main=${a%%-*} b_main=${b%%-*} local a_parts b_parts local max_len i IFS=. read -r -a a_parts <<< "$a_main" IFS=. read -r -a b_parts <<< "$b_main" max_len=${#a_parts[@]} if (( ${#b_parts[@]} > max_len )); then max_len=${#b_parts[@]} fi for (( i=0; i bv )); then printf '%s\n' 1 return 0 fi done local a_suffix=${a#*-} b_suffix=${b#*-} [[ "$a_suffix" == "$a_main" ]] && a_suffix="" [[ "$b_suffix" == "$b_main" ]] && b_suffix="" if [[ -z "$a_suffix" && -z "$b_suffix" ]]; then printf '%s\n' 0 return 0 fi if [[ -z "$a_suffix" ]]; then printf '%s\n' 1 return 0 fi if [[ -z "$b_suffix" ]]; then printf '%s\n' -1 return 0 fi if [[ "$a_suffix" == "$b_suffix" ]]; then printf '%s\n' 0 return 0 fi if [[ "$(printf '%s\n' "$a_suffix" "$b_suffix" | sort -V | head -n1)" == "$a_suffix" ]]; then printf '%s\n' -1 else printf '%s\n' 1 fi } install_ollama() { local version=$1 local tmp_script tmp_script=$(mktemp "${TMPDIR:-/tmp}/ollama-install.XXXXXX") # Temporäre Datei beim Beenden oder Abbruch aufräumen. trap 'rm -f "$tmp_script"' EXIT printf 'Lade Installations-Skript herunter ...\n' curl -fsSL "$INSTALL_URL" -o "$tmp_script" || die "Herunterladen von $INSTALL_URL fehlgeschlagen." if [[ ! -s "$tmp_script" ]]; then die "Installations-Skript ist leer." fi if [[ -n "$version" ]]; then export OLLAMA_VERSION="$version" fi # Skript ausführbar machen und ausführen. chmod +x "$tmp_script" || die "Konnte Installations-Skript nicht ausführbar machen." "$tmp_script" || die "Installation von Ollama ist fehlgeschlagen." # Erfolg: temporäre Datei löschen und Trap entfernen, damit er beim # späteren Script-Exit nicht auf eine nicht mehr existierende lokale # Variable zugreift (sonst Fehler wegen 'set -u'). trap - EXIT rm -f "$tmp_script" } main() { local use_beta=false local force_downgrade=false local local_ver stable_ver beta_ver local target_ver="" parse_args use_beta force_downgrade "$@" check_dependencies local_ver=$(get_local_version) # Immer Stable und Beta (neueste Release inkl. Pre-Releases) abrufen. stable_ver=$(get_latest_version "$GITHUB_API/releases/latest") if [[ -z "$stable_ver" ]]; then die "Ermittlung der aktuellen Stable-Version fehlgeschlagen." fi beta_ver=$(get_latest_version "$GITHUB_API/releases?per_page=1") if [[ -z "$beta_ver" ]]; then die "Ermittlung der aktuellen Beta-Version fehlgeschlagen." fi printf 'Lokal: %s\n' "${local_ver:-(nicht installiert)}" printf 'Stable: %s\n' "$stable_ver" if [[ "$(cmp_versions "$beta_ver" "$stable_ver")" == 1 ]]; then printf 'Beta: %s\n' "$beta_ver" else printf 'Beta: keine neuere Beta verfuegbar\n' fi if [[ -z "$local_ver" ]]; then # Keine lokale Installation. if [[ "$use_beta" == true ]] && [[ "$(cmp_versions "$beta_ver" "$stable_ver")" == 1 ]]; then target_ver="$beta_ver" printf 'Ollama ist nicht installiert. Installation der Beta %s.\n' "$target_ver" else target_ver="$stable_ver" printf 'Ollama ist nicht installiert. Installation der Stable %s.\n' "$target_ver" fi else # Lokale Installation vorhanden. if [[ "$use_beta" == true ]]; then if [[ "$(cmp_versions "$beta_ver" "$stable_ver")" == 1 ]] \ && [[ "$(cmp_versions "$beta_ver" "$local_ver")" == 1 ]]; then target_ver="$beta_ver" printf 'Beta-Update verfuegbar: %s -> %s\n' "$local_ver" "$target_ver" elif [[ "$(cmp_versions "$stable_ver" "$local_ver")" == 1 ]]; then target_ver="$stable_ver" printf 'Stable-Update verfuegbar: %s -> %s\n' "$local_ver" "$target_ver" else printf 'Kein Update erforderlich.\n' return 0 fi else if [[ "$(cmp_versions "$stable_ver" "$local_ver")" == 1 ]]; then target_ver="$stable_ver" printf 'Update verfuegbar: %s -> %s\n' "$local_ver" "$target_ver" else printf 'Kein Update erforderlich.\n' return 0 fi fi fi # Downgrade-Schutz: Eine Installation älterer Version als die bereits # installierte nur mit --force/-f erlauben. if [[ -n "$local_ver" && -n "$target_ver" && "$(cmp_versions "$target_ver" "$local_ver")" == -1 ]]; then if [[ "$force_downgrade" != true ]]; then printf 'Aktuelle Version %s ist neuer als Zielversion %s. Downgrade abgebrochen (verwende --force/-f, um es trotzdem durchzuführen).\n' "$local_ver" "$target_ver" >&2 return 0 fi printf 'Downgrade wird erzwungen: %s -> %s\n' "$local_ver" "$target_ver" fi # Bei Beta-Installation die gewünschte Version an das Installer-Skript übergeben. if [[ "$use_beta" == true && -n "$target_ver" && "$target_ver" != "$stable_ver" ]]; then install_ollama "$target_ver" else install_ollama "" fi } main "$@"