From 756b788605351e7789e6faef625110e21357ce2a Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Sat, 15 Aug 2020 10:13:43 +0700 Subject: [PATCH] Update external Umbrel installation when booting from a newer Umbrel OS version. (#134) --- events/triggers/update | 70 +-- .../external-storage/update-from-sdcard | 58 ++ scripts/umbrel-os/semver | 521 ++++++++++++++++++ .../services/umbrel-external-storage.service | 2 + scripts/update/00-run.sh | 2 +- scripts/update/01-run.sh | 2 +- scripts/update/02-run.sh | 2 +- scripts/update/03-run.sh | 2 +- scripts/update/update | 109 ++++ 9 files changed, 696 insertions(+), 72 deletions(-) create mode 100755 scripts/umbrel-os/external-storage/update-from-sdcard create mode 100755 scripts/umbrel-os/semver create mode 100755 scripts/update/update diff --git a/events/triggers/update b/events/triggers/update index 3c14137..c2e017f 100755 --- a/events/triggers/update +++ b/events/triggers/update @@ -1,71 +1,5 @@ #!/usr/bin/env bash -check_dependencies () { - for cmd in "$@"; do - if ! command -v "$cmd" >/dev/null 2>&1; then - echo "This script requires \"${cmd}\" to be installed" - exit 1 - fi - done -} +UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)" -check_dependencies jq wget git rsync - -# UMBREL_ROOT=/home/umbrel -UMBREL_ROOT=$(dirname $(readlink -f "${BASH_SOURCE[0]}"))/../.. -RELEASE=$(cat "$UMBREL_ROOT"/statuses/update-status.json | jq .updateTo -r) - -echo -echo "=======================================" -echo "============= OTA UPDATE ==============" -echo "=======================================" -echo "========== Stage: Download ============" -echo "=======================================" -echo - -# Make sure an update is not in progres -if [[ -f "$UMBREL_ROOT/statuses/update-in-progress" ]]; then - echo "An update is already in progress. Exiting now." - exit 2 -fi - -echo "Creating lock" -touch "$UMBREL_ROOT"/statuses/update-in-progress - -# Cleanup just in case there's temp stuff lying around from previous update -echo "Cleaning up any previous mess" -[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE" - -# Update status file -cat < "$UMBREL_ROOT"/statuses/update-status.json -{"state": "installing", "progress": 10, "description": "Downloading Umbrel $RELEASE", "updateTo": "$RELEASE"} -EOF - -# Clone new release -echo "Downloading Umbrel $RELEASE" -mkdir -p "$UMBREL_ROOT"/.umbrel-"$RELEASE" -cd "$UMBREL_ROOT"/.umbrel-"$RELEASE" -curl -L "https://github.com/getumbrel/umbrel/archive/$RELEASE.tar.gz" | tar -xz --strip-components=1 - -# Run update scripts -echo "Running update install scripts of the new release" -cd scripts/update -UPDATE_INSTALL_SCRIPTS=$(ls *-run.sh) -for script in $UPDATE_INSTALL_SCRIPTS; do - if [[ -x $script ]]; then - echo - echo "== Begin Update Script $script ==" - ./"$script" "$RELEASE" "$UMBREL_ROOT" - echo "== End Update Script $script ==" - echo - fi -done - -# Delete cloned repo -echo "Deleting cloned repository" -[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE" - -echo "Removing lock" -rm -f "$UMBREL_ROOT"/statuses/update-in-progress - -exit 0 +"${UMBREL_ROOT}/scripts/update/update" --ota diff --git a/scripts/umbrel-os/external-storage/update-from-sdcard b/scripts/umbrel-os/external-storage/update-from-sdcard new file mode 100755 index 0000000..3a93c82 --- /dev/null +++ b/scripts/umbrel-os/external-storage/update-from-sdcard @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -euo pipefail + +UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../../..)" +SD_MOUNT_POINT="/sd-root" +SD_UMBREL_ROOT="${SD_MOUNT_POINT}${UMBREL_ROOT}" + +check_root () { + if [[ $UID != 0 ]]; then + echo "This script must be run as root" + exit 1 + fi +} + +check_dependencies () { + for cmd in "$@"; do + if ! command -v $cmd >/dev/null 2>&1; then + echo "This script requires \"${cmd}\" to be installed" + exit 1 + fi + done +} + +check_semver_range () { + local range="${1}" + local version="${2}" + "${UMBREL_ROOT}/scripts/umbrel-os/semver" -r "${range}" "${version}" | grep --quiet "^${version}$" +} + +main () { + check_root + check_dependencies jq + echo "Checking if SD card Umbrel is newer than external storage..." + local external_version=$(cat "${UMBREL_ROOT}/info.json" | jq -r .version | cut -d "-" -f "1") + local sd_version=$(cat "${SD_UMBREL_ROOT}/info.json" | jq -r .version | cut -d "-" -f "1") + + if ! check_semver_range ">${external_version}" "${sd_version}"; then + echo "No, SD version is not newer, exiting." + exit 0 + fi + + echo "Yes, SD version is newer." + # This will fail if we ever have multiple ranges with pre-release tags. + # e.g `1.2.3-beta <2.0.0` will become `1.2.3` due to striping the `-` + local update_requirement=$(cat "${SD_UMBREL_ROOT}/info.json" | jq -r .requires | cut -d "-" -f "1") + + echo "Checking if the external storage version \"${external_version}\" satisfies update requirement \"${update_requirement}\"..." + if ! check_semver_range "${update_requirement}" "${external_version}"; then + echo "No, we can't do an automatic update, exiting." + exit 0 + fi + + echo "Yes, it does, attempting an automatic update..." + "${UMBREL_ROOT}/scripts/update/update" --path "${SD_UMBREL_ROOT}" +} + +main diff --git a/scripts/umbrel-os/semver b/scripts/umbrel-os/semver new file mode 100755 index 0000000..2828114 --- /dev/null +++ b/scripts/umbrel-os/semver @@ -0,0 +1,521 @@ +#!/usr/bin/env bash + +# https://github.com/qzb/sh-semver +# Commit: 2ac2437 + +_num_part='([0-9]|[1-9][0-9]*)' +_lab_part='([0-9]|[1-9][0-9]*|[0-9]*[a-zA-Z-][a-zA-Z0-9-]*)' +_met_part='([0-9A-Za-z-]+)' + +RE_NUM="$_num_part(\.$_num_part)*" +RE_LAB="$_lab_part(\.$_lab_part)*" +RE_MET="$_met_part(\.$_met_part)*" +RE_VER="[ \t]*$RE_NUM(-$RE_LAB)?(\+$RE_MET)?" + +BRE_DIGIT='[0-9]\{1,\}' +BRE_ALNUM='[0-9a-zA-Z-]\{1,\}' +BRE_IDENT="$BRE_ALNUM\(\.$BRE_ALNUM\)*" + +BRE_MAJOR="$BRE_DIGIT" +BRE_MINOR="\(\.$BRE_DIGIT\)\{0,1\}" +BRE_PATCH="\(\.$BRE_DIGIT\)\{0,1\}" +BRE_PRERE="\(-$BRE_IDENT\)\{0,1\}" +BRE_BUILD="\(+$BRE_IDENT\)\{0,1\}" +BRE_VERSION="${BRE_MAJOR}${BRE_MINOR}${BRE_PATCH}${BRE_PRERE}${BRE_BUILD}" + +filter() +{ + local text="$1" + local regex="$2" + shift 2 + echo "$text" | grep -E "$@" "$regex" +} + +# Gets number part from normalized version +get_number() +{ + echo "${1%%-*}" +} + +# Gets prerelase part from normalized version +get_prerelease() +{ + local pre_and_meta=${1%+*} + local pre=${pre_and_meta#*-} + if [ "$pre" = "$1" ]; then + echo + else + echo "$pre" + fi +} + +# Gets major number from normalized version +get_major() +{ + echo "${1%%.*}" +} + +# Gets minor number from normalized version +get_minor() +{ + local minor_major_bug=${1%%-*} + local minor_major=${minor_major_bug%.*} + local minor=${minor_major#*.} + + if [ "$minor" = "$minor_major" ]; then + echo + else + echo "$minor" + fi +} + +get_bugfix() +{ + local minor_major_bug=${1%%-*} + local bugfix=${minor_major_bug##*.*.} + + if [ "$bugfix" = "$minor_major_bug" ]; then + echo + else + echo "$bugfix" + fi +} + +strip_metadata() +{ + echo "${1%+*}" +} + +semver_eq() +{ + local ver1 ver2 part1 part2 + ver1=$(get_number "$1") + ver2=$(get_number "$2") + + local count=1 + while true; do + part1=$(echo "$ver1"'.' | cut -d '.' -f $count) + part2=$(echo "$ver2"'.' | cut -d '.' -f $count) + + if [ -z "$part1" ] || [ -z "$part2" ]; then + break + fi + + if [ "$part1" != "$part2" ]; then + return 1 + fi + + local count=$(( count + 1 )) + done + + if [ "$(get_prerelease "$1")" = "$(get_prerelease "$2")" ]; then + return 0 + else + return 1 + fi +} + +semver_lt() +{ + local number_a number_b prerelease_a prerelease_b + number_a=$(get_number "$1") + number_b=$(get_number "$2") + prerelease_a=$(get_prerelease "$1") + prerelease_b=$(get_prerelease "$2") + + + local head_a='' + local head_b='' + local rest_a=$number_a. + local rest_b=$number_b. + while [ -n "$rest_a" ] || [ -n "$rest_b" ]; do + head_a=${rest_a%%.*} + head_b=${rest_b%%.*} + rest_a=${rest_a#*.} + rest_b=${rest_b#*.} + + if [ -z "$head_a" ] || [ -z "$head_b" ]; then + return 1 + fi + + if [ "$head_a" -eq "$head_b" ]; then + continue + fi + + if [ "$head_a" -lt "$head_b" ]; then + return 0 + else + return 1 + fi + done + + if [ -n "$prerelease_a" ] && [ -z "$prerelease_b" ]; then + return 0 + elif [ -z "$prerelease_a" ] && [ -n "$prerelease_b" ]; then + return 1 + fi + + local head_a='' + local head_b='' + local rest_a=$prerelease_a. + local rest_b=$prerelease_b. + while [ -n "$rest_a" ] || [ -n "$rest_b" ]; do + head_a=${rest_a%%.*} + head_b=${rest_b%%.*} + rest_a=${rest_a#*.} + rest_b=${rest_b#*.} + + if [ -z "$head_a" ] && [ -n "$head_b" ]; then + return 0 + elif [ -n "$head_a" ] && [ -z "$head_b" ]; then + return 1 + fi + + if [ "$head_a" = "$head_b" ]; then + continue + fi + + # If both are numbers then compare numerically + if [ "$head_a" = "${head_a%[!0-9]*}" ] && [ "$head_b" = "${head_b%[!0-9]*}" ]; then + [ "$head_a" -lt "$head_b" ] && return 0 || return 1 + # If only a is a number then return true (number has lower precedence than strings) + elif [ "$head_a" = "${head_a%[!0-9]*}" ]; then + return 0 + # If only b is a number then return false + elif [ "$head_b" = "${head_b%[!0-9]*}" ]; then + return 1 + # Finally if of identifiers is a number compare them lexically + else + test "$head_a" \< "$head_b" && return 0 || return 1 + fi + done + + return 1 +} + +semver_gt() +{ + if semver_lt "$1" "$2" || semver_eq "$1" "$2"; then + return 1 + else + return 0 + fi +} + +semver_le() +{ + semver_gt "$1" "$2" && return 1 || return 0 +} + +semver_ge() +{ + semver_lt "$1" "$2" && return 1 || return 0 +} + +semver_sort() +{ + if [ $# -le 1 ]; then + echo "$1" + return + fi + + local pivot=$1 + local args_a=() + local args_b=() + + shift 1 + + for ver in "$@"; do + if semver_le "$ver" "$pivot"; then + args_a=( "${args_a[@]}" "$ver" ) + else + args_b=( "$ver" "${args_b[@]}" ) + fi + done + + args_a=( $(semver_sort "${args_a[@]}") ) + args_b=( $(semver_sort "${args_b[@]}") ) + echo "${args_a[@]}" "$pivot" "${args_b[@]}" +} + +regex_match() +{ + local string="$1 " + local regexp="$2" + local match + match="$(eval "echo '$string' | grep -E -o '^[ \t]*($regexp)[ \t]+'")"; + + for i in $(seq 0 9); do + unset "MATCHED_VER_$i" + unset "MATCHED_NUM_$i" + done + unset REST + + if [ -z "$match" ]; then + return 1 + fi + + local match_len=${#match} + REST="${string:$match_len}" + + local part + local i=1 + for part in $string; do + local ver num + ver="$(eval "echo '$part' | grep -E -o '$RE_VER' | head -n 1 | sed 's/ \t//g'")"; + num=$(get_number "$ver") + + if [ -n "$ver" ]; then + eval "MATCHED_VER_$i='$ver'" + eval "MATCHED_NUM_$i='$num'" + i=$(( i + 1 )) + fi + done + + return 0 +} + +# Normalizes rules string +# +# * replaces chains of whitespaces with single spaces +# * replaces whitespaces around hyphen operator with "_" +# * removes wildcards from version numbers (1.2.* -> 1.2) +# * replaces "x" with "*" +# * removes whitespace between operators and version numbers +# * removes leading "v" from version numbers +# * removes leading and trailing spaces +normalize_rules() +{ + echo " $1" \ + | sed 's/\\t/ /g' \ + | sed 's/ / /g' \ + | sed 's/ \{2,\}/ /g' \ + | sed 's/ - /_-_/g' \ + | sed 's/\([~^<>=]\) /\1/g' \ + | sed 's/\([ _~^<>=]\)v/\1/g' \ + | sed 's/\.[xX*]//g' \ + | sed 's/[xX]/*/g' \ + | sed 's/^ //g' \ + | sed 's/ $//g' +} + +# Reads rule from provided string +resolve_rule() +{ + local rule operator operands + rule="$1" + operator="$( echo "$rule" | sed "s/$BRE_VERSION/#/g" )" + operands=( $( echo "$rule" | grep -o "$BRE_VERSION") ) + + case "$operator" in + '*') echo "all" ;; + '#') echo "eq ${operands[0]}" ;; + '=#') echo "eq ${operands[0]}" ;; + '<#') echo "lt ${operands[0]}" ;; + '>#') echo "gt ${operands[0]}" ;; + '<=#') echo "le ${operands[0]}" ;; + '>=#') echo "ge ${operands[0]}" ;; + '#_-_#') echo "ge ${operands[0]}" + echo "le ${operands[1]}" ;; + '~#') echo "tilde ${operands[0]}" ;; + '^#') echo "caret ${operands[0]}" ;; + *) return 1 + esac +} + +resolve_rules() +{ + local rules + rules="$(normalize_rules "$1")" + IFS=' ' read -ra rules <<< "${rules:-all}" + + for rule in "${rules[@]}"; do + resolve_rule "$rule" + done +} + +rule_eq() +{ + local rule_ver="$1" + local tested_ver="$2" + + semver_eq "$tested_ver" "$rule_ver" && return 0 || return 1; +} + +rule_le() +{ + local rule_ver="$1" + local tested_ver="$2" + + semver_le "$tested_ver" "$rule_ver" && return 0 || return 1; +} + +rule_lt() +{ + local rule_ver="$1" + local tested_ver="$2" + + semver_lt "$tested_ver" "$rule_ver" && return 0 || return 1; +} + +rule_ge() +{ + local rule_ver="$1" + local tested_ver="$2" + + semver_ge "$tested_ver" "$rule_ver" && return 0 || return 1; +} + +rule_gt() +{ + local rule_ver="$1" + local tested_ver="$2" + + semver_gt "$tested_ver" "$rule_ver" && return 0 || return 1; +} + +rule_tilde() +{ + local rule_ver="$1" + local tested_ver="$2" + + if rule_ge "$rule_ver" "$tested_ver"; then + local rule_major rule_minor + rule_major=$(get_major "$rule_ver") + rule_minor=$(get_minor "$rule_ver") + + if [ -n "$rule_minor" ] && rule_eq "$rule_major.$rule_minor" "$(get_number "$tested_ver")"; then + return 0 + fi + if [ -z "$rule_minor" ] && rule_eq "$rule_major" "$(get_number "$tested_ver")"; then + return 0 + fi + fi + + return 1 +} + +rule_caret() +{ + local rule_ver="$1" + local tested_ver="$2" + + if rule_ge "$rule_ver" "$tested_ver"; then + local rule_major + rule_major="$(get_major "$rule_ver")" + + if [ "$rule_major" != "0" ] && rule_eq "$rule_major" "$(get_number "$tested_ver")"; then + return 0 + fi + if [ "$rule_major" = "0" ] && rule_eq "$rule_ver" "$(get_number "$tested_ver")"; then + return 0 + fi + fi + + return 1 +} + +rule_all() +{ + return 0 +} + +apply_rules() +{ + local rules_string="$1" + shift + local versions=( "$@" ) + + # Loop over sets of rules (sets of rules are separated with ||) + for ver in "${versions[@]}"; do + rules_tail="$rules_string"; + + while [ -n "$rules_tail" ]; do + head="${rules_tail%%||*}" + + if [ "$head" = "$rules_tail" ]; then + rules_string="" + else + rules_tail="${rules_tail#*||}" + fi + + #if [ -z "$head" ] || [ -n "$(echo "$head" | grep -E -x '[ \t]*')" ]; then + #group=$(( $group + 1 )) + #continue + #fi + + rules="$(resolve_rules "$head")" + + # If specified rule cannot be recognised - end with error + if [ $? -eq 1 ]; then + exit 1 + fi + + if ! echo "$ver" | grep -q -E -x "[v=]?[ \t]*$RE_VER"; then + continue + fi + + ver=$(echo "$ver" | grep -E -x "$RE_VER") + + success=true + allow_prerel=false + if $FORCE_ALLOW_PREREL; then + allow_prerel=true + fi + + while read -r rule; do + comparator="${rule%% *}" + operand="${rule#* }" + + if [ -n "$(get_prerelease "$operand")" ] && semver_eq "$(get_number "$operand")" "$(get_number "$ver")" || [ "$rule" = "all" ]; then + allow_prerel=true + fi + + "rule_$comparator" "$operand" "$ver" + if [ $? -eq 1 ]; then + success=false + break + fi + done <<< "$rules" + + if $success; then + if [ -z "$(get_prerelease "$ver")" ] || $allow_prerel; then + echo "$ver" + break; + fi + fi + done + + group=$(( group + 1 )) + done +} + + + +FORCE_ALLOW_PREREL=false +USAGE="Usage: $0 [-r ] [... ] + +Omitting s reads them from STDIN. +Omitting -r simply sorts the versions according to semver ordering." + +while getopts ar:h o; do + case "$o" in + a) FORCE_ALLOW_PREREL=true ;; + r) RULES_STRING="$OPTARG||";; + h) echo "$USAGE" && exit ;; + ?) echo "$USAGE" && exit 1;; + esac +done + +shift $(( OPTIND-1 )) + +VERSIONS=( ${@:-$(cat -)} ) + +# Sort versions +VERSIONS=( $(semver_sort "${VERSIONS[@]}") ) + +if [ -z "$RULES_STRING" ]; then + printf '%s\n' "${VERSIONS[@]}" +else + apply_rules "$RULES_STRING" "${VERSIONS[@]}" +fi diff --git a/scripts/umbrel-os/services/umbrel-external-storage.service b/scripts/umbrel-os/services/umbrel-external-storage.service index 8e27560..164b18a 100644 --- a/scripts/umbrel-os/services/umbrel-external-storage.service +++ b/scripts/umbrel-os/services/umbrel-external-storage.service @@ -8,6 +8,8 @@ Description=External Storage Mounter Type=oneshot Restart=no ExecStart=/home/umbrel/umbrel/scripts/umbrel-os/external-storage/mount +ExecStartPost=/home/umbrel/umbrel/scripts/umbrel-os/external-storage/update-from-sdcard +TimeoutStartSec=45min User=root Group=root StandardOutput=syslog diff --git a/scripts/update/00-run.sh b/scripts/update/00-run.sh index 23698bd..13e76ea 100755 --- a/scripts/update/00-run.sh +++ b/scripts/update/00-run.sh @@ -6,7 +6,7 @@ UMBREL_ROOT=$2 echo echo "=======================================" -echo "============= OTA UPDATE ==============" +echo "=============== UPDATE ================" echo "=======================================" echo "========= Stage: Pre-update ===========" echo "=======================================" diff --git a/scripts/update/01-run.sh b/scripts/update/01-run.sh index 5b0617b..5e127ea 100755 --- a/scripts/update/01-run.sh +++ b/scripts/update/01-run.sh @@ -9,7 +9,7 @@ SD_CARD_UMBREL_ROOT="/sd-root${UMBREL_ROOT}" echo echo "=======================================" -echo "============= OTA UPDATE ==============" +echo "=============== UPDATE ================" echo "=======================================" echo "=========== Stage: Install ============" echo "=======================================" diff --git a/scripts/update/02-run.sh b/scripts/update/02-run.sh index e5c75f6..d143901 100755 --- a/scripts/update/02-run.sh +++ b/scripts/update/02-run.sh @@ -6,7 +6,7 @@ UMBREL_ROOT=$2 echo echo "=======================================" -echo "============= OTA UPDATE ==============" +echo "=============== UPDATE ================" echo "=======================================" echo "========= Stage: Post-update ==========" echo "=======================================" diff --git a/scripts/update/03-run.sh b/scripts/update/03-run.sh index 89db1d9..2f773fc 100755 --- a/scripts/update/03-run.sh +++ b/scripts/update/03-run.sh @@ -6,7 +6,7 @@ UMBREL_ROOT=$2 echo echo "=======================================" -echo "============= OTA UPDATE ==============" +echo "=============== UPDATE ================" echo "=======================================" echo "=========== Stage: Success ============" echo "=======================================" diff --git a/scripts/update/update b/scripts/update/update new file mode 100755 index 0000000..bdd9050 --- /dev/null +++ b/scripts/update/update @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +if [[ $UID != 0 ]]; then + echo "Update script must be run as root" + exit 1 +fi + +check_dependencies () { + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "This script requires \"${cmd}\" to be installed" + exit 1 + fi + done +} + +check_dependencies jq wget git rsync + +UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)" + +update_type="" +if [[ "${1}" == "--ota" ]]; then + update_type="ota" +elif [[ "${1}" == "--path" ]]; then + update_type="path" + update_path="${2}" +else + echo "Update requires \"--ota\" or \"--path \" option." + exit 1 +fi + +if [[ "${update_type}" == "path" ]] && [[ ! -f "${update_path}/.umbrel" ]]; then + echo "Update path doesn't seem to be an Umbrel install." + exit 1 +fi + +if [[ "${update_type}" == "ota" ]]; then + RELEASE=$(cat "$UMBREL_ROOT"/statuses/update-status.json | jq .updateTo -r) +elif [[ "${update_type}" == "path" ]]; then + RELEASE=$(cat "$update_path"/info.json | jq .version -r) +fi + +echo +echo "=======================================" +echo "=============== UPDATE ================" +echo "=======================================" +echo "========== Stage: Download ============" +echo "=======================================" +echo + +# Make sure an update is not in progres +if [[ -f "$UMBREL_ROOT/statuses/update-in-progress" ]]; then + echo "An update is already in progress. Exiting now." + exit 2 +fi + +echo "Creating lock" +touch "$UMBREL_ROOT"/statuses/update-in-progress + +# Cleanup just in case there's temp stuff lying around from previous update +echo "Cleaning up any previous mess" +[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE" + +# Update status file +cat < "$UMBREL_ROOT"/statuses/update-status.json +{"state": "installing", "progress": 10, "description": "Downloading Umbrel $RELEASE", "updateTo": "$RELEASE"} +EOF + +# Download new release +if [[ "${update_type}" == "ota" ]]; then + echo "Downloading Umbrel ${RELEASE}" + mkdir -p "${UMBREL_ROOT}/.umbrel-${RELEASE}" + cd "${UMBREL_ROOT}/.umbrel-${RELEASE}" + curl -L "https://github.com/getumbrel/umbrel/archive/$RELEASE.tar.gz" | tar -xz --strip-components=1 +fi + +# Copy over new release from path +if [[ "${update_type}" == "path" ]]; then + echo "Copying Umbrel ${RELEASE} from ${update_path}" + mkdir -p "${UMBREL_ROOT}/.umbrel-${RELEASE}" + cp --recursive \ + --archive \ + --no-target-directory \ + "${update_path}" "${UMBREL_ROOT}/.umbrel-${RELEASE}" + cd "${UMBREL_ROOT}/.umbrel-${RELEASE}" +fi + +# Run update scripts +echo "Running update install scripts of the new release" +cd scripts/update +UPDATE_INSTALL_SCRIPTS=$(ls *-run.sh) +for script in $UPDATE_INSTALL_SCRIPTS; do + if [[ -x $script ]]; then + echo + echo "== Begin Update Script $script ==" + ./"$script" "$RELEASE" "$UMBREL_ROOT" + echo "== End Update Script $script ==" + echo + fi +done + +# Delete cloned repo +echo "Deleting cloned repository" +[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE" + +echo "Removing lock" +rm -f "$UMBREL_ROOT"/statuses/update-in-progress + +exit 0