From bd995804513adf9b275d6144966cf844009a5253 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Thu, 17 Mar 2022 09:53:28 +0530 Subject: [PATCH 01/19] refactor(update-packages): new auto-update system Signed-off-by: Aditya Alok --- scripts/bin/update-packages | 264 +++++++++++++++++++++++------------- 1 file changed, 169 insertions(+), 95 deletions(-) diff --git a/scripts/bin/update-packages b/scripts/bin/update-packages index 417498a00..831d6048f 100755 --- a/scripts/bin/update-packages +++ b/scripts/bin/update-packages @@ -1,8 +1,8 @@ #!/usr/bin/env bash -set -e -u -BASEDIR=$(dirname "$(realpath "$0")") +# shellcheck source-path=/data/data/com.termux/files/home/termux-packages +set -u -# These variables should be set in environment outside of this script. +# Following variables should be set in environment outside of this script. # Build updated packages. : "${BUILD_PACKAGES:=false}" # Commit changes to Git. @@ -10,110 +10,184 @@ BASEDIR=$(dirname "$(realpath "$0")") # Push changes to remote. : "${GIT_PUSH_PACKAGES:=false}" -if [ -z "${GITHUB_API_TOKEN-}" ]; then - echo "Error: you need a Github Personal Access Token be set in variable GITHUB_API_TOKEN." - exit 1 -fi +export TERMUX_PKG_UPDATE_METHOD="" # Which method to use for updating? (repology, github or gitlab) +export TERMUX_PKG_UPDATE_TAG_TYPE="" # Whether to use latest-release-tag or newest-tag. +export TERMUX_GITLAB_API_HOST="gitlab.com" # Default host for gitlab-ci. +export TERMUX_PKG_AUTO_UPDATE=true # Whether to auto-update or not. +export TERMUX_PKG_UPDATE_VERSION_REGEXP="" # Regexp to extract version. +export TERMUX_REPOLOGY_DATA_FILE +TERMUX_REPOLOGY_DATA_FILE="$(mktemp -t termux-repology.XXXXXX)" # File to store repology data. -for pkg_dir in "${BASEDIR}"/../../packages/*; do - if [ -f "${pkg_dir}/build.sh" ]; then - package=$(basename "$pkg_dir") - else - # Fail if detected a non-package directory. - echo "Error: directory '${pkg_dir}' is not a package." - exit 1 - fi +export TERMUX_SCRIPTDIR +TERMUX_SCRIPTDIR="$(realpath "$(dirname "$0")/../..")" # Script directory. - # Extract the package auto-update configuration. - build_vars=$( - set +e +u - . "${BASEDIR}/../../packages/${package}/build.sh" 2>/dev/null - echo "auto_update_flag=${TERMUX_PKG_AUTO_UPDATE};" - echo "termux_version=\"${TERMUX_PKG_VERSION}\";" - echo "srcurl=\"${TERMUX_PKG_SRCURL}\";" - echo "version_regexp=\"${TERMUX_PKG_AUTO_UPDATE_TAG_REGEXP//\\/\\\\}\";" - ) - auto_update_flag=""; termux_version=""; srcurl=""; version_regexp=""; - eval "$build_vars" +# Define few more variables used by scripts. +# shellcheck source=scripts/properties.sh +. "${TERMUX_SCRIPTDIR}/scripts/properties.sh" - # Ignore packages that have auto-update disabled. - if [ "${auto_update_flag}" != "true" ]; then - continue - fi +# Utility function to write error message to stderr. +# shellcheck source=scripts/updates/utils/termux_error_exit.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_error_exit.sh - # Extract github project from TERMUX_PKG_SRCURL - project="$(echo "${srcurl}" | grep github.com | cut -d / -f4-5)" - if [ -z "${project}" ]; then - echo "Error: package '${package}' doesn't use GitHub archive source URL but has been configured for automatic updates." - exit 1 - fi +# Utility function to write updated version to build.sh. +# shellcheck source=scripts/updates/utils/termux_pkg_upgrade_version.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_pkg_upgrade_version.sh - # Our local version of package. - termux_epoch="$(echo "$termux_version" | cut -d: -f1)" - termux_version=$(echo "$termux_version" | cut -d: -f2-) - if [ "$termux_version" == "$termux_epoch" ]; then - # No epoch set. - termux_epoch="" - else - termux_epoch+=":" - fi +# Utility function to check if package needs to be updated, based on version comparison. +# shellcheck source=scripts/updates/utils/termux_pkg_is_update_needed.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_pkg_is_update_needed.sh - # Get the latest release tag. - latest_tag=$(curl --silent --location -H "Authorization: token ${GITHUB_API_TOKEN}" "https://api.github.com/repos/${project}/releases/latest" | jq -r .tag_name) +# Wrapper around github api to get latest release or newest tag. +# shellcheck source=scripts/updates/api/termux_github_api_get_tag.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_github_api_get_tag.sh - # If the github api returns error - if [ -z "$latest_tag" ] || [ "${latest_tag}" = "null" ]; then - echo "Error: failed to get the latest release tag for '${package}'. GitHub API returned 'null' which indicates that no releases available." - exit 1 - fi +# Wrapper around gitlab api to get latest release or newest tag. +# shellcheck source=scripts/updates/api/termux_gitlab_api_get_tag.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_gitlab_api_get_tag.sh - # Remove leading 'v' which is common in version tag. - latest_version=${latest_tag#v} +# Function to get latest version of a package as per repology. +# shellcheck source=scripts/updates/api/termux_repology_api_get_latest_version.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_repology_api_get_latest_version.sh - # If needed, filter version numbers from tag by using regexp. - if [ -n "$version_regexp" ]; then - latest_version=$(grep -oP "$version_regexp" <<< "$latest_version" || true) - fi - if [ -z "$latest_version" ]; then - echo "Error: failed to get latest version for '${package}'. Check whether the TERMUX_PKG_AUTO_UPDATE_TAG_REGEXP='${version_regexp}' is work right with latest_release='${latest_tag}'." - exit 1 - fi +# Default auto update script for packages hosted on github.com. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_github_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_github_auto_update.sh - # Translate "_" into ".": some packages use underscores to seperate - # version numbers, but we require them to be separated by dots. - latest_version=${latest_version//_/.} +# Default auto update script for packages hosted on hosts using gitlab-ci. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_gitlab_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_gitlab_auto_update.sh - # We have no better choice for comparing versions. - if [ "$(echo -e "${termux_version}\n${latest_version}" | sort -V | head -n 1)" != "$latest_version" ] ;then - if [ "$BUILD_PACKAGES" = "false" ]; then - echo "Package '${package}' needs update to '${latest_version}'." - else - echo "Updating '${package}' to '${latest_version}'." - sed -i "s/^\(TERMUX_PKG_VERSION=\)\(.*\)\$/\1${termux_epoch}${latest_version}/g" "${BASEDIR}/../../packages/${package}/build.sh" - sed -i "/TERMUX_PKG_REVISION=/d" "${BASEDIR}/../../packages/${package}/build.sh" - echo n | "${BASEDIR}/../bin/update-checksum" "$package" || { - echo "Warning: failed to update checksum for '${package}', skipping..." - git checkout -- "${BASEDIR}/../../packages/${package}" - git pull --rebase - continue - } +# Default auto update script for packages. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_repology_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_repology_auto_update.sh - echo "Trying to build package '${package}'." - if "${BASEDIR}/../run-docker.sh" ./build-package.sh -a aarch64 -I "$package" && \ - "${BASEDIR}/../run-docker.sh" ./build-package.sh -a arm -I "$package"; then - if [ "$GIT_COMMIT_PACKAGES" = "true" ]; then - git add "${BASEDIR}/../../packages/${package}" - git commit -m "$(echo -e "${package}: update to ${latest_version}\n\nThis commit has been automatically submitted by Github Actions.")" - fi +# Main script to: +# - by default, decide which update method to use, +# - but can be overrided by build.sh to use custom update method. +# - For example: see neovim-nightly's build.sh. +# shellcheck source=scripts/updates/termux_pkg_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/termux_pkg_auto_update.sh - if [ "$GIT_PUSH_PACKAGES" = "true" ]; then - git pull --rebase - git push - fi - else - echo "Warning: failed to build '${package}'." - git checkout -- "${BASEDIR}/../../packages/${package}" - fi +_update() { + export TERMUX_PKG_NAME + TERMUX_PKG_NAME="$(basename "$1")" + # Avoid: + # - ending on errors such as $(which prog), where prog is not installed. + # - error on unbound variable. + # + # Variables used by auto update script should be covered by above variables and properties.sh. + set +e +u + # shellcheck source=/dev/null + . "${pkg_dir}"/build.sh 2>/dev/null + set -e -u + + IFS="," read -r -a BLACKLISTED_ARCH <<<"${TERMUX_PKG_BLACKLISTED_ARCHES:-}" + export TERMUX_ARCH="" # Arch to test updates. + for arch in aarch64 arm i686 x86_64; do + # shellcheck disable=SC2076 + if [[ ! " ${BLACKLISTED_ARCH[*]} " =~ " ${arch} " ]]; then + TERMUX_ARCH="${arch}" + break fi + done + + echo # Newline. + echo "INFO: Updating ${TERMUX_PKG_NAME}..." + # Only update if auto update is enabled. + if [[ "${TERMUX_PKG_AUTO_UPDATE}" == "true" ]]; then + echo "INFO: Current version: ${TERMUX_PKG_VERSION}" + termux_pkg_auto_update + echo # Newline. + else + echo "INFO: Skipping update. Auto update is disabled." fi -done +} + +_test_pkg_build_file() { + local pkg_dir + pkg_dir="$1" + if [[ ! -f "${pkg_dir}/build.sh" ]]; then + # Fail if detected a non-package directory. + termux_error_exit "ERROR: directory '${pkg_dir}' is not a package." + fi +} + +declare -a _failed_updates=() + +_run_update() { + local pkg_dir="$1" + _test_pkg_build_file "${pkg_dir}" + # Run each package update in separate process since we include their environment variables. + ( + set -euo pipefail + _update "${pkg_dir}" + ) + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]]; then + _failed_updates+=("$(basename "${pkg_dir}")") + fi +} + +_get_unique_packages() { + local -a unique_packages=() + + while read -r pkg; do + unique_packages+=("${pkg}") + done < <(curl --silent --location --retry 5 --retry-delay 5 --retry-max-time 60 \ + "https://repology.org/api/v1/projects/?inrepo=termux&&repos=1" | + jq -r keys) + + echo "${unique_packages[@]}" +} + +declare -a _unique_packages +read -r -a _unique_packages <<<"$(_get_unique_packages)" + +_unique_to_termux() { + local pkg_dir="$1" + if [[ "${_unique_packages[*]}" =~ "$(basename "${pkg_dir}")" ]]; then + return 0 + else + return 1 + fi +} + +main() { + echo "INFO: Running update for: $*" + + if [[ "$1" == "@all" ]]; then + for pkg_dir in "${TERMUX_SCRIPTDIR}"/packages/*; do + # Skip update if package is unique to Termux. + if _unique_to_termux "${pkg_dir}"; then + echo # Newline. + echo "INFO: Skipping update for unique to Termux package: $(basename "${pkg_dir}")" + continue + fi + _run_update "${pkg_dir}" + done + else + for pkg in "$@"; do + # Skip update if package is unique to Termux. + if _unique_to_termux "${TERMUX_SCRIPTDIR}"/packages/"${pkg}"; then + echo # Newline. + echo "INFO: Skipping update for unique to Termux package: ${pkg}" + continue + fi + _run_update "${TERMUX_SCRIPTDIR}/packages/${pkg}" + done + fi + + if ((${#_failed_updates[@]} > 0)); then + echo # Newline. + echo "===========================Failed updates===========================" + for failed_update in "${_failed_updates[@]}"; do + echo "==> ${failed_update}" + done + exit 1 # Exit with error code, so that we know that some/all updates failed. + fi +} + +main "$@" From 5377dbc8b874fba2d86b172ab812c81c10f24eef Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 12:42:40 +0530 Subject: [PATCH 02/19] ci(package_updates.yml): adhere to new update system Signed-off-by: Aditya Alok --- .github/workflows/package_updates.yml | 42 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/.github/workflows/package_updates.yml b/.github/workflows/package_updates.yml index 6463e59c7..139150427 100644 --- a/.github/workflows/package_updates.yml +++ b/.github/workflows/package_updates.yml @@ -2,26 +2,36 @@ name: Package updates on: schedule: - - cron: '0 */6 * * *' + - cron: "0 */6 * * *" workflow_dispatch: + inputs: + packages: + description: "A space-seperated list of packages to update. Defaults to all packages" + default: "@all" + required: false jobs: update-packages: if: github.repository == 'termux/termux-packages' runs-on: ubuntu-latest steps: - - name: Clone repository - uses: actions/checkout@v2 - with: - fetch-depth: 0 - token: ${{ secrets.GH_API_KEY }} - - name: Process package updates - env: - GITHUB_API_TOKEN: ${{ secrets.GH_API_KEY }} - BUILD_PACKAGES: "true" - GIT_COMMIT_PACKAGES: "true" - GIT_PUSH_PACKAGES: "true" - run: | - git config --global user.name "Termux Github Actions" - git config --global user.email "contact@termux.org" - bash ./scripts/bin/update-packages + - name: Clone repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + token: ${{ secrets.GH_API_KEY }} + - name: Process package updates + env: + GITHUB_TOKEN: ${{ secrets.GH_API_KEY }} + BUILD_PACKAGES: "true" + GIT_COMMIT_PACKAGES: "true" + GIT_PUSH_PACKAGES: "true" + run: | + git config --global user.name "Termux Github Actions" + git config --global user.email "contact@termux.com" + + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + ./scripts/bin/update-packages ${{ github.event.inputs.packages }} + else + ./scripts/bin/update-packages "@all" + fi From b089c6182b2b573d0f6772cf19bd4b99dcc3bc39 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 12:44:37 +0530 Subject: [PATCH 03/19] feat(auto update): add script to decide update method - hook to be called when auto updating. - it may be overridden by build.sh Signed-off-by: Aditya Alok --- scripts/updates/termux_pkg_auto_update.sh | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 scripts/updates/termux_pkg_auto_update.sh diff --git a/scripts/updates/termux_pkg_auto_update.sh b/scripts/updates/termux_pkg_auto_update.sh new file mode 100644 index 000000000..835da8587 --- /dev/null +++ b/scripts/updates/termux_pkg_auto_update.sh @@ -0,0 +1,44 @@ +# shellcheck shell=bash +termux_pkg_auto_update() { + local project_host + project_host="$(echo "${TERMUX_PKG_SRCURL}" | cut -d"/" -f3)" + + if [[ -z "${TERMUX_PKG_UPDATE_METHOD}" ]]; then + if [[ "${project_host}" == "github.com" ]]; then + TERMUX_PKG_UPDATE_METHOD="github" + elif [[ "${project_host}" == "gitlab.com" ]]; then + TERMUX_PKG_UPDATE_METHOD="gitlab" + else + TERMUX_PKG_UPDATE_METHOD="repology" + fi + fi + + local _err_msg="ERROR: source url's hostname is not ${TERMUX_PKG_UPDATE_METHOD}.com, but has been +configured to use ${TERMUX_PKG_UPDATE_METHOD}'s method." + + case "${TERMUX_PKG_UPDATE_METHOD}" in + github) + if [[ "${project_host}" != "${TERMUX_PKG_UPDATE_METHOD}.com" ]]; then + termux_error_exit "${_err_msg}" + else + termux_github_auto_update + fi + ;; + gitlab) + if [[ "${project_host}" != "${TERMUX_PKG_UPDATE_METHOD}.com" ]]; then + termux_error_exit "${_err_msg}" + else + termux_gitlab_auto_update + fi + ;; + repology) + termux_repology_auto_update + ;; + *) + termux_error_exit <<-EndOfError + ERROR: wrong value '${TERMUX_PKG_UPDATE_METHOD}' for TERMUX_PKG_UPDATE_METHOD. + Can be 'github', 'gitlab' or 'repology' + EndOfError + ;; + esac +} From e1d6ab87f6136e7240065329ed7cedc0595d862b Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 12:47:54 +0530 Subject: [PATCH 04/19] feat(auto update): add utility function to exit on error Signed-off-by: Aditya Alok --- scripts/updates/utils/termux_error_exit.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 scripts/updates/utils/termux_error_exit.sh diff --git a/scripts/updates/utils/termux_error_exit.sh b/scripts/updates/utils/termux_error_exit.sh new file mode 100644 index 000000000..28425b6cc --- /dev/null +++ b/scripts/updates/utils/termux_error_exit.sh @@ -0,0 +1,10 @@ +# shellcheck shell=bash +termux_error_exit() { + if [ "$#" -eq 0 ]; then + # Read from stdin. + printf '%s\n' "$(cat)" >&2 + else + printf '%s\n' "$*" >&2 + fi + exit 1 +} From 2e093339b24c5b68c80e1cf23d6431de1e1e9b47 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 12:48:39 +0530 Subject: [PATCH 05/19] feat(auto update): add utility function to upgrade package's version Signed-off-by: Aditya Alok --- .../utils/termux_pkg_upgrade_version.sh | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 scripts/updates/utils/termux_pkg_upgrade_version.sh diff --git a/scripts/updates/utils/termux_pkg_upgrade_version.sh b/scripts/updates/utils/termux_pkg_upgrade_version.sh new file mode 100755 index 000000000..7273eeb39 --- /dev/null +++ b/scripts/updates/utils/termux_pkg_upgrade_version.sh @@ -0,0 +1,80 @@ +# shellcheck shell=bash +termux_pkg_upgrade_version() { + if [[ "$#" -lt 1 ]]; then + # Show usage. + termux_error_exit <<-EndUsage + Usage: ${FUNCNAME[0]} LATEST_VERSION [--skip-version-check] + Version should be passed with epoch, if any. + EndUsage + fi + + local LATEST_VERSION="$1" + local SKIP_VERSION_CHECK="${2:-}" + local PKG_DIR + PKG_DIR="${TERMUX_SCRIPTDIR}/packages/${TERMUX_PKG_NAME}" + + if [[ "${SKIP_VERSION_CHECK}" != "--skip-version-check" ]]; then + if ! termux_pkg_is_update_needed \ + "${TERMUX_PKG_VERSION}" "${LATEST_VERSION}" "${TERMUX_PKG_UPDATE_VERSION_REGEXP}"; then + echo "INFO: No update needed. Already at version '${TERMUX_PKG_VERSION}'." + return 0 + fi + fi + + if [[ "${BUILD_PACKAGES}" == "false" ]]; then + echo "INFO: package needs to be updated to $(echo "${LATEST_VERSION}" | cut -d':' -f2)." + else + echo "INFO: package being updated to $(echo "${LATEST_VERSION}" | cut -d':' -f2)." + + sed -i \ + "s/^\(TERMUX_PKG_VERSION=\)\(.*\)\$/\1${LATEST_VERSION}/g" \ + "${PKG_DIR}/build.sh" + sed -i \ + "/TERMUX_PKG_REVISION=/d" \ + "${PKG_DIR}/build.sh" + + # Update checksum + if [[ "${TERMUX_PKG_SHA256[*]}" != "SKIP_CHECKSUM" ]] && [[ "${TERMUX_PKG_SRCURL: -4}" != ".git" ]]; then + echo n | "${TERMUX_SCRIPTDIR}/scripts/bin/update-checksum" "${TERMUX_PKG_NAME}" || { + git checkout -- "${PKG_DIR}" + git pull --rebase + termux_error_exit "ERROR: failed to update checksum." + } + fi + + echo "INFO: Trying to build package." + if "${TERMUX_SCRIPTDIR}/scripts/run-docker.sh" ./build-package.sh -a "${TERMUX_ARCH}" -I "${TERMUX_PKG_NAME}"; then + if [[ "${GIT_COMMIT_PACKAGES}" == "true" ]]; then + echo "INFO: Committing package." + stderr="$( + git add "${PKG_DIR}" 2>&1 >/dev/null + git commit -m "${TERMUX_PKG_NAME}: update to $(echo "${LATEST_VERSION}" | cut -d':' -f2)" \ + -m "This commit has been automatically submitted by Github Actions." 2>&1 >/dev/null + )" || { + termux_error_exit <<-EndOfError + ERROR: git commit failed. See below for details. + ${stderr} + EndOfError + } + fi + + if [[ "${GIT_PUSH_PACKAGES}" == "true" ]]; then + echo "INFO: Pushing package." + stderr="$( + git status # DEBUG + git pull --rebase 2>&1 >/dev/null + git push 2>&1 >/dev/null + )" || { + termux_error_exit <<-EndOfError + ERROR: git push failed. See below for details. + ${stderr} + EndOfError + } + fi + else + git checkout -- "${PKG_DIR}" + termux_error_exit "ERROR: failed to build." + fi + + fi +} From 03cc6b6ce8704ab00d5a278a2c362639bcf310b2 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 12:49:11 +0530 Subject: [PATCH 06/19] feat(auto update): add utility function to check if update is needed - compare current and latest version retrived from respective api Signed-off-by: Aditya Alok --- .../utils/termux_pkg_is_update_needed.sh | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100755 scripts/updates/utils/termux_pkg_is_update_needed.sh diff --git a/scripts/updates/utils/termux_pkg_is_update_needed.sh b/scripts/updates/utils/termux_pkg_is_update_needed.sh new file mode 100755 index 000000000..21def6704 --- /dev/null +++ b/scripts/updates/utils/termux_pkg_is_update_needed.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# NOTE: This function returns true even when CURRENT_VERSION = "1.0" and LATEST_VERSION = "1.0-1". +# This is logically correct, but repology sometimes returns "1.0-1" as the latest version even +# if "1.0" is latest. This happens when any of the repositories tracked by repology has specified +# "1.0-1" as the latest. +# +# For example: +# latest lua:lpeg version (as of 2021-11-20T12:21:31) is "1.0.2" but MacPorts specifies as "1.0.2-1". +# Hence repology returns "1.0.2-1" as the latest. +# +# But hopefully, all this can be avoided if TERMUX_PKG_AUTO_UPDATE_TAG_REGEXP is set. +# +termux_pkg_is_update_needed() { + if [[ "$#" -lt 2 ]] || [[ "$#" -gt 3 ]]; then + termux_error_exit <<-EndOfUsage + Usage: ${FUNCNAME[0]} [version-regexp] + Returns: 0 if update is needed, 1 if not. + EndOfUsage + fi + + local CURRENT_VERSION="$1" + local LATEST_VERSION="$2" + local VERSION_REGEX="${3:-}" + + # If needed, filter version numbers from tag by using regexp. + if [[ -n "${VERSION_REGEX}" ]]; then + LATEST_VERSION="$(grep -oP "${VERSION_REGEX}" <<<"${LATEST_VERSION}" || true)" + fi + + if [[ -z "${LATEST_VERSION}" ]]; then + termux_error_exit <<-EndOfError + ERROR: failed to check latest version. Ensure whether the version regex '${VERSION_REGEX}' + works correctly with latest release tag. + EndOfError + fi + + # Translate "_" into ".": some packages use underscores to seperate + # version numbers, but we require them to be separated by dots. + LATEST_VERSION="${LATEST_VERSION//_/.}" + + # Compare versions. + # shellcheck disable=SC2091 + if $( + cat <<-EOF | python3 - + import sys + + from pkg_resources import parse_version + + if parse_version("${CURRENT_VERSION}") < parse_version("${LATEST_VERSION}"): + sys.exit(0) + else: + sys.exit(1) + EOF + ); then + return 0 # true. Update needed. + fi + return 1 # false. Update not needed. +} + +# Make script sourceable as well as executable. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + declare -f termux_error_exit >/dev/null || . "$(dirname "${BASH_SOURCE[0]}")/termux_error_exit.sh" + termux_pkg_is_update_needed "$@" +fi From 6a061af2818cf9ed114e0cf677a4df18ac68028e Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:41:23 +0530 Subject: [PATCH 07/19] feat(auto update): add script to update github hosted packages Signed-off-by: Aditya Alok --- .../internal/termux_github_auto_update.sh | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 scripts/updates/internal/termux_github_auto_update.sh diff --git a/scripts/updates/internal/termux_github_auto_update.sh b/scripts/updates/internal/termux_github_auto_update.sh new file mode 100644 index 000000000..3ff1dd395 --- /dev/null +++ b/scripts/updates/internal/termux_github_auto_update.sh @@ -0,0 +1,25 @@ +# shellcheck shell=bash +# Default algorithm to use for packages hosted on github.com +termux_github_auto_update() { + local pkg_version + pkg_version="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f2-)" + local pkg_epoch + pkg_epoch="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f1)" + + if [[ "${pkg_version}" == "${pkg_epoch}" ]]; then + # No epoch set. + pkg_epoch="" + else + pkg_epoch+=":" + fi + + local latest_tag + latest_tag="$( + termux_github_api_get_tag "${TERMUX_PKG_SRCURL}" "${TERMUX_PKG_UPDATE_TAG_TYPE}" + )" + + if [[ -z "${latest_tag}" ]]; then + termux_error_exit "ERROR: Unable to get tag from ${TERMUX_PKG_SRCURL}" + fi + termux_pkg_upgrade_version "${pkg_epoch}${latest_tag}" +} From b518a1599b88b9c5738cd4cf8c458284ccc60378 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:42:07 +0530 Subject: [PATCH 08/19] feat(auto update): add script to update gitlab hosted packages Signed-off-by: Aditya Alok --- .../internal/termux_gitlab_auto_update.sh | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 scripts/updates/internal/termux_gitlab_auto_update.sh diff --git a/scripts/updates/internal/termux_gitlab_auto_update.sh b/scripts/updates/internal/termux_gitlab_auto_update.sh new file mode 100644 index 000000000..535ad80bf --- /dev/null +++ b/scripts/updates/internal/termux_gitlab_auto_update.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash +# Default algorithm to use for packages hosted on hosts using gitlab-ci. +termux_gitlab_auto_update() { + # Our local version of package. + local pkg_version + pkg_version="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f2-)" + local pkg_epoch + pkg_epoch="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f1)" + + if [[ "${pkg_version}" == "${pkg_epoch}" ]]; then + # No epoch set. + pkg_epoch="" + else + pkg_epoch+=":" + fi + + local latest_tag + latest_tag="$( + termux_gitlab_api_get_tag \ + "${TERMUX_PKG_SRCURL}" "${TERMUX_PKG_UPDATE_TAG_TYPE}" "${TERMUX_GITLAB_API_HOST}" + )" + # No need to check for return code `2`, since gitlab api does not implement cache control. + + if [[ -z "${latest_tag}" ]]; then + termux_error_exit "ERROR: Unable to get tag from ${TERMUX_PKG_SRCURL}" + fi + termux_pkg_upgrade_version "${pkg_epoch}${latest_tag}" +} From 4af11020295392bc302a04ba0ae940aa94b6f6a3 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:42:50 +0530 Subject: [PATCH 09/19] feat(auto update): add script to update repology tracked packages Signed-off-by: Aditya Alok --- .../internal/termux_repology_auto_update.sh | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 scripts/updates/internal/termux_repology_auto_update.sh diff --git a/scripts/updates/internal/termux_repology_auto_update.sh b/scripts/updates/internal/termux_repology_auto_update.sh new file mode 100644 index 000000000..ef927fc86 --- /dev/null +++ b/scripts/updates/internal/termux_repology_auto_update.sh @@ -0,0 +1,26 @@ +# shellcheck shell=bash +termux_repology_auto_update() { + # Our local version of package. + local pkg_version + pkg_version="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f2-)" + local pkg_epoch + pkg_epoch="$(echo "${TERMUX_PKG_VERSION}" | cut -d: -f1)" + + if [[ "${pkg_version}" == "${pkg_epoch}" ]]; then + # No epoch set. + pkg_epoch="" + else + pkg_epoch+=":" + fi + + local latest_version + latest_version="$(termux_repology_api_get_latest_version "${TERMUX_PKG_NAME}")" + + # Repology api returns null if package is not tracked by repology or is already upto date. + if [[ "${latest_version}" == "null" ]]; then + echo "INFO: Already up to date." # Since we exclude unique to termux packages, this package + # should be tracked by repology and be already up to date. + return 0 + fi + termux_pkg_upgrade_version "${pkg_epoch}${latest_version}" +} From ea595dd257164e7fa28e95a9597d9702e10e2d2c Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:43:34 +0530 Subject: [PATCH 10/19] feat(auto update): add script to extract repology data from its api Signed-off-by: Aditya Alok --- scripts/updates/api/dump-repology-data | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 scripts/updates/api/dump-repology-data diff --git a/scripts/updates/api/dump-repology-data b/scripts/updates/api/dump-repology-data new file mode 100755 index 000000000..f93d9dafd --- /dev/null +++ b/scripts/updates/api/dump-repology-data @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +# The MIT License (MIT) + +# Copyright (c) 2022 Aditya Alok (aka. @MrAdityaAlok) + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +from requests import get as requests_get + + +def get_repology_data(last_project): + repology_data = requests_get( + f"https://repology.org/api/v1/projects/{last_project}?inrepo=termux&outdated=True&families_newest=2-" + ).json() # NOTE: We are using 2- so that api will return a package as outdated if it is so in 2 or more + # repo family. This helps us avoid false positives. + + return repology_data + + +def get_outdated_packages(): + termux_outdated_packages = {} + last_project = "" + brk_flag = False # Flag to break the infinite loop. + + while True: + repology_data = get_repology_data(last_project) + last_project = sorted(repology_data.keys())[ + -1 + ] # This used to query repology for next set of packages. + # Quoting repology documentation: "You may iterate through + # all projects by using the last project name in the next request" + # For more info, visit https://repology.org/api + if len(repology_data) <= 1: + # Break the loop after this iteration. + brk_flag = True + + for package_name, package_data in repology_data.items(): + if package_name in termux_outdated_packages: + # Skip if package is already in the dict. + continue + newest_stable = None + newest_devel = None + for repo_data in package_data: + if repo_data.get("status", "") == "newest": + newest_stable = repo_data["version"] + # If we found stable version, break the loop. + break + elif repo_data.get("status", "") == "devel": + # Do not break the loop if we found devel version as there may be stable version later. + newest_devel = repo_data["version"] + + if newest_stable: + termux_outdated_packages[package_name] = newest_stable + elif newest_devel: + termux_outdated_packages[package_name] = newest_devel + else: + # If we don't find any version, skip the package. + continue + if brk_flag: + break + + return termux_outdated_packages + + +if __name__ == "__main__": + import json + import sys + + try: + output_file = sys.argv[1] + except IndexError: + sys.exit("Please provide an output file") + + with open(output_file, "w") as f: + json.dump(get_outdated_packages(), f) From ba0688e4c5a2b6796c46058150f2b72b9af99291 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:44:51 +0530 Subject: [PATCH 11/19] feat(auto update): add script to get tags from github api Signed-off-by: Aditya Alok --- .../updates/api/termux_github_api_get_tag.sh | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 scripts/updates/api/termux_github_api_get_tag.sh diff --git a/scripts/updates/api/termux_github_api_get_tag.sh b/scripts/updates/api/termux_github_api_get_tag.sh new file mode 100644 index 000000000..5f815fffc --- /dev/null +++ b/scripts/updates/api/termux_github_api_get_tag.sh @@ -0,0 +1,131 @@ +# shellcheck shell=bash +termux_github_api_get_tag() { + if [[ -z "$1" ]]; then + termux_error_exit <<-EndOfUsage + Usage: ${FUNCNAME[0]} PKG_SRCURL [TAG_TYPE] + Returns the latest tag of the given package. + EndOfUsage + fi + + if [[ -z "${GITHUB_TOKEN:-}" ]]; then + # Needed to use graphql API. + termux_error_exit "ERROR: GITHUB_TOKEN environment variable not set." + fi + + local PKG_SRCURL="$1" + local TAG_TYPE="${2:-}" + + local project + project="$(echo "${PKG_SRCURL}" | cut -d'/' -f4-5)" + project="${project%.git}" + + if [[ -z "${TAG_TYPE}" ]]; then # If not set, then decide on the basis of url. + if [[ "${PKG_SRCURL: -4}" == ".git" ]]; then + # Get newest tag. + TAG_TYPE="newest-tag" + else + # Get the latest release tag. + TAG_TYPE="latest-release-tag" + fi + fi + + local jq_filter + local api_url="" + local extra_curl_opts="" + + if [[ "${TAG_TYPE}" == "newest-tag" ]]; then + api_url="https://api.github.com/graphql" + jq_filter='.data.repository.refs.edges[0].node.name' + extra_curl_opts="-d $( + cat <<-EOF + "{ + "query": "query { + repository(owner: \"${project%/*}\", name: \"${project##*/}\") { + refs(refPrefix: \"refs/tags/\", first: 1, orderBy: { + field: TAG_COMMIT_DATE, direction: DESC + }) + { + edges { + node { + name + } + } + } + } + } + }" + EOF + )" + elif [[ "${TAG_TYPE}" == "latest-release-tag" ]]; then + api_url="${api_url}/releases/latest" + jq_filter=".tag_name" + else + termux_error_exit <<-EndOfError + ERROR: Invalid TAG_TYPE: '${TAG_TYPE}'. + Allowed values: 'newest-tag', 'latest-release-tag'. + EndOfError + fi + + local response + # shellcheck disable=SC2086 # we need expansion of $extra_curl_opts + response="$( + curl --silent --location --retry 10 --retry-delay 1 \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github.v3+json" \ + --write-out '|%{http_code}' \ + $extra_curl_opts \ + "${api_url}" + )" + + local http_code + http_code="${response##*|}" + # Why printf "%s\n"? Because echo interpolates control characters, which jq does not like. + response="$(printf "%s\n" "${response%|*}")" + + local tag_name + if [[ "${http_code}" == "200" ]]; then + if jq --exit-status --raw-output "${jq_filter}" <<<"${response}" >/dev/null; then + tag_name="$(jq --exit-status --raw-output "${jq_filter}" <<<"${response}")" + else + termux_error_exit "ERROR: Failed to parse tag name from: '${response}'" + fi + elif [[ "${http_code}" == "404" ]]; then + if jq --exit-status "has(\"message\") and .message == \"Not Found\"" <<<"${response}"; then + termux_error_exit <<-EndOfError + ERROR: No '${TAG_TYPE}' found (${api_url}). + Try using '$( + if [ ${TAG_TYPE} = "newest-tag" ]; then + echo "latest-release-tag" + else + echo "newest-tag" + fi + )'. + EndOfError + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}'(${api_url})'. + Response: + ${response} + EndOfError + fi + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}'(${api_url})'. + HTTP code: ${http_code} + Response: + ${response} + EndOfError + fi + + # If program control reached here and still no tag_name, then something went wrong. + if [[ -z "${tag_name:-}" ]] || [[ "${tag_name}" == "null" ]]; then + termux_error_exit <<-EndOfError + ERROR: JQ could not find '${TAG_TYPE}'(${api_url})'. + Response: + ${response} + Please report this as bug. + EndOfError + fi + + echo "${tag_name#v}" # Remove leading 'v' which is common in version tag. +} From 843823e3f990e93c054493a24e99ed319008f530 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:45:17 +0530 Subject: [PATCH 12/19] feat(auto update): add script to get tags from gitlab api Signed-off-by: Aditya Alok --- .../updates/api/termux_gitlab_api_get_tag.sh | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 scripts/updates/api/termux_gitlab_api_get_tag.sh diff --git a/scripts/updates/api/termux_gitlab_api_get_tag.sh b/scripts/updates/api/termux_gitlab_api_get_tag.sh new file mode 100644 index 000000000..ddcc91b95 --- /dev/null +++ b/scripts/updates/api/termux_gitlab_api_get_tag.sh @@ -0,0 +1,114 @@ +# shellcheck shell=bash +termux_gitlab_api_get_tag() { + if [[ -z "$1" ]]; then + termux_error_exit <<-EndOfUsage + Usage: ${FUNCNAME[0]} PKG_SRCURL [TAG_TYPE] [API_HOST] + Returns the latest tag of the given package. + EndOfUsage + + fi + local PKG_SRCURL="$1" + local TAG_TYPE="${2:-}" + local API_HOST="${3:-gitlab.com}" + + local project + project="$(echo "${PKG_SRCURL}" | cut -d'/' -f4-5)" + project="${project%.git}" + + if [[ -z "${TAG_TYPE}" ]]; then # If not set, then decide on the basis of url. + if [[ "${PKG_SRCURL: -4}" == ".git" ]]; then + # Get newest tag. + TAG_TYPE="newest-tag" + else + # Get the latest release tag. + TAG_TYPE="latest-release-tag" + fi + fi + + local jq_filter + local api_path + + case "${TAG_TYPE}" in + latest-release-tag) + api_path="/releases" + jq_filter=".[0].tag_name" + ;; + newest-tag) + api_path="/repository/tags" + jq_filter=".[0].name" + ;; + *) + termux_error_exit <<-EndOfError + ERROR: Invalid TAG_TYPE: '${TAG_TYPE}'. + Allowed values: 'newest-tag', 'latest-release-tag'. + EndOfError + ;; + esac + + # Replace slash '/' with '%2F' in project name. It is required for Gitlab API. + local api_url="https://${API_HOST}/api/v4/projects/${project//\//%2F}${api_path}" + # Api can be accessed without authentication if the repository is publicly accessible. + # Default rate limit for gitlab.com is 300 requests per minute for unauthenticated users + # and non-protected paths which should be enough for most use cases. + # see: https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits + local response + response="$( + curl --silent --location --retry 10 --retry-delay 1 \ + --write-out '|%{http_code}' \ + "${api_url}" + )" + + local http_code + http_code="${response##*|}" + # Why printf "%s\n"? Because echo interpolates control characters, which jq does not like. + response="$(printf "%s\n" "${response%|*}")" + + local tag_name + if [[ "${http_code}" == "200" ]]; then + if jq --exit-status --raw-output "${jq_filter}" <<<"${response}" >/dev/null; then + tag_name="$(jq --exit-status --raw-output "${jq_filter}" <<<"${response}")" + else + termux_error_exit "ERROR: Failed to parse tag name from: '${response}'" + fi + elif [[ "${http_code}" == "404" ]]; then + if jq --exit-status "has(\"message\") and .message == \"Not Found\"" <<<"${response}"; then + termux_error_exit <<-EndOfError + ERROR: No '${TAG_TYPE}' found. (${api_url}) + Try using '$( + if [ ${TAG_TYPE} = "newest-tag" ]; then + echo "latest-release-tag" + else + echo "newest-tag" + fi + )'. + EndOfError + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}' (${api_url}). + Response: + ${response} + EndOfError + fi + elif [[ "${http_code}" == "304" ]]; then + return 2 # Up-to-date. + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}' (${api_url}). + HTTP code: ${http_code} + Response: + ${response} + EndOfError + fi + + # If program control reached here and still no tag_name, then something is not right. + if [[ -z "${tag_name:-}" ]] || [[ "${tag_name}" == "null" ]]; then + termux_error_exit <<-EndOfError + ERROR: JQ could not find '${TAG_TYPE}' (${api_url}). + Response: + ${response} + Please report this as bug. + EndOfError + fi + + echo "${tag_name#v}" # Strip leading 'v'. +} From 08ac4aa4dbdcd8bf3c3b319ee00d2751c7519ef9 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:45:48 +0530 Subject: [PATCH 13/19] feat(auto update): add script to get newest version from repology api Signed-off-by: Aditya Alok --- .../termux_repology_api_get_latest_version.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scripts/updates/api/termux_repology_api_get_latest_version.sh diff --git a/scripts/updates/api/termux_repology_api_get_latest_version.sh b/scripts/updates/api/termux_repology_api_get_latest_version.sh new file mode 100644 index 000000000..46ac698fc --- /dev/null +++ b/scripts/updates/api/termux_repology_api_get_latest_version.sh @@ -0,0 +1,18 @@ +# shellcheck shell=bash +termux_repology_api_get_latest_version() { + if [[ -z "$1" ]]; then + termux_error_exit "Usage: ${FUNCNAME[0]} PKG_NAME" + fi + + if [[ ! -s "${TERMUX_REPOLOGY_DATA_FILE}" ]]; then + pip3 install bs4 requests >/dev/null # Install python dependencies. + python3 "${TERMUX_SCRIPTDIR}"/scripts/updates/api/dump-repology-data \ + "${TERMUX_REPOLOGY_DATA_FILE}" >/dev/null + fi + + local PKG_NAME="$1" + local version + # Why `--arg`? See: https://stackoverflow.com/a/54674832/15086226 + version="$(jq -r --arg packageName "$PKG_NAME" '.[$packageName]' <"${TERMUX_REPOLOGY_DATA_FILE}")" + echo "${version#v}" +} From 3bc578adb33b79836d6b1e6ebbc8661ad1b31463 Mon Sep 17 00:00:00 2001 From: Aditya Alok Date: Sat, 26 Mar 2022 13:46:52 +0530 Subject: [PATCH 14/19] feat: add package neovim nightly Signed-off-by: Aditya Alok neovim-nightly: update to 0.7.0-dev+1333-g71b4c30ad This commit has been automatically submitted by Github Actions. --- packages/neovim-nightly/build.sh | 125 ++++++++++++++++++ packages/neovim-nightly/custom-bin/cmake | 77 +++++++++++ .../runtime-CMakeLists.txt.patch | 21 +++ .../runtime-autoload-man.vim.patch | 12 ++ .../src-nvim-eval-funcs.c.patch | 13 ++ .../src-nvim-os-stdpaths.c.patch | 14 ++ packages/neovim-nightly/sysinit.vim | 6 + 7 files changed, 268 insertions(+) create mode 100644 packages/neovim-nightly/build.sh create mode 100755 packages/neovim-nightly/custom-bin/cmake create mode 100644 packages/neovim-nightly/runtime-CMakeLists.txt.patch create mode 100644 packages/neovim-nightly/runtime-autoload-man.vim.patch create mode 100644 packages/neovim-nightly/src-nvim-eval-funcs.c.patch create mode 100644 packages/neovim-nightly/src-nvim-os-stdpaths.c.patch create mode 100644 packages/neovim-nightly/sysinit.vim diff --git a/packages/neovim-nightly/build.sh b/packages/neovim-nightly/build.sh new file mode 100644 index 000000000..621aaeb0c --- /dev/null +++ b/packages/neovim-nightly/build.sh @@ -0,0 +1,125 @@ +TERMUX_PKG_HOMEPAGE=https://neovim.io +TERMUX_PKG_DESCRIPTION="Ambitious Vim-fork focused on extensibility and agility (nvim-nightly)" +TERMUX_PKG_LICENSE="Apache-2.0" +TERMUX_PKG_MAINTAINER="Aditya Alok " +TERMUX_PKG_VERSION=0.7.0-dev+1333-g71b4c30ad +TERMUX_PKG_SRCURL="https://github.com/neovim/neovim/archive/nightly.tar.gz" +TERMUX_PKG_SHA256=ab3d8087cfee9dd4684e1e460162a1a13f86c2a7e84b16ba7ea64e0b83061466 +TERMUX_PKG_DEPENDS="libiconv, libuv, luv, libmsgpack, libandroid-support, libvterm, libtermkey, libluajit, libunibilium, libtreesitter" +TERMUX_PKG_HOSTBUILD=true + +TERMUX_PKG_EXTRA_CONFIGURE_ARGS=" +-DCMAKE_BUILD_TYPE=RelWithDebInfo +-DENABLE_JEMALLOC=OFF +-DGETTEXT_MSGFMT_EXECUTABLE=$(which msgfmt) +-DGETTEXT_MSGMERGE_EXECUTABLE=$(which msgmerge) +-DGPERF_PRG=$TERMUX_PKG_HOSTBUILD_DIR/deps/usr/bin/gperf +-DLUA_PRG=$TERMUX_PKG_HOSTBUILD_DIR/deps/usr/bin/luajit +-DPKG_CONFIG_EXECUTABLE=$(which pkg-config) +-DXGETTEXT_PRG=$(which xgettext) +-DLUAJIT_INCLUDE_DIR=$TERMUX_PREFIX/include/luajit-2.1 +" +TERMUX_PKG_CONFFILES="share/nvim/sysinit.vim" +TERMUX_PKG_CONFLICTS="neovim" + +TERMUX_PKG_AUTO_UPDATE=true + +termux_pkg_auto_update() { + # Scrap and parse github release page to get version of nightly build. + # Neovim just uses 'nightly' tag for release and not nightly version specific, so cannot use github api. + local curl_response=$( + curl \ + --silent \ + "https://github.com/neovim/neovim/releases/tag/nightly" \ + --write-out '|%{http_code}' + ) + local http_code="${curl_response##*|}" + + if [ "$http_code" != "200" ]; then + echo "Error: failed to get latest neovim-nightly tag page." + echo -e "http code: ${http_code}\ncurl response: ${curl_response}" + exit 1 + fi + + # this outputs in the following format: "0.6.0-dev+575-g2ef9d2a66" + local remote_nvim_version=$( + echo "$curl_response" | + cut -d"|" -f1 | + grep "
NVIM" | cut -d " " -f2 | sed "0,/v/s///"
+	)
+
+	# since we are using a nightly build, therefore no need to check for version increment/decrement.
+	if [ "${TERMUX_PKG_VERSION}" != "${remote_nvim_version}" ]; then
+		termux_pkg_upgrade_version "${remote_nvim_version}" --skip-version-check
+	fi
+}
+
+_patch_luv() {
+	# git submodule update --init deps/lua-compat-5.3 failed
+	cp -r $1/build/src/lua-compat-5.3/* $1/build/src/luv/deps/lua-compat-5.3/
+	cp -r $1/build/src/luajit/* $1/build/src/luv/deps/luajit/
+	cp -r $1/build/src/libuv/* $1/build/src/luv/deps/libuv/
+}
+
+termux_step_host_build() {
+	termux_setup_cmake
+
+	TERMUX_ORIGINAL_CMAKE=$(which cmake)
+	if [ ! -f "$TERMUX_ORIGINAL_CMAKE.orig" ]; then
+		mv "$TERMUX_ORIGINAL_CMAKE" "$TERMUX_ORIGINAL_CMAKE.orig"
+	fi
+	cp "$TERMUX_PKG_BUILDER_DIR/custom-bin/cmake" "$TERMUX_ORIGINAL_CMAKE"
+	chmod +x "$TERMUX_ORIGINAL_CMAKE"
+	export TERMUX_ORIGINAL_CMAKE="$TERMUX_ORIGINAL_CMAKE.orig"
+
+	mkdir -p $TERMUX_PKG_HOSTBUILD_DIR/deps
+	cd $TERMUX_PKG_HOSTBUILD_DIR/deps
+	cmake $TERMUX_PKG_SRCDIR/third-party
+
+	make -j 1 ||
+		(_patch_luv $TERMUX_PKG_HOSTBUILD_DIR/deps && make -j 1)
+
+	cd $TERMUX_PKG_SRCDIR
+
+	make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$TERMUX_PKG_HOSTBUILD_DIR -DUSE_BUNDLED_LUAROCKS=ON" install ||
+		(_patch_luv $TERMUX_PKG_SRCDIR/.deps && make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$TERMUX_PKG_HOSTBUILD_DIR -DUSE_BUNDLED_LUAROCKS=ON" install)
+
+	make distclean
+	rm -Rf build/
+
+	cd $TERMUX_PKG_HOSTBUILD_DIR
+}
+
+termux_step_pre_configure() {
+	TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" -DLUA_MATH_LIBRARY=$TERMUX_STANDALONE_TOOLCHAIN/sysroot/usr/lib/$TERMUX_HOST_PLATFORM/$TERMUX_PKG_API_LEVEL/libm.so"
+}
+
+termux_step_post_make_install() {
+	local _CONFIG_DIR=$TERMUX_PREFIX/share/nvim
+	mkdir -p $_CONFIG_DIR
+	cp $TERMUX_PKG_BUILDER_DIR/sysinit.vim $_CONFIG_DIR/
+}
+
+termux_step_create_debscripts() {
+	cat <<-EOF >./postinst
+		#!$TERMUX_PREFIX/bin/sh
+		if [ "$TERMUX_PACKAGE_FORMAT" = "pacman" ] || [ "\$1" = "configure" ] || [ "\$1" = "abort-upgrade" ]; then
+			if [ -x "$TERMUX_PREFIX/bin/update-alternatives" ]; then
+				update-alternatives --install \
+					$TERMUX_PREFIX/bin/editor editor $TERMUX_PREFIX/bin/nvim 40
+				update-alternatives --install \
+					$TERMUX_PREFIX/bin/vi vi $TERMUX_PREFIX/bin/nvim 15
+			fi
+		fi
+	EOF
+
+	cat <<-EOF >./prerm
+		#!$TERMUX_PREFIX/bin/sh
+		if [ "$TERMUX_PACKAGE_FORMAT" = "pacman" ] || [ "\$1" != "upgrade" ]; then
+			if [ -x "$TERMUX_PREFIX/bin/update-alternatives" ]; then
+				update-alternatives --remove editor $TERMUX_PREFIX/bin/nvim
+				update-alternatives --remove vi $TERMUX_PREFIX/bin/nvim
+			fi
+		fi
+	EOF
+}
diff --git a/packages/neovim-nightly/custom-bin/cmake b/packages/neovim-nightly/custom-bin/cmake
new file mode 100755
index 000000000..a310d5c4d
--- /dev/null
+++ b/packages/neovim-nightly/custom-bin/cmake
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+if [ -z $TERMUX_ORIGINAL_CMAKE ]; then
+    SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+    TERMUX_ORIGINAL_CMAKE="$SCRIPTPATH/cmake.orig"
+fi
+
+# Need to move --build argument to first due to following error:
+#  CMake Error: Unknown argument --build
+#  CMake Error: Run 'cmake --help' for all supported options.
+HAS_BUILD=false
+for arg in "$@"; do
+    if [ "$arg" == "--build" ]; then
+        HAS_BUILD=true
+    fi
+done
+
+if ! $HAS_BUILD; then
+    $TERMUX_ORIGINAL_CMAKE "$@"
+    exit $?
+fi
+
+
+BUILD_FLAG=false
+BUILD_VALUE=
+NEW_ARGS=()
+UPDATE_CMAKE_CACHE=()
+for arg in "$@"
+do
+    if [ "$arg" == "--build" ]; then
+        BUILD_FLAG=true
+    else
+        if $BUILD_FLAG; then
+            BUILD_VALUE="$arg"
+            BUILD_FLAG=false
+        else
+            case "$arg" in
+                -D*=*)
+                    UPDATE_CMAKE_CACHE+=("${arg:2}")
+                    ;;
+                *)
+                    NEW_ARGS+=("$arg")
+                    ;;
+            esac
+        fi
+    fi
+done
+
+if [ ! -z $BUILD_VALUE ]; then
+    NEW_ARGS=(--build "$BUILD_VALUE" "${NEW_ARGS[@]}")
+fi
+
+function update_cmake_cache() {
+    [ ${#UPDATE_CMAKE_CACHE[@]} -eq 0 ] && return
+    [ -z $BUILD_VALUE ] && return
+    if [ -f "$BUILD_VALUE/CMakeCache.txt" ]; then
+        rm -rf "$BUILD_VALUE/.tmp-orig.CMakeCache.tmp"
+        cp "$BUILD_VALUE/CMakeCache.txt" "$BUILD_VALUE/.tmp-orig.CMakeCache.tmp"
+        cat "$BUILD_VALUE/.tmp-orig.CMakeCache.tmp" | sed -E "$(python3 -c 'import os, sys
+def z(x): return x.replace("/","\\/")
+for a in sys.argv[2:]: print("-e s/^"+z(a.split("=",1)[0])+":(.*)=.*$/"+z(a.split("=",1)[0])+":\\1="+z(a.split("=",1)[1])+"/g", end=" ")
+' -- "${UPDATE_CMAKE_CACHE[@]}")" > "$BUILD_VALUE/CMakeCache.txt"
+    fi
+}
+
+function undo_update_cmake_cache() {
+    [ ${#UPDATE_CMAKE_CACHE[@]} -eq 0 ] && return
+    [ -z $BUILD_VALUE ] && return
+    [ ! -f "$BUILD_VALUE/.tmp-orig.CMakeCache.tmp" ] && return
+    mv -f "$BUILD_VALUE/.tmp-orig.CMakeCache.tmp" "$BUILD_VALUE/CMakeCache.txt"
+}
+
+update_cmake_cache
+trap undo_update_cmake_cache EXIT
+
+
+$TERMUX_ORIGINAL_CMAKE "${NEW_ARGS[@]}"
diff --git a/packages/neovim-nightly/runtime-CMakeLists.txt.patch b/packages/neovim-nightly/runtime-CMakeLists.txt.patch
new file mode 100644
index 000000000..eae593d4a
--- /dev/null
+++ b/packages/neovim-nightly/runtime-CMakeLists.txt.patch
@@ -0,0 +1,21 @@
+diff -u -r ../neovim-0.3.2/runtime/CMakeLists.txt ./runtime/CMakeLists.txt
+--- ../neovim-0.3.2/runtime/CMakeLists.txt	2018-12-31 00:06:17.000000000 +0000
++++ ./runtime/CMakeLists.txt	2019-01-03 00:07:55.652628776 +0000
+@@ -32,7 +32,7 @@
+     add_custom_target("${PACKNAME}-tags"
+       COMMAND ${CMAKE_COMMAND} -E copy_directory
+         ${PACKAGE} ${GENERATED_PACKAGE_DIR}/${PACKNAME}
+-      COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
++      COMMAND "${PROJECT_BINARY_DIR}/../host-build/bin/nvim"
+         -u NONE -i NONE -e --headless -c "helptags doc" -c quit
+       DEPENDS
+         nvim
+@@ -71,7 +71,7 @@
+   COMMAND ${CMAKE_COMMAND} -E remove doc/*
+   COMMAND ${CMAKE_COMMAND} -E copy_directory
+     ${PROJECT_SOURCE_DIR}/runtime/doc doc
+-  COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
++  COMMAND "${PROJECT_BINARY_DIR}/../host-build/bin/nvim"
+     -u NONE -i NONE -e --headless -c "helptags ++t doc" -c quit
+   DEPENDS
+     nvim
diff --git a/packages/neovim-nightly/runtime-autoload-man.vim.patch b/packages/neovim-nightly/runtime-autoload-man.vim.patch
new file mode 100644
index 000000000..6e42ff5e7
--- /dev/null
+++ b/packages/neovim-nightly/runtime-autoload-man.vim.patch
@@ -0,0 +1,12 @@
+diff -u -r ../neovim-0851057a8deaa1197bd0af22babb62c1146d836c/runtime/autoload/man.vim ./runtime/autoload/man.vim
+--- ../neovim-0851057a8deaa1197bd0af22babb62c1146d836c/runtime/autoload/man.vim	2018-02-04 12:54:30.000000000 +0000
++++ ./runtime/autoload/man.vim	2018-02-05 00:48:37.422608665 +0000
+@@ -149,7 +149,7 @@
+   " Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db).
+   " http://comments.gmane.org/gmane.editors.vim.devel/29085
+   " Set MAN_KEEP_FORMATTING so Debian man doesn't discard backspaces.
+-  let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'MAN_KEEP_FORMATTING=1', 'man']
++  let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'MAN_KEEP_FORMATTING=1', 'mandoc']
+   return s:system(cmd + (s:localfile_arg ? ['-l', a:path] : [a:path]))
+ endfunction
+ 
diff --git a/packages/neovim-nightly/src-nvim-eval-funcs.c.patch b/packages/neovim-nightly/src-nvim-eval-funcs.c.patch
new file mode 100644
index 000000000..9cd269192
--- /dev/null
+++ b/packages/neovim-nightly/src-nvim-eval-funcs.c.patch
@@ -0,0 +1,13 @@
+diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
+index 801b0f9..35c54df 100644
+--- a/src/nvim/eval/funcs.c
++++ b/src/nvim/eval/funcs.c
+@@ -4306,6 +4306,8 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+ #ifdef _WIN64
+     "win64",
+ #endif
++    "android",
++    "termux",
+ #ifndef CASE_INSENSITIVE_FILENAME
+     "fname_case",
+ #endif
diff --git a/packages/neovim-nightly/src-nvim-os-stdpaths.c.patch b/packages/neovim-nightly/src-nvim-os-stdpaths.c.patch
new file mode 100644
index 000000000..9801e302c
--- /dev/null
+++ b/packages/neovim-nightly/src-nvim-os-stdpaths.c.patch
@@ -0,0 +1,14 @@
+diff -u -r ../neovim-master/src/nvim/os/stdpaths.c ./src/nvim/os/stdpaths.c
+--- ../neovim-master/src/nvim/os/stdpaths.c	2015-11-01 16:16:38.000000000 -0500
++++ ./src/nvim/os/stdpaths.c	2015-11-02 14:12:12.770172673 -0500
+@@ -34,8 +34,8 @@
+   [kXDGDataHome] = "~/.local/share",
+   [kXDGCacheHome] = "~/.cache",
+   [kXDGRuntimeDir] = NULL,
+-  [kXDGConfigDirs] = "/etc/xdg/",
+-  [kXDGDataDirs] = "/usr/local/share/:/usr/share/",
++  [kXDGConfigDirs] = "@TERMUX_PREFIX@/etc/xdg/",
++  [kXDGDataDirs] = "@TERMUX_PREFIX@/local/share/:@TERMUX_PREFIX@/share/",
+ #endif
+ };
+ 
diff --git a/packages/neovim-nightly/sysinit.vim b/packages/neovim-nightly/sysinit.vim
new file mode 100644
index 000000000..50944a79a
--- /dev/null
+++ b/packages/neovim-nightly/sysinit.vim
@@ -0,0 +1,6 @@
+" Scroll only one line for mouse wheel events to get smooth scrolling on touch screens
+set mouse=a
+map  
+imap  
+map  
+imap  

From 694a941883975ad686d318be017f986f1795c82f Mon Sep 17 00:00:00 2001
From: Aditya Alok 
Date: Sun, 27 Mar 2022 23:38:57 +0530
Subject: [PATCH 15/19] fix(auto update): fix few messages, comments and code

Signed-off-by: Aditya Alok 
---
 scripts/bin/update-packages                   | 22 +++++++++----------
 scripts/updates/api/dump-repology-data        |  9 ++++----
 .../updates/api/termux_github_api_get_tag.sh  |  6 ++---
 .../updates/api/termux_gitlab_api_get_tag.sh  |  2 --
 .../utils/termux_pkg_is_update_needed.sh      | 12 +++++-----
 .../utils/termux_pkg_upgrade_version.sh       |  3 +--
 6 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/scripts/bin/update-packages b/scripts/bin/update-packages
index 831d6048f..c059db191 100755
--- a/scripts/bin/update-packages
+++ b/scripts/bin/update-packages
@@ -13,7 +13,7 @@ set -u
 export TERMUX_PKG_UPDATE_METHOD=""         # Which method to use for updating? (repology, github or gitlab)
 export TERMUX_PKG_UPDATE_TAG_TYPE=""       # Whether to use latest-release-tag or newest-tag.
 export TERMUX_GITLAB_API_HOST="gitlab.com" # Default host for gitlab-ci.
-export TERMUX_PKG_AUTO_UPDATE=true         # Whether to auto-update or not.
+export TERMUX_PKG_AUTO_UPDATE=false        # Whether to auto-update or not. Disabled by default.
 export TERMUX_PKG_UPDATE_VERSION_REGEXP="" # Regexp to extract version.
 export TERMUX_REPOLOGY_DATA_FILE
 TERMUX_REPOLOGY_DATA_FILE="$(mktemp -t termux-repology.XXXXXX)" # File to store repology data.
@@ -59,7 +59,7 @@ TERMUX_SCRIPTDIR="$(realpath "$(dirname "$0")/../..")" # Script directory.
 # shellcheck source=scripts/updates/internal/termux_gitlab_auto_update.sh
 . "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_gitlab_auto_update.sh
 
-# Default auto update script for packages. Should not be overrided by build.sh.
+# Default auto update script for rest packages. Should not be overrided by build.sh.
 # To use custom algorithm, one should override termux_pkg_auto_update().
 # shellcheck source=scripts/updates/internal/termux_repology_auto_update.sh
 . "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_repology_auto_update.sh
@@ -107,15 +107,14 @@ _update() {
 }
 
 _test_pkg_build_file() {
-	local pkg_dir
-	pkg_dir="$1"
+	local pkg_dir="$1"
 	if [[ ! -f "${pkg_dir}/build.sh" ]]; then
 		# Fail if detected a non-package directory.
 		termux_error_exit "ERROR: directory '${pkg_dir}' is not a package."
 	fi
 }
 
-declare -a _failed_updates=()
+declare -a _FAILED_UPDATES=()
 
 _run_update() {
 	local pkg_dir="$1"
@@ -127,7 +126,7 @@ _run_update() {
 	)
 	# shellcheck disable=SC2181
 	if [[ $? -ne 0 ]]; then
-		_failed_updates+=("$(basename "${pkg_dir}")")
+		_FAILED_UPDATES+=("$(basename "${pkg_dir}")")
 	fi
 }
 
@@ -143,12 +142,13 @@ _get_unique_packages() {
 	echo "${unique_packages[@]}"
 }
 
-declare -a _unique_packages
-read -r -a _unique_packages <<<"$(_get_unique_packages)"
+declare -a _UNIQUE_PACKAGES
+read -r -a _UNIQUE_PACKAGES <<<"$(_get_unique_packages)"
 
 _unique_to_termux() {
 	local pkg_dir="$1"
-	if [[ "${_unique_packages[*]}" =~ "$(basename "${pkg_dir}")" ]]; then
+	# shellcheck disable=2076 # We want literal match not regex.
+	if [[ "${_UNIQUE_PACKAGES[*]}" =~ "$(basename "${pkg_dir}")" ]]; then
 		return 0
 	else
 		return 1
@@ -180,10 +180,10 @@ main() {
 		done
 	fi
 
-	if ((${#_failed_updates[@]} > 0)); then
+	if ((${#_FAILED_UPDATES[@]} > 0)); then
 		echo # Newline.
 		echo "===========================Failed updates==========================="
-		for failed_update in "${_failed_updates[@]}"; do
+		for failed_update in "${_FAILED_UPDATES[@]}"; do
 			echo "==> ${failed_update}"
 		done
 		exit 1 # Exit with error code, so that we know that some/all updates failed.
diff --git a/scripts/updates/api/dump-repology-data b/scripts/updates/api/dump-repology-data
index f93d9dafd..bd1795760 100755
--- a/scripts/updates/api/dump-repology-data
+++ b/scripts/updates/api/dump-repology-data
@@ -38,7 +38,6 @@ def get_repology_data(last_project):
 def get_outdated_packages():
     termux_outdated_packages = {}
     last_project = ""
-    brk_flag = False  # Flag to break the infinite loop.
 
     while True:
         repology_data = get_repology_data(last_project)
@@ -48,9 +47,11 @@ def get_outdated_packages():
         # Quoting repology documentation: "You may iterate through
         # all projects by using the last project name in the next request"
         # For more info, visit https://repology.org/api
+        # NOTE: next response to request will include the last_project given.
         if len(repology_data) <= 1:
-            # Break the loop after this iteration.
-            brk_flag = True
+            # Break the loop now. Since api returned only one package, it
+            # must be the last_project, which was already included in previous iteration.
+            break
 
         for package_name, package_data in repology_data.items():
             if package_name in termux_outdated_packages:
@@ -74,8 +75,6 @@ def get_outdated_packages():
             else:
                 # If we don't find any version, skip the package.
                 continue
-        if brk_flag:
-            break
 
     return termux_outdated_packages
 
diff --git a/scripts/updates/api/termux_github_api_get_tag.sh b/scripts/updates/api/termux_github_api_get_tag.sh
index 5f815fffc..2004a4a7c 100644
--- a/scripts/updates/api/termux_github_api_get_tag.sh
+++ b/scripts/updates/api/termux_github_api_get_tag.sh
@@ -30,11 +30,11 @@ termux_github_api_get_tag() {
 	fi
 
 	local jq_filter
-	local api_url=""
+	local api_url="https://api.github.com"
 	local extra_curl_opts=""
 
 	if [[ "${TAG_TYPE}" == "newest-tag" ]]; then
-		api_url="https://api.github.com/graphql"
+		api_url="${api_url}/graphql"
 		jq_filter='.data.repository.refs.edges[0].node.name'
 		extra_curl_opts="-d $(
 			cat <<-EOF
@@ -57,7 +57,7 @@ termux_github_api_get_tag() {
 			EOF
 		)"
 	elif [[ "${TAG_TYPE}" == "latest-release-tag" ]]; then
-		api_url="${api_url}/releases/latest"
+		api_url="${api_url}/repos/${project}/releases/latest"
 		jq_filter=".tag_name"
 	else
 		termux_error_exit <<-EndOfError
diff --git a/scripts/updates/api/termux_gitlab_api_get_tag.sh b/scripts/updates/api/termux_gitlab_api_get_tag.sh
index ddcc91b95..6a4b5c24b 100644
--- a/scripts/updates/api/termux_gitlab_api_get_tag.sh
+++ b/scripts/updates/api/termux_gitlab_api_get_tag.sh
@@ -89,8 +89,6 @@ termux_gitlab_api_get_tag() {
 				${response}
 			EndOfError
 		fi
-	elif [[ "${http_code}" == "304" ]]; then
-		return 2 # Up-to-date.
 	else
 		termux_error_exit <<-EndOfError
 			ERROR: Failed to get '${TAG_TYPE}' (${api_url}).
diff --git a/scripts/updates/utils/termux_pkg_is_update_needed.sh b/scripts/updates/utils/termux_pkg_is_update_needed.sh
index 21def6704..266c48a71 100755
--- a/scripts/updates/utils/termux_pkg_is_update_needed.sh
+++ b/scripts/updates/utils/termux_pkg_is_update_needed.sh
@@ -26,13 +26,13 @@ termux_pkg_is_update_needed() {
 	# If needed, filter version numbers from tag by using regexp.
 	if [[ -n "${VERSION_REGEX}" ]]; then
 		LATEST_VERSION="$(grep -oP "${VERSION_REGEX}" <<<"${LATEST_VERSION}" || true)"
-	fi
 
-	if [[ -z "${LATEST_VERSION}" ]]; then
-		termux_error_exit <<-EndOfError
-			ERROR: failed to check latest version. Ensure whether the version regex '${VERSION_REGEX}'
-			works correctly with latest release tag.
-		EndOfError
+		if [[ -z "${LATEST_VERSION}" ]]; then
+			termux_error_exit <<-EndOfError
+				ERROR: failed to check latest version. Ensure whether the version regex '${VERSION_REGEX}'
+				works correctly with latest release tag.
+			EndOfError
+		fi
 	fi
 
 	# Translate "_" into ".": some packages use underscores to seperate
diff --git a/scripts/updates/utils/termux_pkg_upgrade_version.sh b/scripts/updates/utils/termux_pkg_upgrade_version.sh
index 7273eeb39..fc4155613 100755
--- a/scripts/updates/utils/termux_pkg_upgrade_version.sh
+++ b/scripts/updates/utils/termux_pkg_upgrade_version.sh
@@ -27,7 +27,7 @@ termux_pkg_upgrade_version() {
 		echo "INFO: package being updated to $(echo "${LATEST_VERSION}" | cut -d':' -f2)."
 
 		sed -i \
-			"s/^\(TERMUX_PKG_VERSION=\)\(.*\)\$/\1${LATEST_VERSION}/g" \
+			"s/^\(TERMUX_PKG_VERSION=\)\(.*\)\$/\1\"${LATEST_VERSION}\"/g" \
 			"${PKG_DIR}/build.sh"
 		sed -i \
 			"/TERMUX_PKG_REVISION=/d" \
@@ -61,7 +61,6 @@ termux_pkg_upgrade_version() {
 			if [[ "${GIT_PUSH_PACKAGES}" == "true" ]]; then
 				echo "INFO: Pushing package."
 				stderr="$(
-					git status # DEBUG
 					git pull --rebase 2>&1 >/dev/null
 					git push 2>&1 >/dev/null
 				)" || {

From 292474f08259935223c3831cc9c30513c0a97c75 Mon Sep 17 00:00:00 2001
From: Aditya Alok 
Date: Mon, 28 Mar 2022 13:01:54 +0530
Subject: [PATCH 16/19] fix(termux_github_api_get_tag): expansion of newline in
 graphql api

Signed-off-by: Aditya Alok 
---
 .../updates/api/termux_github_api_get_tag.sh  | 43 +++++++++++--------
 1 file changed, 24 insertions(+), 19 deletions(-)

diff --git a/scripts/updates/api/termux_github_api_get_tag.sh b/scripts/updates/api/termux_github_api_get_tag.sh
index 2004a4a7c..1c4dc4c0c 100644
--- a/scripts/updates/api/termux_github_api_get_tag.sh
+++ b/scripts/updates/api/termux_github_api_get_tag.sh
@@ -31,31 +31,35 @@ termux_github_api_get_tag() {
 
 	local jq_filter
 	local api_url="https://api.github.com"
-	local extra_curl_opts=""
+	local -a extra_curl_opts
 
 	if [[ "${TAG_TYPE}" == "newest-tag" ]]; then
 		api_url="${api_url}/graphql"
 		jq_filter='.data.repository.refs.edges[0].node.name'
-		extra_curl_opts="-d $(
-			cat <<-EOF
-				"{
-					"query": "query {
-						repository(owner: \"${project%/*}\", name: \"${project##*/}\") {
-							refs(refPrefix: \"refs/tags/\", first: 1, orderBy: {
-								field: TAG_COMMIT_DATE, direction: DESC
-							})
-							{
-								edges {
-									node {
-										name
+		extra_curl_opts=(
+			"-X POST"
+			"-d $(
+				cat <<-EOF | tr '\n' ' '
+					{
+						"query": "query {
+							repository(owner: \"${project%/*}\", name: \"${project##*/}\") {
+								refs(refPrefix: \"refs/tags/\", first: 1, orderBy: {
+									field: TAG_COMMIT_DATE, direction: DESC
+								})
+								{
+									edges {
+										node {
+											name
+										}
 									}
 								}
 							}
-						}
+						}"
 					}
-				}"
-			EOF
-		)"
+				EOF
+			)"
+		)
+
 	elif [[ "${TAG_TYPE}" == "latest-release-tag" ]]; then
 		api_url="${api_url}/repos/${project}/releases/latest"
 		jq_filter=".tag_name"
@@ -67,13 +71,14 @@ termux_github_api_get_tag() {
 	fi
 
 	local response
-	# shellcheck disable=SC2086 # we need expansion of $extra_curl_opts
+	# shellcheck disable=SC2086 # we need expansion of ${extra_curl_opts[0]}
 	response="$(
 		curl --silent --location --retry 10 --retry-delay 1 \
 			-H "Authorization: token ${GITHUB_TOKEN}" \
 			-H "Accept: application/vnd.github.v3+json" \
 			--write-out '|%{http_code}' \
-			$extra_curl_opts \
+			${extra_curl_opts[0]:-} \
+			"${extra_curl_opts[1]:-}" \
 			"${api_url}"
 	)"
 

From 4b87d872a38f1409c438c4003107d8af01c92d59 Mon Sep 17 00:00:00 2001
From: Aditya Alok 
Date: Mon, 28 Mar 2022 23:36:04 +0530
Subject: [PATCH 17/19] chore(neovim-nightly): update to
 0.7.0-dev+1341-g79dcd045d

---
 packages/neovim-nightly/build.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/neovim-nightly/build.sh b/packages/neovim-nightly/build.sh
index 621aaeb0c..741d40e3d 100644
--- a/packages/neovim-nightly/build.sh
+++ b/packages/neovim-nightly/build.sh
@@ -2,9 +2,9 @@ TERMUX_PKG_HOMEPAGE=https://neovim.io
 TERMUX_PKG_DESCRIPTION="Ambitious Vim-fork focused on extensibility and agility (nvim-nightly)"
 TERMUX_PKG_LICENSE="Apache-2.0"
 TERMUX_PKG_MAINTAINER="Aditya Alok "
-TERMUX_PKG_VERSION=0.7.0-dev+1333-g71b4c30ad
+TERMUX_PKG_VERSION="0.7.0-dev+1341-g79dcd045d"
 TERMUX_PKG_SRCURL="https://github.com/neovim/neovim/archive/nightly.tar.gz"
-TERMUX_PKG_SHA256=ab3d8087cfee9dd4684e1e460162a1a13f86c2a7e84b16ba7ea64e0b83061466
+TERMUX_PKG_SHA256=d37d50c28059fde68b1ff6787bace6f4744c052cddce0bef38e4cf228da75266
 TERMUX_PKG_DEPENDS="libiconv, libuv, luv, libmsgpack, libandroid-support, libvterm, libtermkey, libluajit, libunibilium, libtreesitter"
 TERMUX_PKG_HOSTBUILD=true
 

From 92ea572ede9b0296e6bf82d716f6d0168a5e805a Mon Sep 17 00:00:00 2001
From: Aditya Alok 
Date: Mon, 28 Mar 2022 23:45:07 +0530
Subject: [PATCH 18/19] ci(package_updates.yml): use `contact@termux.org` for
 git email

Signed-off-by: Aditya Alok 
---
 .github/workflows/package_updates.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/package_updates.yml b/.github/workflows/package_updates.yml
index 139150427..36bb4812e 100644
--- a/.github/workflows/package_updates.yml
+++ b/.github/workflows/package_updates.yml
@@ -28,7 +28,7 @@ jobs:
           GIT_PUSH_PACKAGES: "true"
         run: |
           git config --global user.name "Termux Github Actions"
-          git config --global user.email "contact@termux.com"
+          git config --global user.email "contact@termux.org"
 
           if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
             ./scripts/bin/update-packages ${{ github.event.inputs.packages }}

From c23d019058c82110f9ef05013953b4a8793aab18 Mon Sep 17 00:00:00 2001
From: Aditya Alok 
Date: Tue, 29 Mar 2022 00:50:29 +0530
Subject: [PATCH 19/19] feat: replace `apt-compare-versions` script with
 `termux_pkg_is_update_needed`

Signed-off-by: Aditya Alok 
---
 scripts/bin/apt-compare-versions              | 30 +-------------
 .../utils/termux_pkg_is_update_needed.sh      | 40 ++++++++++++++-----
 2 files changed, 32 insertions(+), 38 deletions(-)
 mode change 100755 => 120000 scripts/bin/apt-compare-versions

diff --git a/scripts/bin/apt-compare-versions b/scripts/bin/apt-compare-versions
deleted file mode 100755
index b1225448f..000000000
--- a/scripts/bin/apt-compare-versions
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python3
-# apt-compare-versions: Simple script which takes two arguments and compares
-# their version according to apt rules. This can be used to verify the ordering
-# between two versions.
-#
-# Note that ~ (tilde) construct, which allows for beta and preview releases.
-# A version with ~ is considered earlier than one without, so 1.6~beta1 is
-# considered earlier than 1.6. If both versions contains ~ the version comparison
-# is made first on the part preceding the tilde, then the part coming after,
-# so 1.6~beta1 comes before 1.6~beta2.
-
-import apt_pkg, sys
-apt_pkg.init_system()
-
-if len(sys.argv) != 3:
-	sys.exit('usage: apt-compare-versions  ')
-
-version1 = sys.argv[1]
-version2 = sys.argv[2]
-
-comparison_result =  apt_pkg.version_compare(version1, version2)
-if comparison_result > 0:
-	operator = ' > '
-elif comparison_result < 0:
-	operator = ' < '
-elif comparison_result == 0:
-	operator = ' == '
-
-print(version1 + operator + version2)
diff --git a/scripts/bin/apt-compare-versions b/scripts/bin/apt-compare-versions
new file mode 120000
index 000000000..00f20e6cf
--- /dev/null
+++ b/scripts/bin/apt-compare-versions
@@ -0,0 +1 @@
+../updates/utils/termux_pkg_is_update_needed.sh
\ No newline at end of file
diff --git a/scripts/updates/utils/termux_pkg_is_update_needed.sh b/scripts/updates/utils/termux_pkg_is_update_needed.sh
index 266c48a71..250725e52 100755
--- a/scripts/updates/utils/termux_pkg_is_update_needed.sh
+++ b/scripts/updates/utils/termux_pkg_is_update_needed.sh
@@ -12,11 +12,10 @@
 # But hopefully, all this can be avoided if TERMUX_PKG_AUTO_UPDATE_TAG_REGEXP is set.
 #
 termux_pkg_is_update_needed() {
-	if [[ "$#" -lt 2 ]] || [[ "$#" -gt 3 ]]; then
-		termux_error_exit <<-EndOfUsage
-			Usage: ${FUNCNAME[0]}   [version-regexp]
-			Returns: 0 if update is needed, 1 if not.
-		EndOfUsage
+	# USAGE: termux_pkg_is_update_needed   [regexp]
+
+	if [[ -z "$1" ]] || [[ -z "$2" ]]; then
+		termux_error_exit "${BASH_SOURCE[0]}: at least 2 arguments expected"
 	fi
 
 	local CURRENT_VERSION="$1"
@@ -29,8 +28,8 @@ termux_pkg_is_update_needed() {
 
 		if [[ -z "${LATEST_VERSION}" ]]; then
 			termux_error_exit <<-EndOfError
-				ERROR: failed to check latest version. Ensure whether the version regex '${VERSION_REGEX}'
-				works correctly with latest release tag.
+				ERROR: failed to compare versions. Ensure whether the version regex '${VERSION_REGEX}'
+				works correctly with given versions.
 			EndOfError
 		fi
 	fi
@@ -58,8 +57,31 @@ termux_pkg_is_update_needed() {
 	return 1 # false. Update not needed.
 }
 
+show_help() {
+	echo "Usage: ${BASH_SOURCE[0]} [--help]  ] [version-regex]"
+	echo "--help - show this help message and exit"
+	echo "   - first version to compare"
+	echo "   - second version to compare"
+	echo "  [version-regex] - optional regular expression to filter version numbers"
+	exit 0
+}
+
 # Make script sourceable as well as executable.
 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
-	declare -f termux_error_exit >/dev/null || . "$(dirname "${BASH_SOURCE[0]}")/termux_error_exit.sh"
-	termux_pkg_is_update_needed "$@"
+	declare -f termux_error_exit >/dev/null ||
+		. "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/termux_error_exit.sh" # realpath is used to resolve symlinks.
+
+	if [[ "${1}" == "--help" ]]; then
+		show_help
+	fi
+
+	# Print in human readable format.
+	first_version="$1"
+	second_version="$2"
+	version_regexp="${3:-}"
+	if termux_pkg_is_update_needed "${first_version}" "${second_version}" "${version_regexp}"; then
+		echo "${first_version} < ${second_version}"
+	else
+		echo "${first_version} >= ${second_version}"
+	fi
 fi