devtools/src/lib/version/upgrade.sh

245 lines
6.3 KiB
Bash

#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
[[ -z ${DEVTOOLS_INCLUDE_VERSION_UPGRADE_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_VERSION_UPGRADE_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/version/check.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/check.sh
# shellcheck source=src/lib/util/pkgbuild.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/pkgbuild.sh
# shellcheck source=src/lib/util/term.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/term.sh
source /usr/share/makepkg/util/message.sh
set -e
pkgctl_version_upgrade_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS] [PKGBASE]...
Upgrade the PKGBUILD according to the latest available upstream version
Uses nvchecker, a .nvchecker.toml file and the current PKGBUILD
pkgver to check if there is a newer package version available.
The current working directory is used if no PKGBASE is specified.
OPTIONS
-v, --verbose Display results including up-to-date versions
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} neovim vim
_EOF_
}
pkgctl_version_upgrade() {
local path upstream_version result
local pkgbases=()
local verbose=0
local exit_code=0
local current_item=0
while (( $# )); do
case $1 in
-h|--help)
pkgctl_version_upgrade_usage
exit 0
;;
-v|--verbose)
verbose=1
shift
;;
--)
shift
break
;;
-*)
die "invalid argument: %s" "$1"
;;
*)
pkgbases=("$@")
break
;;
esac
done
if ! command -v nvchecker &>/dev/null; then
die "The \"$_DEVTOOLS_COMMAND\" command requires 'nvchecker'"
fi
# Check if used without pkgbases in a packaging directory
if (( ${#pkgbases[@]} == 0 )); then
if [[ -f PKGBUILD ]]; then
pkgbases=(".")
else
pkgctl_version_upgrade_usage
exit 1
fi
fi
# enable verbose mode when we only have a single item to check
if (( ${#pkgbases[@]} == 1 )); then
verbose=1
fi
# start a terminal spinner as checking versions takes time
status_dir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-version-check-spinner.XXXXXXXXXX)
term_spinner_start "${status_dir}"
for path in "${pkgbases[@]}"; do
pushd "${path}" >/dev/null
if [[ ! -f "PKGBUILD" ]]; then
die "No PKGBUILD found for ${path}"
fi
# update the current terminal spinner status
(( ++current_item ))
pkgctl_version_upgrade_spinner \
"${status_dir}" \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}" \
"${current_item}" \
"${#pkgbases[@]}"
# reset common PKGBUILD variables
unset pkgbase pkgname arch source pkgver pkgrel validpgpkeys
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. ./PKGBUILD
pkgbase=${pkgbase:-$pkgname}
if ! result=$(get_upstream_version); then
result="${BOLD}${pkgbase}${ALL_OFF}: ${result}"
failure+=("${result}")
popd >/dev/null
continue
fi
upstream_version=${result}
if ! result=$(vercmp "${upstream_version}" "${pkgver}"); then
result="${BOLD}${pkgbase}${ALL_OFF}: failed to compare version ${upstream_version} against ${pkgver}"
failure+=("${result}")
popd >/dev/null
continue
fi
if (( result == 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is latest"
up_to_date+=("${result}")
elif (( result < 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is never than ${DARK_GREEN}${upstream_version}${ALL_OFF}"
up_to_date+=("${result}")
elif (( result > 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: upgraded from version ${PURPLE}${pkgver}${ALL_OFF} to ${DARK_GREEN}${upstream_version}${ALL_OFF}"
out_of_date+=("${result}")
# change the PKGBUILD
pkgbuild_set_pkgver "${upstream_version}"
pkgbuild_set_pkgrel 1
fi
popd >/dev/null
done
# stop the terminal spinner after all checks
term_spinner_stop "${status_dir}"
if (( verbose )) && (( ${#up_to_date[@]} > 0 )); then
printf "%sUp-to-date%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${up_to_date[@]}"; do
msg_success " ${result}"
done
fi
if (( ${#failure[@]} > 0 )); then
exit_code=1
printf "%sFailure%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${failure[@]}"; do
msg_error " ${result}"
done
fi
if (( ${#out_of_date[@]} > 0 )); then
printf "%sUpgraded%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${out_of_date[@]}"; do
msg_warn " ${result}"
done
fi
# Show summary when processing multiple packages
if (( ${#pkgbases[@]} > 1 )); then
printf '%s' "${section_separator}"
pkgctl_version_upgrade_summary \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}"
fi
# return status based on results
return "${exit_code}"
}
pkgctl_version_upgrade_summary() {
local up_to_date_count=$1
local out_of_date_count=$2
local failure_count=$3
# print nothing if all stats are zero
if (( up_to_date_count == 0 )) && \
(( out_of_date_count == 0 )) && \
(( failure_count == 0 )); then
return 0
fi
# print summary for all none zero stats
printf "%sSummary%s\n" "${BOLD}${UNDERLINE}" "${ALL_OFF}"
if (( up_to_date_count > 0 )); then
msg_success " Up-to-date: ${BOLD}${up_to_date_count}${ALL_OFF}" 2>&1
fi
if (( failure_count > 0 )); then
msg_error " Failure: ${BOLD}${failure_count}${ALL_OFF}" 2>&1
fi
if (( out_of_date_count > 0 )); then
msg_warn " Upgraded: ${BOLD}${out_of_date_count}${ALL_OFF}" 2>&1
fi
}
pkgctl_version_upgrade_spinner() {
local status_dir=$1
local up_to_date_count=$2
local out_of_date_count=$3
local failure_count=$4
local current=$5
local total=$6
local percentage=$(( 100 * current / total ))
local tmp_file="${status_dir}/tmp"
local status_file="${status_dir}/status"
# print the current summary
pkgctl_version_upgrade_summary \
"${up_to_date_count}" \
"${out_of_date_count}" \
"${failure_count}" > "${tmp_file}"
# print the progress status
printf "📡 Upgrading: %s/%s [%s] %%spinner%%" \
"${BOLD}${current}" "${total}" "${percentage}%${ALL_OFF}" \
>> "${tmp_file}"
# swap the status file
mv "${tmp_file}" "${status_file}"
}