#!/bin/bash # Queries the ABS # License: GPL3 ## TODO # * Add license text # * Create symlinks from pkgbase to pkgname[@] for easy package finding ## GOALS # * Have a searchable database of PKGBUILD metadata # * Have an interface for source-only builds # * Possibility to hook up ABS dirs besides ABSROOT (low priority) # * Tell updates and non available binary packages (working on this) source /etc/abs.conf source /etc/libretools.conf if [ ! -w "$TORUPATH" ]; then error "Toru's path isn't writable. Please check $TORUPATH" exit 1 fi # TODO move to common functions function in_array { # usage : in_array( $needle, $haystack ) [[ $2 ]] || return 1 # Not found local needle=$1; shift local item for item in "$@"; do [[ ${item#@} = $needle ]] && return 0 # Found done return 1 # Not Found } # Stores the lastsync date lastsync() { [ -e ${lastsyncfile} -a ! -w ${lastsyncfile} ] && { error "The sync date can't be saved. ${lastsyncfile} isn't writable." return 1 } date +%s > ${lastsyncfile} touch ${lastsyncfile} } # Saves contents on a named cache # $1 cache name (repo) # $2+ contents store_cache() { cache=$1; shift [ -z "$cache" ] && return 1 cat $@ > ${TORUPATH}/${cache}.cache return $? } # Return cache contents # $1 cache name read_cache() { [ ! -e "$1" ] && return 1 cat ${TORUPATH}/${1}.cache return $? } ## # usage : get_full_version( $epoch, $pkgver, $pkgrel ) # return : full version spec, including epoch (if necessary), pkgver, pkgrel ## get_full_version() { if [[ $1 -eq 0 ]]; then # zero epoch case, don't include it in version echo $2-$3 else echo $1:$2-$3 fi } # Outputs an ordered package-fullpkgver array print_package_array() { echo "$@" | tr " " "\n" | sort -u } # Gets repo.db contents (unordered) # $1 repo get_db_contents() { [ ! -r /var/lib/pacman/sync/$1.db ] && return 0 bsdtar -tf /var/lib/pacman/sync/$1.db | cut -d'/' -f1 | sort -u } # Get the pkgname # pkgname from pkgver separator can be either '-' or ' ' extract_pkgname() { echo "$@" | tr " " "\n" | sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/" } # Get all the pkgnames from a file # pkgname from pkgver separator can be either '-' or ' ' extract_pkgname_from_file() { sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/" $1 } # Split pkgnames from pkgvers split_pkgname_from_pkgver() { sed "s/^\(.\+\)-\([^-]\+-[^-]\+\)$/\1 \2/" $1 } # Get the fullpkgver # pkgname from pkgver separator can be either '-' or ' ' extract_fullpkgver() { echo "$@" | tr " " "\n" | sed "s/^.\+[ -]\([^-]\+-[^-]\+\)$/\1/" } # Updates the database by finding all PKGBUILDS # Workflow: # * Find all PKGBUILDs on the ABS repo specified # * Get all packages already on package repos # * Compare them # Args: update() { # The PKGBUILDs found local pkgbuilds=() # The list of pkgname-fullpkgver local packages_in_abs=() local packages_in_sync=() local need_update=() # Traverse all specified repos for _repo in $@; do if ! in_array ${_repo} ${REPOS[@]}; then warning "You don't have access to this repo (check REPOS at libretools.conf)" continue fi # Find all the PKGBUILDs newer than the last update # Update newer, otherwise everything if [[ $force = true || ! -e ${lastsyncfile} ]]; then $quiet || warning "Forcing upgrade" pkgbuilds=($(find ${_repo} -maxdepth 2 -type f -name 'PKGBUILD')) else pkgbuilds=($(find ${_repo} -maxdepth 2 -type f -name 'PKGBUILD' -newer ${lastsyncfile})) packages_in_abs=($(read_cache ${_repo})) $quiet || msg2 "Getting ${#packages_in_abs[@]} packages from cache" fi # Inform how many PKGBUILDS were found and quit immediately if none $quiet || msg "Found $((${#pkgbuilds[*]}-1)) PKGBUILDs to update" if [ ${#pkgbuilds[*]} -eq 1 ]; then $quiet || msg2 "There's nothing to be done. Phew!" exit 0 fi # Traverse all found PKGBUILDs for _pkgbuild in ${pkgbuilds[@]}; do # The repo name is guessed # You *must* use repo/pkgbase structure _pkgpath=$(dirname "${_pkgbuild}") _pkgbase=$(basename "${_pkgpath}") # Load PKGBUILD's metadata source ${_pkgbuild} # We won't need this unset build package url md5sums install pkgdesc backup options # TODO fill a license list unset license # TODO create source tarballs? unset mksource # TODO solve dependency tree? unset depends makedepends for _pkg in ${pkgname[@]}; do # Keep removing unneeded stuff unset package_${_pkg} >/dev/null 2>&1 # Fill the list of packages to find packages_in_abs+=($_pkg-$(get_full_version ${epoch:-0} $pkgver $pkgrel)) done # end pkgnames unset pkgbase pkgname pkgver pkgrel source epoch done # end pkgbuilds # Get repo database contents packages_in_sync=($(get_db_contents ${_repo})) # Drops arrays into files print_package_array "${packages_in_abs[@]}" > ${TMPDIR}/packages_in_abs print_package_array "${packages_in_sync[@]}" > ${TMPDIR}/packages_in_sync unset packages_in_abs package_in_sync # Use a different separator for pkgnames and pkvers # so we can join them by pkgname split_pkgname_from_pkgver ${TMPDIR}/packages_in_abs | sort -k1b,1 > ${TMPDIR}/in_abs split_pkgname_from_pkgver ${TMPDIR}/packages_in_sync | sort -k1b,1 > ${TMPDIR}/in_sync $quiet || msg "This packages are available to update" # Join both files by pkgname, the end result is: # pkgname syncver absver join ${TMPDIR}/in_sync ${TMPDIR}/in_abs | \ while read need_line; do _pkg=$(echo "${need_line}" | cut -d' ' -f1) _syncver=$(echo "${need_line}" | cut -d' ' -f2) _absver=$(echo "${need_line}" | cut -d' ' -f3) # If the versions differ we need an update if [ "${_syncver}" != "${_absver}" ]; then $quiet || msg2 "$_pkg update from $_syncver to $_absver" $quiet && echo "$_pkg" fi done # end need_line unset _pkg _syncver _absver need_line # Save the cache store_cache ${_repo} ${TMPDIR}/packages_in_abs done # end repos lastsync } # Find all the packages that are missing from the repo dbs (aka not built) missing() { true } ## MAIN commands=() repos=() quiet=false force=false while getopts 'hqfum' arg; do case $arg in h) usage; exit 0 ;; q) quiet=true ;; f) force=true ;; u) commands+=(update);; m) commands+=(missing);; esac shift $((OPTIND-1)) done # This is the syncfile, stores the last date as content and mtime lastsyncfile=${TORUPATH}/lastsync TMPDIR=$(mktemp -d) [[ -z ${TMPDIR} ]] && exit 1 # TODO this is all for debugging msg2 "force: $force quiet: $quiet repos: $@ commands: ${commands[@]}" msg2 "read lastsync: $([ -e $lastsyncfile ])" ${commands[0]} ${@} #rm -rf ${TMPDIR} exit $?