From 9217f3869f76d6936e77cec0a1a4d5efd1e97727 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Sat, 22 Jul 2017 18:06:12 -0400 Subject: Merge branch 'feature/use-autoconf-automake-shpp-and-shld' --- (limited to 'src') diff --git a/src/cmd.sh b/src/cmd.sh new file mode 100644 index 0000000..1ed69b2 --- /dev/null +++ b/src/cmd.sh @@ -0,0 +1,116 @@ +# pro-archman +# lib/cmd.sh +# Command-related functions +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmds=' ' + +register_cmd() +{ + local cmd="${1}" + shift 1 + + cmds="${cmds}${cmd} " + return 0 +} + +print_opt_summaries() +{ + local padding= + local opt= + local opt_out= + local summary= + + padding="$(printf '%24s' '')" + for opt in $(printf '%s' "${OPTSTRING}" | sed 's/\([a-zA-Z0-9]\)/ \1/g') + do + if [ ${#opt} -eq 1 ]; then + # No argument expected. + opt_out="-${opt}" + else + # Argument expected. + opt="${opt%?}" + opt_out="-${opt} $(get_msg "opt_${opt}_arg")" + fi + if [ ${#opt_out} -gt 20 ]; then + printf ' %s\n%24s' "${opt_out}" '' + else + printf ' %-20s ' "${opt_out}" + fi + summary="$(get_msg "opt_${opt}_summary")" + printf '%s\n' "${summary}" | fold -s -w 56 | \ + sed "2,\$s/^/${padding}/;" + done +} + +print_cmd_summaries() +{ + local padding= + local cmd= + local cmd_clean= + local summary= + + padding="$(printf '%24s' '')" + for cmd in ${cmds}; do + if [ ${#cmd} -gt 20 ]; then + printf ' %s\n%24s' "${cmd}" '' + else + printf ' %-20s ' "${cmd}" + fi + cmd_clean="$(printf '%s' "${cmd}" | \ + tr '[A-Z]' '[a-z]' | tr -C '[a-z0-9_]' '_')" + summary="$(get_msg "cmd_${cmd_clean}_summary")" + printf '%s\n' "${summary}" | fold -s -w 56 | \ + sed "2,\$s/^/${padding}/;" + done +} + +print_cmd_usage() +{ + local cmd="${1}" + local cmd_clean= + local usage= + + cmd_clean="$(printf '%s' "${cmd}" | \ + tr '[A-Z]' '[a-z]' | tr -C '[a-z0-9_]' '_')" + usage="$(get_msg "cmd_${cmd_clean}_usage")" + + printf "$(get_msg 'cmd_usage')\n" "${0}" "${cmd}" "${usage}" +} + +is_cmd() +{ + local cmd="${1}" + + case "${cmds}" in *" ${cmd} "*) return 0;; esac + return 1 +} + +run_cmd() +{ + local cmd="${1}" + local cmd_clean= + shift + + cmd_clean="$(printf '%s' "${cmd}" | \ + tr '[A-Z]' '[a-z]' | tr -C '[a-z0-9_]' '_')" + if is_cmd "${cmd}"; then + "cmd_${cmd_clean}_main" "${@}" + else + error 1 "$(get_msg 'cmd_not_found')" "${cmd}" + fi +} diff --git a/src/cmd/copy-suite.sh b/src/cmd/copy-suite.sh new file mode 100644 index 0000000..51fd969 --- /dev/null +++ b/src/cmd/copy-suite.sh @@ -0,0 +1,53 @@ +# pro-archman +# lib/cmd/copy-suite.sh +# "copy-suite" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_copy_suite_main() +{ + local src_suite="${1}" + local dst_suite="${2}" + local src_chan= + local src_dist= + local dst_chan= + local dst_dist= + + init + + src_chan="${src_suite%/*}" + src_dist="${src_suite##*/}" + if [ "x${src_chan}" = "x${src_suite}" ]; then + src_chan="${conf_incoming_channel}" + fi + dst_chan="${dst_suite%/*}" + dst_dist="${dst_suite##*/}" + if [ "x${dst_chan}" = "x${dst_suite}" ]; then + dst_chan="${conf_incoming_channel}" + fi + + copy_suite "${src_chan}" "${src_dist}" "${dst_chan}" "${dst_dist}" + + fini + + return 0 +} + +cmd_copy_suite_register() +{ + register_cmd 'copy-suite' +} +__init cmd_copy_suite_register diff --git a/src/cmd/help.sh b/src/cmd/help.sh new file mode 100644 index 0000000..628b0dc --- /dev/null +++ b/src/cmd/help.sh @@ -0,0 +1,46 @@ +# pro-archman +# lib/cmd/help.sh +# "help" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_help_main() +{ + local cmd= + + if [ ${#} -eq 1 ]; then + cmd="${1}" + if is_cmd "${cmd}"; then + print_cmd_usage "${cmd}" + return 0 + fi + fi + + printf "$(get_msg 'cmd_help_head')\n\n" "${0}" + + printf "$(get_msg 'cmd_help_opts_head')\n" + print_opt_summaries + printf '\n' + + printf "$(get_msg 'cmd_help_summary_head')\n" + print_cmd_summaries +} + +cmd_help_register() +{ + register_cmd 'help' +} +__init cmd_help_register diff --git a/src/cmd/include.sh b/src/cmd/include.sh new file mode 100644 index 0000000..7f8fbac --- /dev/null +++ b/src/cmd/include.sh @@ -0,0 +1,39 @@ +# pro-archman +# lib/cmd/include.sh +# "include" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_include_main() +{ + local changes= + + init + + for changes in "${@}"; do + include_changes "${changes}" >/dev/null + done + + fini + + return 0 +} + +cmd_include_register() +{ + register_cmd 'include' +} +__init cmd_include_register diff --git a/src/cmd/local.mk b/src/cmd/local.mk new file mode 100644 index 0000000..9dd7023 --- /dev/null +++ b/src/cmd/local.mk @@ -0,0 +1,8 @@ +pro_archman_SOURCES += \ + %reldir%/help.sh \ + %reldir%/version.sh \ + %reldir%/include.sh \ + %reldir%/process-incoming.sh \ + %reldir%/remove.sh \ + %reldir%/copy-suite.sh \ + %reldir%/remove-suite.sh diff --git a/src/cmd/process-incoming.sh b/src/cmd/process-incoming.sh new file mode 100644 index 0000000..0634f34 --- /dev/null +++ b/src/cmd/process-incoming.sh @@ -0,0 +1,51 @@ +# pro-archman +# lib/cmd/generate-index.sh +# "generate-index" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_process_incoming_main() +{ + local changes= + local file= + + init + + info "$(get_msg 'cmd_process_incoming_processing')" + + for changes in "${conf_incoming_dir}/"*.changes; do + if [ ! -f "${changes}" ]; then + continue + fi + for file in $(include_changes "${changes}"); do + if [ ! -f "${file}" ]; then + continue + fi + rm -f "${file}" + done + rm -f "${changes}" + done + + fini + + return 0 +} + +cmd_process_incoming_register() +{ + register_cmd 'process-incoming' +} +__init cmd_process_incoming_register diff --git a/src/cmd/remove-suite.sh b/src/cmd/remove-suite.sh new file mode 100644 index 0000000..6703d24 --- /dev/null +++ b/src/cmd/remove-suite.sh @@ -0,0 +1,45 @@ +# pro-archman +# lib/cmd/remove-suite.sh +# "remove-suite" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_remove_suite_main() +{ + local suite="${1}" + local chan= + local dist= + + init + + chan="${suite%/*}" + dist="${suite##*/}" + if [ "x${chan}" = "x${suite}" ]; then + chan="${conf_incoming_channel}" + fi + + remove_suite "${chan}" "${dist}" + + fini + + return 0 +} + +cmd_remove_suite_register() +{ + register_cmd 'remove-suite' +} +__init cmd_remove_suite_register diff --git a/src/cmd/remove.sh b/src/cmd/remove.sh new file mode 100644 index 0000000..388a4d3 --- /dev/null +++ b/src/cmd/remove.sh @@ -0,0 +1,46 @@ +# pro-archman +# lib/cmd/remove.sh +# "remove" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_remove_main() +{ + local suite="${1}" + local source="${2}" + local chan= + local dist= + + init + + chan="${suite%/*}" + dist="${suite##*/}" + if [ "x${chan}" = "x${suite}" ]; then + chan="${conf_incoming_channel}" + fi + + remove_source_from_suite "${chan}" "${dist}" "${source}" + + fini + + return 0 +} + +cmd_remove_register() +{ + register_cmd 'remove' +} +__init cmd_remove_register diff --git a/src/cmd/version.sh b/src/cmd/version.sh new file mode 100644 index 0000000..b22205f --- /dev/null +++ b/src/cmd/version.sh @@ -0,0 +1,32 @@ +# pro-archman +# lib/cmd/version.sh +# "version" command +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +cmd_version_main() +{ + printf '%s %s\n' "${PACKAGE}" "${PACKAGE_VERSION}" + + printf "$(get_msg 'cmd_version_copyright')\n" \ + '2013' 'Patrick "P. J." McDermott' +} + +cmd_version_register() +{ + register_cmd 'version' +} +__init cmd_version_register diff --git a/src/control.sh b/src/control.sh new file mode 100644 index 0000000..3fe00d4 --- /dev/null +++ b/src/control.sh @@ -0,0 +1,130 @@ +# pro-archman +# lib/control.sh +# Functions for parsing control files. +# +# Copyright (C) 2012, 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +control_file= +control_line_nr= + +parse_control() +{ + local field_cb="${2}" + local req_fields="${3}" + local opt_fields="${4}" + local all_fields= + local got_fields= + local line= + local name= + local value= + + control_file="${1}" + control_line_nr=0 + + req_fields="$(printf '%s\n' ${req_fields})" + opt_fields="$(printf '%s\n' ${opt_fields})" + all_fields="${LF}${req_fields}${LF}${opt_fields}${LF}" + got_fields="${LF}" + + while IFS='' read -r line; do + control_line_nr=$(($control_line_nr + 1)) + if [ "x$(echo ${line})" = 'x' ]; then + parse_control_error 'control_empty_line' + elif [ "x${line#\#}" != "x${line}" ]; then + # Comment. + : + elif [ "x${line# }" = "x${line}" ]; then + # "Name: Value" line. + if [ "x${name}" != 'x' ]; then + if ! "${field_cb}" "${name}" "${value}"; then + return 0 + fi + fi + name="${line%%:*}" + value="${line#*:}" + value="${value# }" + if [ "x${name}" = 'x' -o "x${name}" = "x${line}" ]; then + parse_control_error 'control_bad_nv' + continue + fi + if [ "x${req_fields}" != 'x' ]; then + if [ "x${all_fields%${LF}${name}${LF}*}" = \ + "x${all_fields}" ]; then + # Unknown field. + parse_control_error \ + 'control_unknown_field' \ + "${name}" + else + # Remove field from list of required + # fields. + req_fields="$(printf '%s' \ + "${req_fields}" | \ + grep -Fv "${name}")" + fi + fi + if [ "x${got_fields%${LF}${name}${LF}*}" != \ + "x${got_fields}" ]; then + # Duplicate field. + parse_control_error 'control_duplicate_field' \ + "${name}" + else + got_fields="${got_fields}${name}${LF}" + fi + else + # Continuation line. + if [ "x${name}" = 'x' ]; then + # Expecting a "Name: Value" line. + parse_control_error 'control_found_continuation' + continue + fi + value="${value}${LF}${line# }" + fi + done <<-EOF + $(cat "${control_file}") + EOF + + if [ "x${name}" != 'x' ]; then + if ! "${field_cb}" "${name}" "${value}"; then + return 0 + fi + fi + + if [ "x${req_fields}" != 'x' ]; then + req_fields="$(printf "%s$(get_msg 'list_item_separator')" \ + ${req_fields})" + parse_control_error 'control_missing_fields' "${req_fields}" + fi + + return 0 +} + +parse_control_error() +{ + local msgid="${1}" + local file_info= + shift 1 + + if [ ${control_line_nr} -eq 0 ]; then + file_info="$(printf '%20s:' "${control_file}")" + else + file_info="$(printf '%20s(l%d):' "${control_file}" \ + "${control_line_nr}")" + fi + + warn "${file_info} $(get_msg "${msgid}")" "${@}" + + return 0 +} diff --git a/src/db.sh b/src/db.sh new file mode 100644 index 0000000..291f9b8 --- /dev/null +++ b/src/db.sh @@ -0,0 +1,288 @@ +# pro-archman +# lib/db.sh +# Functions for querying and modifying the database +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# Functions for the suites indices +# + +db_get_srcver() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}" + if [ -f "${dir}/srcver" ]; then + cat "${dir}/srcver" + fi + + return 0 +} + +db_set_srcver() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + local srcver="${4}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}" + mkdir -p "${dir}" + printf '%s\n' "${srcver}" >"${dir}/srcver" + + return 0 +} + +db_del_srcver() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}" + rm -f "${dir}/srcver" + # Remove ".../.db//". + rmdir "${dir}" + # Try to remove ".../.db/" and ".../.db". + for dir in "${dir%/*}" "${dir%/*/*}"; do + try_rmdir "${dir}" || break + done + + return 0 +} + +db_get_binver() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local source="${5}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}/${arch}_${plat}" + if [ -f "${dir}/binver" ]; then + cat "${dir}/binver" + fi + + return 0 +} + +db_set_binver() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local source="${5}" + local binver="${6}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}/${arch}_${plat}" + mkdir -p "${dir}" + printf '%s\n' "${binver}" >"${dir}/binver" + + return 0 +} + +db_del_binver() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local source="${5}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}/${arch}_${plat}" + rm -f "${dir}/binver" + # Remove ".../.db///_". + rmdir "${dir}" + + return 0 +} + +db_foreach_source() +{ + local chan="${1}" + local dist="${2}" + local cb="${3}" + local dir= + + shift 3 + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + # For each hash: + for dir in "${dir}/"*/; do + if [ ! -d "${dir}" ]; then + continue + fi + # For each source: + for dir in "${dir}/"*/; do + if [ ! -d "${dir}" ]; then + continue + fi + dir="${dir%/}" + dir="${dir##*/}" + "${cb}" "${chan}" "${dist}" "${dir}" "${@}" + done + done + + return 0 +} + +db_get_archplats() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + local dir= + + dir="${base_dir}/feeds/${chan}/${dist}/.db" + dir="${dir}/$(hash_name "${source}")/${source}" + for dir in "${dir}/"*_*/; do + if [ ! -d "${dir}" ]; then + continue + fi + dir="${dir%/}" + dir="${dir##*/}" + printf '%s %s\n' "${dir%%_*}" "${dir#*_}" + done + + return 0 +} + +# +# Functions for the pool indices +# + +db_get_packages() +{ + local arch="${1}" + local plat="${2}" + local source="${3}" + local binver="${4}" + local dir= + + dir="${base_dir}/pool/$(hash_name "${source}")/${source}/.db" + dir="${dir}/${binver}_${arch}_${plat}" + if [ -f "${dir}/packages" ]; then + cat "${dir}/packages" + fi + + return 0 +} + +db_add_package() +{ + local arch="${1}" + local plat="${2}" + local source="${3}" + local binver="${4}" + local size="${5}" + local sect="${6}" + local pkg="${7}" + local dir= + + dir="${base_dir}/pool/$(hash_name "${source}")/${source}/.db" + dir="${dir}/${binver}_${arch}_${plat}" + mkdir -p "${dir}" + printf '%s %s %s\n' "${size}" "${sect}" "${pkg}" >>"${dir}/packages" + + return 0 +} + +db_del_packages() +{ + local arch="${1}" + local plat="${2}" + local source="${3}" + local binver="${4}" + local dir= + + dir="${base_dir}/pool/$(hash_name "${source}")/${source}/.db" + dir="${dir}/${binver}_${arch}_${plat}" + rm -f "${dir}/packages" + # Remove "pool///.db/__". + rmdir "${dir}" + # Try to remove "pool///.db". + try_rmdir "${dir%/*}" + + return 0 +} + +db_inc_references() +{ + local arch="${1}" + local plat="${2}" + local source="${3}" + local binver="${4}" + local dir= + local refs= + + dir="${base_dir}/pool/$(hash_name "${source}")/${source}/.db" + dir="${dir}/${binver}_${arch}_${plat}" + if [ -f "${dir}/references" ]; then + refs="$(cat "${dir}/references")" + refs=$(($refs + 1)) + else + refs=1 + mkdir -p "${dir}" + fi + printf '%d\n' "${refs}" >"${dir}/references" + printf '%d\n' "${refs}" + + return 0 +} + +db_dec_references() +{ + local arch="${1}" + local plat="${2}" + local source="${3}" + local binver="${4}" + local dir= + local refs= + + dir="${base_dir}/pool/$(hash_name "${source}")/${source}/.db" + dir="${dir}/${binver}_${arch}_${plat}" + if [ -f "${dir}/references" ]; then + refs="$(cat "${dir}/references")" + refs=$(($refs - 1)) + else + refs=0 + fi + if [ ${refs} -eq 0 ]; then + rm -f "${dir}/references" + else + printf '%d\n' "${refs}" >"${dir}/references" + fi + printf '%d\n' "${refs}" + + return 0 +} diff --git a/src/dir.sh b/src/dir.sh new file mode 100644 index 0000000..b72d786 --- /dev/null +++ b/src/dir.sh @@ -0,0 +1,71 @@ +# pro-archman +# lib/dir.sh +# Miscellaneous directory-related functions +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +hash_name() +{ + local name="${1}" + local hash= + + if [ "x${name}" != "x${name#lib?}" ]; then + hash="$(printf '%s\n' "${name}" | sed 's/^\(lib.\).*$/\1/')" + elif [ "x${name}" != "x${name#src-?}" ]; then + hash="$(printf '%s\n' "${name}" | sed 's/^\(src-.\).*$/\1/')" + else + hash="$(printf '%s\n' "${name}" | sed 's/^\(.\).*$/\1/')" + fi + printf '%s\n' "${hash}" + + return 0 +} + +dir_is_empty() +{ + local dir="${1}" + local ret= + local dirent= + + ret=0 + + # Patterns to match all dirents except "." and "..": + # * dirents whose names don't start with "." + # .[!.] dirents whose names start with ".", are two characters long, + # and aren't ".." + # .??* dirents whose names start with "." and are three or more + # characters long + for dirent in "${dir}/"* "${dir}/".[!.] "${dir}/".[!.] "${dir}/".??*; do + if [ -e "${dirent}" ]; then + ret=1 + break + fi + done + + return ${ret} +} + +try_rmdir() +{ + local dir="${1}" + + if dir_is_empty "${dir}"; then + rmdir "${dir}" + return ${?} + else + return 1 + fi +} diff --git a/src/garbage.sh b/src/garbage.sh new file mode 100644 index 0000000..0cf8afe --- /dev/null +++ b/src/garbage.sh @@ -0,0 +1,69 @@ +# pro-archman +# lib/garbage.sh +# Functions for garbage collection +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +collect_garbage() +{ + local cur_time= + local garbage= + local gar_time= + local dirs= + local file= + + info_v "$(get_msg 'collecting_garbage')" + + # NB: The %s format conversion specifier is not specified by POSIX, but + # it is supported by the GNU and BusyBox implementations of date. + cur_time=$(date '+%s') + + for garbage in "${base_dir}/.db/garbage/"*; do + if [ ! -f "${garbage}" ]; then + continue + fi + gar_time=${garbage##*/} + if [ ${cur_time} -lt ${gar_time} ]; then + break + fi + while read -r dirs file; do + info_v "$(get_msg 'collecting_garbage_file')" "${file}" + rm -f "${base_dir}/${file}" + while [ ${dirs} -gt 0 ]; do + file="${file%/*}" + try_rmdir "${base_dir}/${file}" + dirs=$(($dirs - 1)) + done + done <"${garbage}" + rm -f "${garbage}" + done +} + +mark_pool_garbage() +{ + local file="${1}" + local time= + + info_v "$(get_msg 'marking_garbage_file')" "${file}" + + # NB: The %s format conversion specifier is not specified by POSIX, but + # it is supported by the GNU and BusyBox implementations of date. + time=$(date '+%s') + time=$(($time + $conf_pool_gc_delay)) + + mkdir -p "${base_dir}/.db/garbage" + printf '2 %s\n' "${file}" >>"${base_dir}/.db/garbage/${time}" +} diff --git a/src/include.sh b/src/include.sh new file mode 100644 index 0000000..e83b41d --- /dev/null +++ b/src/include.sh @@ -0,0 +1,173 @@ +# pro-archman +# lib/include.sh +# Functions for including changes +# +# Copyright (C) 2013, 2014 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +_INCLUDE_CHANGES_FIELDS='Format Source Binary Version Architecture Platform +Distribution Maintainer Changed-By Date Description Changes Files' + +_include_format= +_include_source= +_include_version= +_include_distribution= +_include_files= + +include_changes() +{ + local changes="${1}" + local chan= + local dist= + local source= + local srcver= + local script= + local bvaps= + local binver= + local arch= + local plat= + local old_ver= + local files= + local size= + local sect= + local file= + local pkg= + local pool_file= + + parse_control "${changes}" _include_changes_field \ + "${_INCLUDE_CHANGES_FIELDS}" '' + if [ "x${_include_format}" != 'x1.0' ]; then + error 2 "$(get_msg 'include_unknown_changes_format')" \ + "${changes}" "${_include_format}" + fi + chan="${conf_incoming_channel}" + dist="${_include_distribution}" + source="${_include_source}" + srcver="${_include_version}" + + info "$(get_msg 'include_including')" "${source}" "${srcver}" \ + "${chan}" "${dist}" + + if [ "x${_include_files}" = 'x' ]; then + warn "$(get_msg 'include_no_files')" + return 0 + fi + + # List of (binver, arch, plat) tuples to be checked later. + script='s/[0-9][0-9]* [^ ][^ ]* [^_]*_\([^_]*\)' + script="${script}"'_\([^_]*\)_\([^_]*\)\.opk/\1 \2 \3/p' + bvaps="$(printf '%s\n' "${_include_files}" | \ + sed -n "${script}" | LC_COLLATE='C' sort | uniq)" + + # Pre-inclusion database sanity checks and updates: check for an + # existing version of the package in the suite. + old_ver="$(db_get_srcver "${chan}" "${dist}" "${source}")" + if [ "x${old_ver}" = 'x' ]; then + # New package. + db_set_srcver "${chan}" "${dist}" "${source}" "${srcver}" + elif [ "x${old_ver}" != "x${_include_version}" ]; then + # New source version. Remove the old source package from the + # suite. + remove_source_from_suite "${chan}" "${dist}" "${source}" + db_set_srcver "${chan}" "${dist}" "${source}" "${srcver}" + else + # Same source version. Hopefully different binary version, + # architecture, and/or platform. Make sure such "bvap" tuples + # are new. + while read -r binver arch plat; do + old_ver="$(db_get_binver "${chan}" "${dist}" \ + "${arch}" "${plat}" "${source}")" + if [ "x${old_ver}" = "x${binver}" ]; then + error 2 "$(get_msg 'include_bvap_exists')" \ + "${binver}" "${arch}" "${plat}" + fi + done <<-EOF + ${bvaps} + EOF + fi + + # For each (binver, arch, plat) tuple in the package changes: + # * Remove old binary packages of the same arch and plat from the + # suite. + # * Set the new binary version of packages of the arch and plat in the + # suite. + # * Set the reference count for the tuple to 1. + # This is done separately from the next loop because it must be done + # exactly once for each bvap tuple. The next loop can hit any given + # bvap tuple multiple times. + while read -r binver arch plat; do + old_ver="$(db_get_binver "${chan}" "${dist}" \ + "${arch}" "${plat}" "${source}")" + if [ "x${old_ver}" != 'x' ]; then + remove_packages_from_suite_archplat "${chan}" \ + "${dist}" "${arch}" "${plat}" "${source}" + fi + db_set_binver "${chan}" "${dist}" "${arch}" "${plat}" \ + "${source}" "${binver}" + db_inc_references "${arch}" "${plat}" "${source}" "${binver}" \ + >/dev/null + done <<-EOF + ${bvaps} + EOF + + # Include each binary package. + files='' + while read -r size sect file; do + if [ "x${file##[ ]}" = 'x' ]; then + continue + fi + IFS='_' read -r pkg binver arch plat <<-EOF + ${file%.opk} + EOF + db_add_package "${arch}" "${plat}" "${source}" "${binver}" \ + "${size}" "${sect}" "${pkg}" + pool_file="pool/$(hash_name "${source}")/${source}" + pool_file="${pool_file}/${pkg}_${binver}_${arch}_${plat}.opk" + file="$(dirname "${changes}")/${file}" + files="${files} ${file}" + cp -p "${file}" "${base_dir}/${pool_file}" + feed_add_package "${chan}" "${dist}" "${arch}" "${plat}" \ + "${sect}" "${pkg}" "${size}" "${pool_file}" + done <<-EOF + ${_include_files} + EOF + + printf '%s\n' ${files} + return 0 +} + +_include_changes_field() +{ + local name="${1}" + local value="${2}" + + case "${name}" in + 'Format') + _include_format="${value}" + ;; + 'Source') + _include_source="${value}" + ;; + 'Version') + _include_version="${value}" + ;; + 'Distribution') + _include_distribution="${value}" + ;; + 'Files') + _include_files="${value}" + ;; + esac +} diff --git a/src/index.sh b/src/index.sh new file mode 100644 index 0000000..a975e7c --- /dev/null +++ b/src/index.sh @@ -0,0 +1,193 @@ +# pro-archman +# lib/index.sh +# Functions for working with package feed indices +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +feed_add_package() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local sect="${5}" + local pkg="${6}" + local size="${7}" + local file="${8}" + local pkg_hash= + local feed_hash_idx= + local old_dir= + + info_v "$(get_msg 'feed_adding')" "${pkg}" \ + "${chan}" "${dist}" "${arch}" "${plat}" "${sect}" + + pkg_hash="$(hash_name "${pkg}")" + + # Add package metadata to feed hash index. + feed_hash_idx="${base_dir}/feeds/${chan}/${dist}/${arch}/${plat}" + feed_hash_idx="${feed_hash_idx}/${sect}/.db/${pkg_hash}" + mkdir -p "${feed_hash_idx}/info" + tar -xzOf "${base_dir}/${file}" 'control.tar.gz' | \ + tar -xzO './control' >"${feed_hash_idx}/info/${pkg}.control" + printf 'Filename: %s\nSize: %s\nMD5sum: %s\nSHA256sum: %s\n\n' \ + "../../../../../../${file}" "${size}" \ + "$(md5sum "${base_dir}/${file}" | sed 's/ .*$//')" \ + "$(sha256sum "${base_dir}/${file}" | sed 's/ .*$//')" \ + >>"${feed_hash_idx}/info/${pkg}.control" + + # Mark feed index fragment as outdated. + old_dir="${base_dir}/feeds/.db/${chan}_${dist}/${arch}_${plat}" + old_dir="${old_dir}/${sect}" + mkdir -p "${old_dir}" + >"${old_dir}/${pkg_hash}" + + return 0 +} + +feed_remove_package() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local sect="${5}" + local pkg="${6}" + local pkg_hash= + local feed_hash_idx= + local old_dir= + + info_v "$(get_msg 'feed_removing')" "${pkg}" \ + "${chan}" "${dist}" "${arch}" "${plat}" "${sect}" + + pkg_hash="$(hash_name "${pkg}")" + + # Remove package metadata from feed hash index. + feed_hash_idx="${base_dir}/feeds/${chan}/${dist}/${arch}/${plat}" + feed_hash_idx="${feed_hash_idx}/${sect}/.db/${pkg_hash}" + rm -f "${feed_hash_idx}/info/${pkg}.control" + try_rmdir "${feed_hash_idx}/info" + + # Mark feed index fragment as outdated. + old_dir="${base_dir}/feeds/.db/${chan}_${dist}/${arch}_${plat}" + old_dir="${old_dir}/${sect}" + mkdir -p "${old_dir}" + >"${old_dir}/${pkg_hash}" + + return 0 +} + +update_feeds() +{ + local suite_dirent= + local chan= + local dist= + local suite= + local archplat_dirent= + local arch= + local plat= + local archplat= + local sect_dirent= + local sect= + local manifest_entry= + local hash_dirent= + local idx= + + info_v "$(get_msg 'updating_feeds')" + + # For each suite: + for suite_dirent in "${base_dir}/feeds/.db/"*_*/; do + if [ ! -d "${suite_dirent}" ]; then + continue + fi + chan="${suite_dirent%/}" + chan="${chan##*/}" + dist="${chan##*_}" + chan="${chan%_*}" + suite="${base_dir}/feeds/${chan}/${dist}" + exec 3>"${suite}/Manifest~" + # For each archplat: + for archplat_dirent in "${suite_dirent}/"*_*/; do + if [ ! -d "${archplat_dirent}" ]; then + continue + fi + arch="${archplat_dirent%/}" + arch="${arch##*/}" + plat="${arch##*_}" + arch="${arch%_*}" + archplat="${suite}/${arch}/${plat}" + # For each section: + for sect_dirent in "${archplat_dirent}/"*/; do + if [ ! -d "${sect_dirent}" ]; then + continue + fi + sect="${sect_dirent%/}" + sect="${sect##*/}" + info_v "$(get_msg 'updating_feed')" \ + "${chan}" "${dist}" \ + "${arch}" "${plat}" "${sect}" + manifest_entry="${arch}/${plat}/${sect}" + sect="${archplat}/${sect}" + # For each package name hash: + for hash_dirent in "${sect_dirent}/"*; do + if [ ! -f "${hash_dirent}" ]; then + continue + fi + idx="${sect}/.db/${hash_dirent##*/}" + # Ensure there are still packages here. + if [ -d "${idx}/info" ]; then + cat "${idx}/info/"*.control \ + >"${idx}/Packages" + else + rm -f "${idx}/Packages" + rmdir "${idx}" + fi + rm -f "${hash_dirent}" + done + # Ensure there are still packages here. + if ! try_rmdir "${sect}/.db"; then + cat "${sect}/.db/"*/Packages \ + >"${sect}/Packages~" + mv "${sect}/Packages~" \ + "${sect}/Packages" + if ${conf_gzip}; then + gzip -9c "${sect}/Packages" \ + >"${sect}/Packages.gz" + fi + printf '%s\n' "${manifest_entry}" >&3 + else + rm -f "${sect}/Packages" \ + "${sect}/Packages.gz" + fi + rmdir "${sect_dirent}" + try_rmdir "${sect}" + done + rmdir "${archplat_dirent}" + try_rmdir "${archplat}" + try_rmdir "${archplat%/*}" + done + rmdir "${suite_dirent}" + exec 3>&- + if [ -s "${suite}/Manifest~" ]; then + mv "${suite}/Manifest~" "${suite}/Manifest" + else + rm -f "${suite}/Manifest~" "${suite}/Manifest" + rmdir "${suite}" + rmdir "${suite%/*}" + fi + done + + return 0 +} diff --git a/src/local.mk b/src/local.mk index c42c66e..c906578 100644 --- a/src/local.mk +++ b/src/local.mk @@ -1,5 +1,15 @@ -# pro-archman -# src/local.mk +pro_archman_SOURCES += \ + %reldir%/main.sh \ + %reldir%/output.sh \ + %reldir%/locale.sh \ + %reldir%/control.sh \ + %reldir%/dir.sh \ + %reldir%/db.sh \ + %reldir%/index.sh \ + %reldir%/garbage.sh \ + %reldir%/include.sh \ + %reldir%/remove.sh \ + %reldir%/suite.sh \ + %reldir%/cmd.sh -bin_srcs = \ - src/pro-archman.sh +include %reldir%/cmd/local.mk diff --git a/src/locale.sh b/src/locale.sh new file mode 100644 index 0000000..f7cc0a5 --- /dev/null +++ b/src/locale.sh @@ -0,0 +1,83 @@ +# pro-archman +# lib/locale.sh +# Locale functions +# +# Copyright (C) 2012, 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +DEFAULT_LOCALE='en_US' + +load_locale() +{ + local localedir= + + # Make sure LC_MESSAGES is set. + if [ "x${LC_MESSAGES+set}" != 'xset' ]; then + if [ "x${LC_ALL+set}" = 'xset' ]; then + LC_MESSAGES="${LC_ALL}" + elif [ "x${LANG+set}" = 'xset' ]; then + LC_MESSAGES="${LANG}" + else + LC_MESSAGES="${DEFAULT_LOCALE}" + fi + fi + + if [ "${ARCHMAN_LOCALEDIR+set}" = 'set' ]; then + localedir="${ARCHMAN_LOCALEDIR:-.}" + else + localedir="${LOCALEDIR}" + fi + + # Try to load the locale. + if ! _try_load_locale "${localedir}" \ + "${LC_MESSAGES%.*}"; then + if ! _try_load_locale "${localedir}" \ + "${LC_MESSAGES%_*}"; then + if ! _try_load_locale "${localedir}" \ + "${DEFAULT_LOCALE}"; then + warn 'Cannot load locale' + return 1 + fi + fi + fi + + return 0 +} + +get_msg() +{ + local msgid="${1}" + + eval "printf '%s' \"\${msg_${TEXTDOMAIN}_${msgid}}\"" + + return 0 +} + +_try_load_locale() +{ + local localedir="${1}" + local locale="${2}" + local ms= + + for ms in "${localedir}/${locale}/LC_MESSAGES/${TEXTDOMAIN}.ms" \ + "${localedir}/${locale}.ms"; do + if [ -f "${ms}" ]; then + . "${ms}" + return 0 + fi + done + + return 1 +} diff --git a/src/pro-archman.sh b/src/main.sh index 0cd34e9..b31e9ea 100644 --- a/src/pro-archman.sh +++ b/src/main.sh @@ -1,5 +1,3 @@ -#!@@SH@@ -# # pro-archman # src/pro-archman.sh # Main program file @@ -22,11 +20,6 @@ set -u # Constant global variables -PACKAGE_NAME='@@PACKAGE_NAME@@' -PACKAGE_VERSION='@@PACKAGE_VERSION@@' -PKGLIBDIR='@@PKGLIBDIR@@' -PKGLIBCMDDIR='@@PKGLIBCMDDIR@@' -PKGLIBCMD='@@PKGLIBCMD@@' LF=' ' OPTSTRING='hVvb:' @@ -42,49 +35,6 @@ conf_gzip= lock= exit_status= -# use() must be defined inline so it can be used to load other modules. -use() -{ - local module="${1}" - local default_dir= - local lib_subdir= - local dir= - - if [ "x${module%/*}" = "x${module}" ]; then - default_dir="${PKGLIBDIR}" - lib_subdir='' - else - case "${module%/*}" in - 'cmd') - loading_cmd="$(printf '%s' "${module##*/}" | \ - tr '[A-Z]' '[a-z]' | \ - tr -C '[a-z0-9_]' '_')" - default_dir="${PKGLIBCMDDIR}" - lib_subdir='cmd' - ;; - esac - fi - - if [ "${ARCHMAN_LIBDIR+set}" = 'set' ]; then - dir="${ARCHMAN_LIBDIR:-.}/${lib_subdir}" - else - dir="${default_dir}" - fi - - if [ -f "${dir}/${module##*/}.sm" ]; then - . "${dir}/${module##*/}.sm" - else - printf '%s: Error: Failed to load module "%s": %s\n' \ - "${0##*/}" "${module}" 'no such file or directory' >&2 - exit 2 - fi -} - -use locale -use cmd -use index -use garbage - main() { local cmd= @@ -92,7 +42,6 @@ main() init_sigs load_locale - load_cmds get_options "${@}" shift $(($OPTIND - 1)) @@ -221,5 +170,3 @@ handle_sig() exit $((128 + $sig)) fi } - -main "${@}" diff --git a/src/output.sh b/src/output.sh new file mode 100644 index 0000000..da3a7d5 --- /dev/null +++ b/src/output.sh @@ -0,0 +1,65 @@ +# pro-archman +# lib/output.sh +# Functions for printing messages +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +error() +{ + local status=${1} + local fmt="${2}" + shift 2 + + printf '%s: Error: ' "${0##*/}" >&2 + printf "${fmt}\n" "${@}" >&2 + + # In a subshell, this will have no effect, so the shell's exit status + # will be 128+SIGINT. Meh. + exit_status=${status} + kill -s INT ${$} +} + +warn() +{ + local fmt="${1}" + shift 1 + + printf '%s: Warning: ' "${0##*/}" >&2 + printf "${fmt}\n" "${@}" >&2 + + return 0 +} + +info() +{ + local fmt="${1}" + shift 1 + + printf '%s: ' "${0##*/}" >&2 + printf "${fmt}\n" "${@}" >&2 + + return 0 +} + +info_v() +{ + if ${opt_v:-false} || ${conf_verbose:-false}; then + info "${@}" + return ${?} + fi + + return 0 +} diff --git a/src/remove.sh b/src/remove.sh new file mode 100644 index 0000000..b580b1b --- /dev/null +++ b/src/remove.sh @@ -0,0 +1,85 @@ +# pro-archman +# lib/remove.sh +# Functions for removing packges +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +remove_source_from_suite() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + local arch= + local plat= + + info "$(get_msg 'removing_from_suite')" \ + "${source}" "${chan}" "${dist}" + + while read -r arch plat; do + remove_packages_from_suite_archplat \ + "${chan}" "${dist}" "${arch}" "${plat}" "${source}" + done <<-EOF + $(db_get_archplats "${chan}" "${dist}" "${source}") + EOF + + db_del_srcver "${chan}" "${dist}" "${source}" + + return 0 +} + +remove_packages_from_suite_archplat() +{ + local chan="${1}" + local dist="${2}" + local arch="${3}" + local plat="${4}" + local source="${5}" + local binver= + local refs= + local size= + local sect= + local pkg= + local file= + + info_v "$(get_msg 'removing_from_suite_archplat')" \ + "${source}" "${chan}" "${dist}" "${arch}" "${plat}" + + binver="$(db_get_binver "${chan}" "${dist}" "${arch}" "${plat}" \ + "${source}")" + if [ "x${binver}" = 'x' ]; then + return 0 + fi + db_del_binver "${chan}" "${dist}" "${arch}" "${plat}" "${source}" + refs=$(db_dec_references "${arch}" "${plat}" "${source}" "${binver}") + + while read -r size sect pkg; do + feed_remove_package "${chan}" "${dist}" "${arch}" "${plat}" \ + "${sect}" "${pkg}" + if [ ${refs} -eq 0 ]; then + file="pool/$(hash_name "${source}")/${source}" + file="${file}/${pkg}_${binver}_${arch}_${plat}.opk" + mark_pool_garbage "${file}" + fi + done <<-EOF + $(db_get_packages "${arch}" "${plat}" "${source}" "${binver}") + EOF + + if [ ${refs} -eq 0 ]; then + db_del_packages "${arch}" "${plat}" "${source}" "${binver}" + fi + + return 0 +} diff --git a/src/suite.sh b/src/suite.sh new file mode 100644 index 0000000..da4a02d --- /dev/null +++ b/src/suite.sh @@ -0,0 +1,96 @@ +# pro-archman +# lib/suite.sh +# Functions for working with suites +# +# Copyright (C) 2013 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +copy_suite() +{ + local src_chan="${1}" + local src_dist="${2}" + local dst_chan="${3}" + local dst_dist="${4}" + + info "$(get_msg 'suite_copying')" \ + "${src_chan}" "${src_dist}" "${dst_chan}" "${dst_dist}" + + remove_suite "${dst_chan}" "${dst_dist}" + + db_foreach_source "${src_chan}" "${src_dist}" _suite_copy_source \ + "${dst_chan}" "${dst_dist}" +} + +remove_suite() +{ + local chan="${1}" + local dist="${2}" + + info "$(get_msg 'suite_removing')" \ + "${chan}" "${dist}" + + db_foreach_source "${chan}" "${dist}" _suite_remove_source +} + +_suite_copy_source() +{ + local src_chan="${1}" + local src_dist="${2}" + local source="${3}" + local dst_chan="${4}" + local dst_dist="${5}" + local srcver= + local arch= + local plat= + local binver= + local size= + local sect= + local pkg= + local pool_file= + + srcver="$(db_get_srcver "${chan}" "${dist}" "${source}")" + db_set_srcver "${dst_chan}" "${dst_dist}" "${source}" "${srcver}" + + while read -r arch plat; do + binver="$(db_get_binver "${src_chan}" "${src_dist}" \ + "${arch}" "${plat}" "${source}")" + db_set_binver "${dst_chan}" "${dst_dist}" "${arch}" "${plat}" \ + "${source}" "${binver}" + db_inc_references "${arch}" "${plat}" "${source}" "${binver}" \ + >/dev/null + while read -r size sect pkg; do + pool_file="pool/$(hash_name "${source}")/${source}" + pool_file="${pool_file}/${pkg}_${binver}" + pool_file="${pool_file}_${arch}_${plat}.opk" + feed_add_package "${dst_chan}" "${dst_dist}" \ + "${arch}" "${plat}" \ + "${sect}" "${pkg}" "${size}" "${pool_file}" + done <<-EOF + $(db_get_packages "${arch}" "${plat}" \ + "${source}" "${binver}") + EOF + done <<-EOF + $(db_get_archplats "${src_chan}" "${src_dist}" "${source}") + EOF +} + +_suite_remove_source() +{ + local chan="${1}" + local dist="${2}" + local source="${3}" + + remove_source_from_suite "${chan}" "${dist}" "${source}" +} -- cgit v0.9.1