From 575768d7c68fbbc674505ee0d56aac3cddd0f247 Mon Sep 17 00:00:00 2001 From: Esteban Carnevale Date: Sun, 21 Dec 2014 11:56:49 -0300 Subject: libredbdiff: Many improvements * cleaner output format * multiple non-default repositories Parabola: libre pcr libre-multilib nonprism Arch: multilib * a single Parabola repository can be specified as argument to restrict the comparison to that repository * support expac 4 extra/expac 4.2 has a bug, so pcr/expac-relative 4.2-parabola1 or later is needed * detection of missing files * code style * move code to functions * usage text and messages --- src/abslibre-tools/libredbdiff | 285 +++++++++++++++++++++++++++++++++-------- 1 file changed, 232 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/abslibre-tools/libredbdiff b/src/abslibre-tools/libredbdiff index ff3b4a1..2bc8a5a 100755 --- a/src/abslibre-tools/libredbdiff +++ b/src/abslibre-tools/libredbdiff @@ -34,10 +34,23 @@ 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 @@ -54,6 +67,14 @@ downloadfile() { 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 @@ -71,7 +92,7 @@ setmirror() { if [[ $init ]] && [[ $mirror ]]; then mirrorescaped="${mirror//./\\.}" mirrorescaped="${mirrorescaped//\$/\\$}" - msg "Setting %q as the only enabled %s mirror." "${mirror}" "${distro}" + msg2 "Setting %s as the only enabled %s mirror." "${mirror}" "${distro}" sed -i 's|^#\(Server = '"${mirrorescaped}"'\)$|\1|' "${mirrorlist}" fi } @@ -79,35 +100,150 @@ setmirror() { filenotfound() { local file=$1 if [[ ! -r $1 ]]; then - die "Could not read %q. Nothing done." "$file" - plain "It may be necessary to run %q without arguments as root to initialize %s." "$cmd" "$name" + 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 } -comparepkgs() { +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 +} + +expac_version_test() { + if ! pkgname="$(pacman -Qoq expac 2> /dev/null)" ; then + die "The command expac could not be found installed. The package \ +pcr/expac-relative 4-2.parabola1 (or later) must be installed." + elif [[ $pkgname == expac-git ]] ; then + true + elif [[ $pkgname == expac-relative ]] ; then + expac_ver="$(expac %v expac-relative)" + if [[ $(vercmp "${expac_ver}" 4-2.parabola1) == -1 ]] ; then + die "The version of expac-relative installed on the system is \ +lower than needed." + fi + else + die "expac command must be provided by pcr/expac-relative version \ +4-2.parabola1 (or later). This package must be installed." + fi +} + +compare_pkgs() { + local cmp if [[ ${verarch[$pkgname]} ]] ; then cmp=$(vercmp "${ver[$pkgname]}" "${verarch[$pkgname]}") if [[ $cmp -lt 0 ]]; then - msg "%s needs update from the Arch package of the same name. Versions: %s - %s" "${pkgname}" "${ver[$pkgname]}" "${verarch[$pkgname]}" + 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 - msg "%s may need update from provide candidate %s. Versions: %s - %s" "${pkgname}" "${provide}" "${ver[$pkgname]}" "${verarch[$provide]}" + printf "${printf_format}" \ + 'p' \ + "${pkgname}" \ + "${provide}" \ + "${ver[$pkgname]}" \ + "${verarch[$provide]}" fi fi done else - msg "Could not find candidate to compare %s" "${pkgname}" + 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 [libre] packages that need to be updated from Arch repositories.' + 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." 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 @@ -116,68 +252,83 @@ usage() { print 'Options:' flag '-n' "Don't update anything, just compare already downloaded files." flag '-h' 'Show this message' + echo + print "Output format: + type_character parabola_pkgname (arch_pkgname) parabola_pkgver - (arch_pkgver)" + echo + print "Type characters: + = Arch package with the same pkgname and greater pkgver was found + 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 + 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) UPDATE=0;; - -h) usage; return 0;; + -n|--noupdate) + UPDATE=0 + ;; + -h|--help) + usage + return 0 + ;; *) - error "Bad arguments. Nothing done." - usage >&2 - return 1 + repo_test "$arg" + repo_arg="$arg" + break ;; esac done if (( $UPDATE )) ; then if [[ $EUID != 0 ]]; then - die "To initialize $name or update %s pacman databases, the script must be run as root. Nothing done." "$name" + die "To initialize %s or update %s pacman \ +databases, %s must be run as root (without arguments). Nothing done." \ + "$name" \ + "$name" \ + "$cmd" fi - if ! [[ -d "$baseconfpath" && -d "$basedbpath" && -d "$dbpath" && -d "$dbpatharch" && -e "${conffile}" && -e "${conffilearch}" && -e "${mirrorlist}" && -e "${mirrorlist}" ]]; then - msg "%s files are missing. Initializing." "${name}" + 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" - createdir "$dbpath" - createdir "$dbpatharch" - downloadfile "${conffile}" "https://projects.parabola.nu/abslibre.git/plain/libre/pacman/pacman.conf.x86_64" \ - "Downloading Parabola %q" pacman.conf + initialize - downloadfile "${conffilearch}" "https://projects.archlinux.org/svntogit/packages.git/plain/pacman/trunk/pacman.conf.x86_64" \ - "Downloading Arch %q" pacman.conf - if [[ $? == 255 ]] ; then - msg "Setting Arch mirrorlist file in %q" "${conffilearch}" - sed -i "s|/etc/pacman\.d/mirrorlist$|$baseconfpath/mirrorlist.archlinux|" "${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" + 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}" -b "${dbpath}" -Sy || die "Failed to synchronize pacman database for Parabola. Exiting." + 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." + 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" + msg "%s pacman databases are updated. %s is ready. Run %q -n to \ +print results." "$name" "$name" "$cmd" return 0 else filenotfound "${dbpath}" @@ -186,21 +337,49 @@ main() { filenotfound "${conffilearch}" filenotfound "${mirrorlist}" filenotfound "${mirrorlistarch}" - fi - unset provides ver verarch - declare -gA provides ver verarch + 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 + + expac_version_test + + 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} - while read -a line; do - verarch["${line[0]}"]="${line[1]}" - done < <(pacman --dbpath "${dbpatharch}" --config "${conffilearch}" -Ss | grep -v '^ ' | awk -F/ '{print $2}') + 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} - while read -a line; do - ver[${line[0]}]="${line[1]}" - provides[${line[0]}]="${line[@]:2}" - pkgname=${line[0]} - comparepkgs - done < <(expac -b "${dbpath}" -c "${conffile}" -Ss '%r/%n %v %S' | awk -F/ '$1 == "libre" {print $2}') + if [[ ${repo_arg} ]] ; then + print_cmp "${repo_arg}" + else + for repo in ${repos} ; do + print "[$repo]" + print_cmp "$repo" + done + fi + fi } main "$@" -- cgit v1.2.2