#!/bin/bash usage() { tee <&1)" local divergent_redirect application_content text_content inline_content content_length request_success while IFS= read -r line; do case "${line}" in *location:*"${version}"*) continue ;; *location:*) divergent_redirect='true' ;; *content-length:*) content_length='true' ;; *content-disposition:*inline*) inline_content='true' ;; *content-type:*application*) application_content='true' ;; *content-type:*text*) text_content='true' ;; *http/*200*ok*) request_success='true' ;; esac done <<< "${response,,}" test -n "${request_success}" || return 1 test -z "${divergent_redirect}" || return 1 test -n "${application_content}" && return 0 test -n "${content_length}" && return 0 test -n "${inline_content}" && return 0 test -z "${text_content}" } downloadable_url() { local location="${1}" [[ "${location}" =~ ^https:// ]] && return 0 [[ "${location}" =~ ^http:// ]] && return 0 [[ "${location}" =~ ^ftp:// ]] && return 0 return 1 } downloadable_urls() { local recipe="${1}" local -n nameref_list="${2}" local source location silent recipe_info "${recipe}" source for element in "${source[@]}"; do location="${element#*::}" downloadable_url "${location}" && nameref_list+=("${location}") done } unreferenced_version() { local current_recipe="${1}" local updated_recipe="${2}" local current_urls updated_urls local index=0 downloadable_urls "${current_recipe}" current_urls downloadable_urls "${updated_recipe}" updated_urls while [[ ${index} -lt ${#current_urls[@]} ]]; do [[ "${current_urls[index]}" != "${updated_urls[index]}" ]] && return 1 index=$((index + 1)) done return 0 } check_version() { local recipe="${1}" local locations pkgver silent recipe_info "${recipe}" pkgver downloadable_urls "${recipe}" locations for element in "${locations[@]}"; do download_available "${element}" "${pkgver}" || return 1 done return 0 } reset_recipes() { for element in "${recipes[@]}"; do test -f "${element}.NEW" || continue rm -v "${element}.NEW" done } pending_updates() { local package pkgbase pkgname current_version updated_version progress 'Checking status' for recipe in "${recipes[@]}"; do test -f "${recipe}.NEW" || continue silent recipe_info "${recipe}" pkgver:current_version pkgbase pkgname silent recipe_info "${recipe}.NEW" pkgver:updated_version package_name "${recipe}" "${pkgbase}" "${pkgname}" package collect pending none "${recipe}" "${package}" "${current_version}" "${updated_version}" done progress_done test -n "${pending}" && echo report 'Pending updates' "${pending[@]}" } detect_version() { local directory="${1}" local name="${2}" local pkgver="${3}" local realname="${name#mingw-w64-}" [[ "${name}" =~ .*-(git|hg|bzr|svn|cvs)$ ]] && return 2 [[ "${realname}" =~ .*[0-9].* && -z "${option_versioned}" ]] && return 3 [[ "${pkgver}" =~ ^([0-9]|[1-9][0-9]+)(\.([0-9]|[1-9][0-9]+))*$ ]] || return 4 [[ "${pkgver}" =~ ^[0-9]{1,2}(\.[0-9]{1,2})*$ ]] || return 5 ! find_pattern "${directory}" "${excludes[@]}" } detect_versions() { local package pkgbase pkgname pkgver directory for recipe in "${recipes[@]}"; do recipe_location "${recipe}" directory recipe_info "${recipe}" pkgbase pkgname pkgver package_name "${recipe}" "${pkgbase}" "${pkgname}" package detect_version "${directory}" "${pkgbase:-${pkgname}}" "${pkgver}" case ${?} in 1) collect ignored_excluded ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" ;; 2) collect ignored_development ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" ;; 3) collect ignored_versioned ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" ;; 4) collect ignored_strange ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" ;; 5) collect ignored_large ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" ;; *) collect updatable ${#recipes[@]} "${recipe}" "${package}" "${pkgver}" esac done progress_done test -n "${updatable}" || test -n "${option_report}" && echo } report_versions() { report 'Updatable versions' "${updatable[@]}" report 'Large versions' "${ignored_large[@]}" report 'Strange versions' "${ignored_strange[@]}" report 'Versioned names' "${ignored_versioned[@]}" report 'Development names' "${ignored_development[@]}" report 'Excluded names' "${ignored_excluded[@]}" } check_update() { local package="${1}" local version="${2}" local recipe="${3}" local current_version="${version}" local recipe_name recipe_directory component component_level unreferenced_version recipe_filename "${recipe}" recipe_name recipe_location "${recipe}" recipe_directory cd "${recipe_directory}" if test -f "${recipe_name}.NEW"; then silent recipe_info "${recipe_name}.NEW" pkgver:version status success "${package}" "${current_version}" "${version}" current_version="${version}" fi for component in ${current_version//./ }; do component_level=$((component_level + 1)) local bump_count=0 while true; do bump_count=$((bump_count + 1)) test ${bump_count} -gt ${max_bump[component_level - 1]:-${max_bump[-1]}} && break bump_version version ${component_level} status checking "${package}" "${current_version}" "${version}" temporary_recipe "${recipe_name}" "${recipe_directory}" replace_version "${recipe_name}.TMP" "${version}" if unreferenced_version "${recipe_name}" "${recipe_name}.TMP"; then collect unreferenced none "${recipe}" "${package}" "${current_version}" "${version}" unreferenced_version='true' status failure break fi if check_version "${recipe_name}.TMP"; then status success "${package}" "${current_version}" "${version}" current_version="${version}" cp "${recipe_name}.TMP" "${recipe_name}.NEW" else status failure fi done test -z "${unreferenced_version}" || break version="${current_version}" done rm "${recipe_name}.TMP" if test -f "${recipe_name}.NEW"; then silent recipe_info "${recipe_name}" pkgver:version silent recipe_info "${recipe_name}.NEW" pkgver:current_version collect updates none "${recipe}" "${package}" "${version}" "${current_version}" fi silent cd - } check_updates() { local -A package test -n "${updatable}" || return 0 header 'Checking updates' for element in "${updatable[@]}"; do restore package "${element}" check_update "${package[name]}" "${package[version]}" "${package[recipe]}" done test -z "${updates}" && message 'no updates detected\n' echo test -n "${option_report}" && report 'Unreferenced versions' "${unreferenced[@]}" } makepkg_command() { local -n nameref_command="${1}" local recipe_name="${2}" local type pkgname arch if test -n "${static_makepkg}"; then nameref_command="${static_makepkg}" return fi silent recipe_info "${recipe_name}" pkgname arch recipe_type type pkgname arch if [[ "${type}" = mingw ]] then nameref_command='makepkg-mingw' else nameref_command='makepkg' fi } make_package() { local makepkg="${1}" local recipe_name="${2}" local options='--noconfirm --skippgpcheck --nocheck --syncdeps --rmdeps --clean --cleanbuild --force --log' ${makepkg} -p "${recipe_name}" ${options} } build_filter() { local pattern="${1}" sed --unbuffered --regexp-extended -e 's/\.+$//' -e "s/^${pattern}/${indent}::/" | grep --color=never "^${indent}::" } build_status() { local status="${1}" local package="${2}" local version="${3}" local makepkg="${4}" if test -z "${option_verbose}"; then case "${status}" in started) status building "${package}" "${version}" ;; success) echo 'success' ;; failure) echo 'failed' ;; esac else case "${status}" in started) echo "==> Building ${package} ${version} with ${makepkg}" ;; success) echo '==> SUCCESS' esac fi } build_update() { local -n nameref_package="${1}" local recipe_name recipe_directory makepkg silent recipe_filename "${nameref_package[recipe]}" recipe_name recipe_location "${nameref_package[recipe]}" recipe_directory cd "${recipe_directory}" makepkg_command makepkg "${recipe_name}" build_status started "${nameref_package[name]}" "${nameref_package[new_version]}" "${makepkg}" test -z "${option_verbose}" && silent='silent' if (${silent} updpkgsums "${recipe_name}.NEW" && ${silent} make_package "${makepkg}" "${recipe_name}.NEW" && mv "${recipe_name}.NEW" "${recipe_name}") then build_status success else build_status failure fi silent cd - } build_updates() { local -A package test -n "${updates}" || return 0 header 'Building packages' for element in "${updates[@]}"; do restore package "${element}" if test -z "${option_verbose}" then build_update package else build_update package 2>&1 | build_filter '==>' fi if test -f "${package[recipe]}.NEW" then failed+=("${element}") else updated+=("${element}") fi test -n "${option_verbose}" && echo done test -z "${option_verbose}" && echo } commit_updates() { local message='Automatic package updates by updpkgver.\n' local files recipe_name recipe_directory local -A package if test -n "${option_no_build}"; then for element in "${updates[@]}"; do restore package "${element}" recipe_filename "${package[recipe]}" recipe_name recipe_location "${package[recipe]}" recipe_directory cd "${recipe_directory}" if (silent updpkgsums "${recipe_name}.NEW" && mv "${recipe_name}.NEW" "${recipe_name}") then updated+=("${element}") else failed+=("${element}") fi silent cd - done fi test -n "${updated}" || return 0 for element in "${updated[@]}"; do restore package "${element}" files+=("${package[recipe]}") message+="\n* Update ${package[name]} to ${package[new_version]}." done silent git commit --file <(printf "${message}") "${files[@]}" || terminate 'failed committing updates' } pactoys_options='color.simple' source pactoys || exit import clearline import colorize import colors_stdout import progress import progress_done import terminal import terminate import truncate import find_pattern import lines_to_list import noiseless import separate import silent import find_recipes import package_name import recipe_info import recipe_location import recipe_type if [[ "${BASH_SOURCE}" = "${0}" ]]; then read_arguments "${@}" test -n "${option_reset}" && { reset_recipes; exit; } test -n "${option_status}" && { pending_updates; exit; } detect_versions test -n "${option_report}" && report_versions check_updates test -z "${option_no_build}" && build_updates test -n "${option_commit}" && commit_updates test -n "${option_report}" && report 'Failed packages' "${failed[@]}" test -n "${option_report}" && report 'Updated packages' "${updated[@]}" fi