diff options
Diffstat (limited to 'src/abslibre-tools/libredbdiff')
-rwxr-xr-x | src/abslibre-tools/libredbdiff | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/src/abslibre-tools/libredbdiff b/src/abslibre-tools/libredbdiff new file mode 100755 index 0000000..09c7ad1 --- /dev/null +++ b/src/abslibre-tools/libredbdiff @@ -0,0 +1,360 @@ +#!/usr/bin/env bash +name="Libredbdiff" + +# Copyright (C) 2014 Esteban Carnevale <alfplayer@mailoo.org> +# Copyright (C) 2014 Luke Shumaker <lukeshu@sbcglobal.net> +# +# License: GNU GPLv3+ +# +# 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/>. + +baseconfpath="/etc/libredbdiff" +basedbpath="/var/lib/libredbdiff" + +conffile="$baseconfpath/pacman.conf.parabola" +conffilearch="$baseconfpath/pacman.conf.archlinux" + +dbpath="$basedbpath/pacman.parabola" +dbpatharch="$basedbpath/pacman.archlinux" + +mirrorlist="$baseconfpath/mirrorlist.parabola" +mirrorlistarch="$baseconfpath/mirrorlist.archlinux" + +mirror='http://repo.parabola.nu/$repo/os/$arch' +mirrorarch='http://mirrors.kernel.org/archlinux/$repo/os/$arch' + +repos="libre pcr libre-multilib nonprism" + +field_pkgname_parabola=30 +field_pkgname_arch=30 + + +. libremessages + +cmd="${0##*/}" + +arch_packages_tmp="/tmp/${cmd}.arch-packages" +parabola_packages_tmp="/tmp/${cmd}.parabola-packages" + +field_pkgname_total="$((${field_pkgname_parabola} + ${field_pkgname_arch}))" +printf_format="%s %-${field_pkgname_parabola}s%-${field_pkgname_arch}s %s | %s\n" +printf_format_noarch="%s %-${field_pkgname_total}s %s\n" + +downloadfile() { + local outfile=$1 + local url=$2 + local mesg=("${@:3}") + if [[ ! -e $outfile ]] ; then + msg "${mesg[@]}" + if wget -q "$url" -O "$outfile"; then + return 255 + else + die "Failed to download %q. Exiting." "$outfile" + fi + elif [[ $init ]]; then + warning "%q already exists. Skipping." "$outfile" + fi +} + +enablerepo() { + repo="$1" + conffile_arg="$2" + msg2 "Enabling repo %q in %q" "$repo" "${conffile_arg}" + sed -i "s/\#\[$repo\]/[$repo]/" "${conffile_arg}" + sed -i "\/\[$repo\]/,+1 s/#Include/Include/" "${conffile_arg}" +} + +createdir() { + local dir=$1 + if [[ ! -e $dir ]] ; then + msg "Creating directory %q" "$dir" + mkdir -- "$1" || die "Failed to create directory %q. Exiting." "$dir" + elif [[ $init ]]; then + warning "%q already exists. Skipping." "$dir" + fi +} + +setmirror() { + local distro="$1" + local mirror="$2" + local mirrorlist="$3" + if [[ $init ]] && [[ $mirror ]]; then + mirrorescaped="${mirror//./\\.}" + mirrorescaped="${mirrorescaped//\$/\\$}" + msg2 "Setting %s as the only enabled %s mirror." "${mirror}" "${distro}" + sed -i 's|^#\(Server = '"${mirrorescaped}"'\)$|\1|' "${mirrorlist}" + fi +} + +filenotfound() { + local file=$1 + if [[ ! -r $1 ]]; then + error "Could not read %q." "$file" + die "Nothing done. It may be necessary to run %q without \ +arguments as root to initialize %s." "$cmd" "$name" + fi +} + +initialize() { + createdir "$baseconfpath" + createdir "$basedbpath" + + downloadfile \ + "${conffile}" \ + "https://projects.parabola.nu/abslibre.git/plain/libre/pacman/pacman.conf.x86_64" \ + "Downloading Parabola %q" \ + pacman.conf + if [[ $? == 255 ]] ; then + msg2 "Setting DBPath in %q" "${conffile}" + sed -i "s|^#DBPath .*|DBPath = ${dbpath}|" "${conffile}" + enablerepo nonprism "${conffile}" + enablerepo pcr "${conffile}" + enablerepo libre-multilib "${conffile}" + enablerepo multilib "${conffile}" + fi + + downloadfile \ + "${conffilearch}" \ + "https://projects.archlinux.org/svntogit/packages.git/plain/pacman/trunk/pacman.conf.x86_64" \ + "Downloading Arch %q" \ + pacman.conf + if [[ $? == 255 ]] ; then + msg2 "Setting DBPath in %q" "${conffilearch}" + sed -i "s|^#DBPath .*|DBPath = ${dbpatharch}|" "${conffilearch}" + msg2 "Setting Arch mirrorlist file in %q" "${conffilearch}" + sed -i "s|/etc/pacman\.d/mirrorlist$|$baseconfpath/mirrorlist.archlinux|" \ + "${conffilearch}" + enablerepo multilib "${conffilearch}" + fi + + downloadfile \ + "${mirrorlist}" \ + "https://repo.parabola.nu/mirrorlist.txt" \ + "Downloading Parabola %q" \ + mirrorlist + if [[ $? == 255 ]] ; then + sed -i 's|^Server|#Server|' "${mirrorlist}" + setmirror "Parabola" "$mirror" "$mirrorlist" + fi + + downloadfile \ + "${mirrorlistarch}" \ + "https://projects.archlinux.org/svntogit/packages.git/plain/pacman-mirrorlist/trunk/mirrorlist" \ + "Downloading Arch %q" \ + mirrorlist + if [[ $? == 255 ]] ; then + setmirror "Arch" "$mirrorarch" "$mirrorlistarch" + fi +} + +repo_test() { + for repo in ${repos} ; do + if [[ $repo == $1 ]] ; then + found=1 + return 0 + fi + done + if [[ $found != 1 ]] ; then + die "The specified Parabola repo \"%s\" cannot be compared. It's not in the list of repos in the configuration variable \"repos\"." "$1" + fi +} + +compare_pkgs() { + local cmp + if [[ ${verarch[$pkgname]} ]] ; then + cmp=$(vercmp "${ver[$pkgname]}" "${verarch[$pkgname]}") + if [[ $cmp -lt 0 ]]; then + printf "${printf_format}" \ + '=' \ + "${pkgname}" \ + "" \ + "${ver[$pkgname]}" \ + "${verarch[$pkgname]}" + fi + elif [[ ${provides[$pkgname]} ]]; then + for provide in "${provides[$pkgname]}"; do + if [[ ${verarch["$provide"]} ]]; then + cmp=$(vercmp "${ver[$pkgname]}" "${verarch[$provide]}") + if [[ $cmp -lt 0 ]]; then + printf "${printf_format}" \ + 'p' \ + "${pkgname}" \ + "${provide}" \ + "${ver[$pkgname]}" \ + "${verarch[$provide]}" + fi + fi + done + else + printf "${printf_format_noarch}" \ + 'o' \ + "${pkgname}" \ + "${ver[$pkgname]}" + fi +} + +print_cmp() { + local repo="$1" + awk -F/ -v repo="$repo" \ + '$1 == repo {print $2}' \ + ${parabola_packages_tmp} | \ + while read -a line ; do + ver["${line[0]}"]="${line[1]}" + provides[${line[0]}]="${line[@]:2}" + pkgname=${line[0]} + compare_pkgs + done +} + +usage() { + print "Usage: %q [-n|-h]" "$cmd" + print 'Show packages that need to be updated from Arch repositories.' + echo + prose "Compares packages in Parabola repositories. Packages from + all configured Parabola repositories are compared. A Parabola + repository name can be specified as argument to compare only + packages in that repository." + echo + prose "The default mode of operation is to download/update all necessary + files for comparison, but not compare them. Specify the \`-n\` + flag to not download anything, but to compare already downloaded + files." + echo + print 'Options:' + flag '-n' "Don't update anything, just compare already downloaded files." + flag '-h' 'Show this message' + echo + print "Output format:" + print "type_character parabola_pkgname (arch_pkgname) parabola_pkgver - (arch_pkgver)" + echo + print "Type characters:" + flag '=' "Arch package with the same pkgname and greater pkgver was found" + flag 'p' "Arch package with pkgname equal to a provide and greater + pkgver was found In this case arch_pkgname is a provide of + parabola_pkgname" + flag 'o' "No Arch package with the same pkgname or with pkgname equal to + a provide was found" +} + +main() { + local UPDATE=1 + local arg + local repo_arg + + for arg in "$@"; do + case "$arg" in + -n|--noupdate) + UPDATE=0 + ;; + -h|--help) + usage + return 0 + ;; + *) + repo_test "$arg" + repo_arg="$arg" + break + ;; + esac + done + + if (( $UPDATE )) ; then + if [[ $EUID != 0 ]]; then + die "To initialize %s or update %s pacman databases, %s must be run as root (without arguments). Nothing done." \ + "$name" \ + "$name" \ + "$cmd" + fi + + if ! [[ -e "${conffile}" && \ + -e "${conffilearch}" && \ + -e "${mirrorlist}" && \ + -e "${mirrorlist}" ]]; then + warning "At least one %s configuration file is missing." \ + "${name}" + msg "Downloading and preparing missing configuration files." + init=1 + fi + + createdir "$baseconfpath" + createdir "$basedbpath" + + initialize + + if ! [[ -d "$dbpath" && \ + -d "$dbpatharch" ]]; then + warning "At least one %s pacman DB directory is missing. Synchronizing %s DB files." \ + "${name}" "${name}" + fi + + createdir "$dbpath" + msg "Synchronizing %s pacman databases for Parabola" "$name" + pacman --config "${conffile}" -Sy || + die "Failed to synchronize pacman database for Parabola. Exiting." + + createdir "$dbpatharch" + msg "Synchronizing %s pacman databases for Arch" "$name" + pacman --config "${conffilearch}" -b "${dbpatharch}" -Sy || + die "Failed to synchronize pacman database for Arch. Exiting." + + msg "%s pacman databases are updated. %s is ready. Run %q -n to print results." \ + "$name" "$name" "$cmd" + return 0 + else + filenotfound "${dbpath}" + filenotfound "${dbpatharch}" + filenotfound "${conffile}" + filenotfound "${conffilearch}" + filenotfound "${mirrorlist}" + filenotfound "${mirrorlistarch}" + + unset provides ver verarch + declare -gA provides ver verarch + + if ! [[ -d "$dbpath" && \ + -d "$dbpatharch" ]]; then + die "At least one %s pacman DB directory is missing. To update %s pacman databases, %s must be run as root. Nothing done." \ + "$name" \ + "$name" \ + "$cmd" + fi + + pacman --config "${conffilearch}" -Ss | \ + grep -v '^ ' | \ + awk -F/ '{print $2}' \ + > ${arch_packages_tmp} || \ + die "pacman command to get Arch package data has failed. Exiting." + chmod 777 ${arch_packages_tmp} + + while read -a line; do + verarch["${line[0]}"]="${line[1]}" + done < ${arch_packages_tmp} + + expac --config "${conffile}" -S '%r/%n %v %S' \ + > ${parabola_packages_tmp} || \ + die "expac command to get Parabola package data has failed. Exiting." + chmod 777 ${parabola_packages_tmp} + + if [[ ${repo_arg} ]] ; then + print_cmp "${repo_arg}" + else + for repo in ${repos} ; do + echo "[$repo]" + print_cmp "$repo" + done + fi + fi +} + +main "$@" |