summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd.sh116
-rw-r--r--src/cmd/copy-suite.sh53
-rw-r--r--src/cmd/help.sh46
-rw-r--r--src/cmd/include.sh39
-rw-r--r--src/cmd/local.mk8
-rw-r--r--src/cmd/process-incoming.sh51
-rw-r--r--src/cmd/remove-suite.sh45
-rw-r--r--src/cmd/remove.sh46
-rw-r--r--src/cmd/version.sh32
-rw-r--r--src/control.sh130
-rw-r--r--src/db.sh288
-rw-r--r--src/dir.sh71
-rw-r--r--src/garbage.sh69
-rw-r--r--src/include.sh173
-rw-r--r--src/index.sh193
-rw-r--r--src/local.mk18
-rw-r--r--src/locale.sh83
-rw-r--r--src/main.sh (renamed from src/pro-archman.sh)53
-rw-r--r--src/output.sh65
-rw-r--r--src/remove.sh85
-rw-r--r--src/suite.sh96
21 files changed, 1703 insertions, 57 deletions
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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+#
+# 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/<hash>/<source>".
+ rmdir "${dir}"
+ # Try to remove ".../.db/<hash>" 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/<hash>/<source>/<arch>_<plat>".
+ 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/<hash>/<source>/.db/<binver>_<arch>_<plat>".
+ rmdir "${dir}"
+ # Try to remove "pool/<hash>/<source>/.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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+_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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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}"
+}