#!/bin/sh # delete obsolete binary packages # 1] Condition for deleting a package A is that: # a) nothing on the build-list (make|check|)depends on A and # b) no built package B which is not being deleted depends on A # "Package x depends on package y" means, that something needed by x # is provided by y and no other package which will not be deleted. # shellcheck disable=SC2039 # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" # TODO: delete other to-be-deleted packages if asked to do so # shellcheck disable=SC2016 usage() { >&2 echo '' >&2 echo 'delete-packages [options]:' >&2 echo ' delete obsolete binary packages.' >&2 echo '' >&2 echo 'possible options:' >&2 echo ' -b|--block: If necessary, wait for lock blocking.' >&2 echo ' -h|--help: Show this help and exit.' >&2 echo ' -n|--no-action: Only print what would be deleted.' [ -z "$1" ] && exit 1 || exit "$1" } eval set -- "$( getopt -o bhn \ --long block \ --long help \ --long no-action \ -n "$(basename "$0")" -- "$@" || \ echo usage )" block_flag='-n' no_action=false while true do case "$1" in -b|--block) block_flag='' ;; -h|--help) usage 0 ;; -n|--no-action) no_action=true ;; --) shift break ;; *) >&2 echo 'Whoops, forgot to implement option "'"$1"'" internally.' exit 42 ;; esac shift done if [ -s "${work_dir}/build-master-sanity" ]; then >&2 echo 'Build master is not sane.' exit fi # Create a lock file and a trap. if ! ${no_action}; then # exec 9> "${build_list_lock_file}" # if ! flock ${block_flag} 9; then # >&2 echo 'come back (shortly) later - I cannot lock build list.' # exit 0 # fi exec 8> "${package_database_lock_file}" if ! flock ${block_flag} 8; then >&2 echo 'come back (shortly) later - I cannot lock package database.' exit 0 fi exec 7> "${sanity_check_lock_file}" if ! flock -s ${block_flag} 7; then >&2 echo 'come back (shortly) later - sanity-check running.' exit 0 fi fi tmp_dir=$(mktemp -d "${work_dir}/tmp.delete-packages.XXXXXXXXXX") trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT # shellcheck disable=SC2016 { printf 'CREATE TEMPORARY TABLE `to_deletes` (`id` BIGINT, UNIQUE KEY (`id`));\n' printf 'INSERT IGNORE INTO `to_deletes`' printf ' SELECT `binary_packages`.`id`' printf ' FROM `binary_packages`' mysql_join_binary_packages_dependencies mysql_join_dependencies_dependency_types printf ' AND `dependency_types`.`relevant_for_binary_packages`' mysql_join_binary_packages_repositories printf ' AND `repositories`.`is_on_master_mirror`' printf ' WHERE `binary_packages`.`is_to_be_deleted`' printf ' AND NOT EXISTS (' printf 'SELECT * FROM `install_target_providers`' mysql_join_install_target_providers_binary_packages '' 'prov_bp' mysql_join_binary_packages_repositories 'prov_bp' 'prov_r' mysql_join_repositories_repository_stabilities 'prov_r' printf ' WHERE `install_target_providers`.`install_target`=`dependencies`.`depending_on`' printf ' AND `repository_stabilities`.`name` NOT IN ("forbidden","virtual")' printf ');\n' printf ' SELECT DISTINCT "repo",`repositories`.`name`' printf ' FROM `to_deletes`' printf ' JOIN `binary_packages` ON `to_deletes`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories printf ';\n' printf ' SELECT "package",`repositories`.`name`,`binary_packages`.`pkgname`' printf ' FROM `to_deletes`' printf ' JOIN `binary_packages` ON `to_deletes`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories printf ';\n' printf ' SELECT "package-file",`repositories`.`name`,' mysql_package_name_query printf ' FROM `to_deletes`' printf ' JOIN `binary_packages` ON `to_deletes`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories mysql_join_binary_packages_architectures printf ';\n' printf ' SELECT "package-id",`to_deletes`.`id`' printf ' FROM `to_deletes`' printf ';\n' } | \ mysql_run_query | \ sed ' y/\t/ / /^repo /{ s/^\S\+ // w '"${tmp_dir}"'/repositories d } /^package /{ s/^\S\+ // w '"${tmp_dir}"'/packages d } /^package-file /{ s/^\S\+ // s, ,/, w '"${tmp_dir}"'/package-files s/$/.sig/ w '"${tmp_dir}"'/package-files d } /^package-id /{ s/^\S\+ // w '"${tmp_dir}"'/package-ids d } ' if [ ! -s "${tmp_dir}/packages" ]; then printf 'Nothing to delete.\n' exit fi mkdir "${tmp_dir}/repos" while read -r repo; do ${master_mirror_rsync_command} \ "${master_mirror_rsync_directory}/i686/${repo}/${repo}.db.tar.gz" \ "${master_mirror_rsync_directory}/i686/${repo}/${repo}.files.tar.gz" \ "${tmp_dir}/repos/" tar -Oxzf "${tmp_dir}/repos/${repo}.db.tar.gz" --wildcards '*/desc' | \ sed -n ' /^%FILENAME%$/{ N s/^\S\+\n\(\S\+-[^-.]\+\)\(-[^-]\+\)/\1.0\2 \1\2/ T p } ' | \ while read -r old new; do printf 's,/%s\\(\\.sig\\)\\?$,/%s\\1,\n' \ "$(str_to_regex "${old}")" \ "$(str_to_regex "${new}")" done >> \ "${tmp_dir}/sub_pkgrel-removal.sed" # shellcheck disable=SC2046 repo-remove "${tmp_dir}/repos/${repo}.db.tar.gz" \ $( grep "^$(str_to_regex "${repo}") " "${tmp_dir}/packages" | \ cut -d' ' -f2 ) if ! ${no_action}; then ${master_mirror_rsync_command} \ "${tmp_dir}/repos/${repo}.db.tar.gz" \ "${tmp_dir}/repos/${repo}.files.tar.gz" \ "${master_mirror_rsync_directory}/i686/${repo}/" fi done < \ "${tmp_dir}/repositories" if [ -s "${tmp_dir}/sub_pkgrel-removal.sed" ]; then sed -i -f "${tmp_dir}/sub_pkgrel-removal.sed" "${tmp_dir}/package-files" fi if ${no_action}; then printf 'Now, I would remove the packages from the database and delete the following files from the master mirror:\n' sed ' s,^, , ' "${tmp_dir}/package-files" exit fi # shellcheck disable=SC2016 { printf 'CREATE TEMPORARY TABLE `to_deletes` (`id` BIGINT, UNIQUE KEY (`id`));\n' printf 'LOAD DATA LOCAL INFILE "%s" INTO TABLE `to_deletes`;\n' \ "${tmp_dir}/package-ids" printf 'UPDATE `binary_packages` ' printf ' JOIN `to_deletes` ON `to_deletes`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories mysql_join_binary_packages_architectures printf ' SET `repository`=(' printf 'SELECT `repositories`.`id`' printf ' FROM `repositories`' printf ' WHERE `repositories`.`name`="deletion-list"' printf ');\n' } | \ mysql_run_query sed ' s,^,rm "i686/, s,$,", ' "${tmp_dir}/package-files" | \ ${master_mirror_sftp_command}