#!/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 curl 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}" elif [[ "${1}" == "--repo" ]]; then update_type="repo" descriptor="${2}" if [[ "${descriptor}" != *"#"* ]]; then descriptor="${descriptor}#master" fi repo="${descriptor%%#*}" branch="${descriptor#*#}" else echo "Update requires \"--ota\", \"--path \", or \"--repo user/repo[#branch]\" option." exit 1 fi if [[ "${update_type}" == "repo" ]]; then repo_path="/tmp/umbrel-update/" rm -rf "${repo_path}" 2> /dev/null || true mkdir -p "${repo_path}" git clone --single-branch --branch "${branch}" "https://github.com/${repo}.git" "${repo_path}" # Patch version to show development build commit=$(git --git-dir "${repo_path}/.git" rev-parse --short HEAD) mv "${repo_path}/info.json" "${repo_path}/info.json.orig" jq \ --arg commit "${commit}" \ '.build = $commit' \ "${repo_path}/info.json.orig" \ > "${repo_path}/info.json" # Now hand over to the path updater update_type="path" update_path="${repo_path}" 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 # Make sure the update-status file isn't stuck in an # unresolved state (i.e anything except "success" or "failed") update_state=$(cat "${UMBREL_ROOT}/statuses/update-status.json" | jq .state -r) # Show error update_failure_status_file="${UMBREL_ROOT}/statuses/update-failure" if [[ -f "${update_failure_status_file}" ]]; then reason=$(cat "${update_failure_status_file}") rm "${update_failure_status_file}" cat < "${UMBREL_ROOT}/statuses/update-status.json" {"state": "failed", "progress": 100, "description": "${reason}", "updateTo": ""} EOF fi if [[ "${update_state}" != "success" ]] && [[ "${update_state}" != "failed" ]]; then # Sleep for a few seconds to make sure the user is on the update view sleep 8 cat < "${UMBREL_ROOT}/statuses/update-status.json" {"state": "failed", "progress": 100, "description": "An unexpected error occured", "updateTo": ""} EOF fi exit 0