#!/bin/bash ###################################################################### # apacman - AUR wrapper forked from packer version="3.1" # Copyright OS Hazard # # New Features: # * Build old AUR releases from source (pkgname~, pkgname==ver) # * Merge fix for aurbar length # * Clean build files # * Clean temp files # * --savedir , --savedir= # * Install AUR packages offline # * --testing for unit testing purposes only # * Regex matching for searching packages # * Regex matching for installing packages # * -P patched AUR passthrough for pkgfile # * Save installed AUR package metadata to database # * Enabled --progress by default # * Fix CLI switch precedence over config file # * Improved support for virtual packages # * Improved -U handling # * Built-in ABS support (improved) # * -W View AUR comments (WIP) # * Signed package support (improved) # * Split package support # * AUR4 support # * Config file support # * Workaround for running as root # * Saves AUR packages to /var/cache/apacman/pkg # * Uses AUR package cache directory if applicable # * --asdeps install AUR packages non-explicitly # * --asexplicit install AUR packages explicitly # * --edit always ask to edit PKGBUILD # * --gendb generate AUR database files # * --keepkeys do not remove imported PGP keys # * --purgekeys remove imported PGP keys # * --legacy backwards compatability for AUR3 (deprecated) # * --progress transaction status in terminal titlebar # * --nodatabase do not store AUR database # * --nosource for security do not source PKGBUILDs (WIP) # * --noprogress no transaction status in titlebar # * --notify transaction status in notification # * --buildonly create but do not install packages # * --nofail do not continue if a package fails to build # * --purgebuild remove unneeded build dependencies # * --skiptest skips installing check() unit test packages # * --config specify alternate config file (default: /etc/apacman.conf) # * --verbose turns on verbose output # * -L list installed packages by size # * --noaur do not actions for aur # * --warn treat errors as non-fatal warnings # * --needed does not install up-to-date packages # * --ignorearch ignores architectures specified in PKGBUILD # * --skipcache skips check for pre-built package in cache directory # * --cachevcs installs cached VCS (git, svn, hg) packages newer than AUR PKGBUILDs # * partial passthrough for -R, -Q, -T and -U parameters ###################################################################### # Copyright Matthew Bruenig # 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 . [[ $PACMAN ]] || PACMAN="pacman" pacmanbin="/usr/bin/pacman" makepkgconf='/etc/makepkg.conf' usermakepkgconf="$HOME/.makepkg.conf" pacmanconf='/etc/pacman.conf' apacmanconf='/etc/apacman.conf' gpgconf='/etc/pacman.d/gnupg/gpg.conf' downdir='/var/cache/pacman/pkg' savedir='/var/cache/apacman/pkg' database='/var/lib/apacman' pacmandb='/var/lib/pacman/sync/aur.db' pkgfiledb='/var/cache/pkgfile/aur.files' localrepo='aur' builddir="${TMPDIR:-/tmp}/pkgbuild-$UID" tmpdir="${TMPDIR:-/tmp}/apacmantmp-$UID" testdir="${TMPDIR:-/tmp}/apacman-testing" editor="vi" [[ $EDITOR ]] && editor="$EDITOR" pager="less -R" [[ $PAGER ]] && pager="$PAGER" RPCURL="https://aur.archlinux.org/rpc/?v=5&type" PKGURL="https://aur.archlinux.org" WEBURL="https://www.archlinux.org" ABSURL="rsync.archlinux.org" legacy="0" if [[ -t 1 && ! $COLOR = "NO" ]]; then COLOR1='\e[1;39m' COLOR2='\e[1;32m' COLOR3='\e[1;35m' COLOR4='\e[1;36m' COLOR5='\e[1;34m' COLOR6='\e[1;33m' COLOR7='\e[1;31m' ENDCOLOR='\e[0m' S='\\' fi _WIDTH="$(stty size | cut -d ' ' -f 2)" trap ctrlc INT ctrlc() { echo exit 1 } err() { echo -e "$1" [[ "$warn" == 1 ]] || exit 3 } dne() { echo -e "$1" [[ "$warn" == 1 ]] || exit 5 } invalid() { echo -e "${COLOR7}error:${ENDCOLOR} invalid option \`$1'" [[ $nofail ]] && exit 2 } progress() { [[ $progress == 1 || $progress == 3 ]] && echo -en "\033]2;$@\007" [[ $progress == 2 || $progress == 3 ]] && notify-send "$@" } deptest() { type -p $1 &>/dev/null } version() { pacver=$($pacmanbin -V 2>/dev/null | grep -o "Pacman v.*") echo " === = = ===== apacman v${version} - forked from packer" echo " = = = = = = ${pacver}" echo ' ===== = = ====' echo ' = = = = = = This program may be freely redistributed under' echo ' = = === = = the terms of the GNU General Public License.' exit } usage() { echo 'usage: apacman [option] [package] [package] [...]' echo 'If no operation is specified, searches and installs packages by number' echo echo 'OPERATIONS' echo ' -S - installs package' echo ' -Syu|-Su - updates all packages, also takes -uu and -yy options' echo ' -Ss|-Ssq - searches for package' echo ' -Si - outputs info for package' echo ' -G - download and extract aur tarball only' echo ' -L - list installed packages by size' echo ' -P - passthrough for pkgfile command' echo ' -W - view web comments for package' echo echo 'OPTIONS' echo ' --asdeps - install AUR packages marked as dependencies' echo ' --asexplicit - install AUR packages marked as explicit' echo ' --auronly - only do actions for AUR' echo ' --buildonly - create but do not install packages' echo ' --config - specify alternate config file (default: /etc/apacman.conf)' echo ' --cachevcs - installs cached VCS packages newer than AUR PKGBUILDs' echo ' --devel - update VCS (git, svn, hg) packages during -Su' echo ' --edit - always ask to edit PKGBUILD' echo ' --gendb - generate AUR database files' echo ' --ignore - takes a comma-separated list of packages to ignore' echo ' --ignorearch - ignore a missing or incomplete architecture field' echo ' --keepkeys - do not remove imported PGP keys' echo ' --legacy - uses AUR3.0 instead of AUR4.0 (deprecated)' echo ' --needed - do not install up-to-date packages' echo ' --noaur - do not actions for AUR' echo ' --noconfirm - do not prompt for any confirmation' echo ' --nodatabase - do not store AUR database' echo ' --noedit - do not prompt to edit files' echo ' --nofail - do not continue if a package fails to build' echo ' --noprogress - no transaction status in titlebar' echo ' --nosource - do not source PKGBUILDs (WIP)' echo ' --notify - transaction status in notification' echo ' --preview - edit pkgbuild before sourcing' echo ' --progress - transaction status in terminal titlebar' echo ' --purgebuild - remove unneeded build dependencies' echo ' --purgekeys - remove trusted PGP keys' echo ' --quickcheck - check for updates and exit' echo ' --quiet - only output package name for searches' echo ' --savedir - takes a path as the cache directory' echo ' --skipcache - skips check for pre-built package in cache directory' echo ' --skipinteg - when using makepkg, do not check md5s' echo ' --skiptest - when using makepkg, do not parse check() test deps' echo ' --testing - for unit testing purposes only' echo ' --warn - treat errors as non-fatal warnings' echo ' -v - turns on verbose output' echo ' -V - display version' echo ' -h - outputs this message' exit } varstatus() { val=$(eval echo \$$1) if [ "$val" == 1 ]; then echo -e "${COLOR1}$1${ENDCOLOR}" | awk '{printf "%-25s %-40s\n",$1,": yes"}'; elif [ "$val" == 0 ]; then echo -e "${COLOR1}$1${ENDCOLOR}" | awk '{printf "%-25s %-40s\n",$1,": no"}'; elif [ "$val" == 2 ] || [ "$val" == 3 ]; then echo -e "${COLOR1}$1${ENDCOLOR}" | awk '{printf "%-25s %-40s\n",$1,": alt mode"}'; elif [[ -r $val ]]; then echo -e "${COLOR1}$1${ENDCOLOR} $val" | awk '{printf "%-25s %-40s\n",$1,": "$2}'; fi } infoconf() { vars="apacmanconf builddir database downdir editor localrepo makepkgconf" vars="$vars pacmanconf pacmandb pkgfiledb savedir tmpdir usermakepkgconf" for i in $vars; do varstatus $i done vars="asdeps asexplicit auronly buildonly cachevcs force gendb ignorearch keepkeys" vars="$vars legacy needed noaur noconfirm nodatabase noedit nofail preview progress" vars="$vars purgebuild purgekeys quiet skipcache skipinteg skiptest testing warn" for j in $vars; do varstatus $j done } # Called whenever anything needs to be run as root ($@ is the command) runasroot() { if [[ $testing == 1 ]]; then fakeroot "$@" || code='10' elif [[ $UID -eq 0 ]]; then "$@" || code='11' elif sudo -v &>/dev/null && sudo -l "$@" &>/dev/null; then sudo -E "$@" || code='12' else echo -n "root " su -c "$(printf '%q ' "$@")" || code='13' fi } # debugging for curl ($1 is curl exit code, $2 package name) curlyq() { if [ $1 -eq 6 ]; then offline='1' echo -e "${COLOR7}:: ${COLOR1}No internet connection${ENDCOLOR}" elif [ $1 -ne 0 -a $1 -ne 7 -a $1 -ne 22 ]; then echo -e "${COLOR6}notice:${ENDCOLOR} curl exited with code $1 on $2" if deptest man; then curlman=$(man curl | sed '1,/^EXIT CODES/d' | grep " $1 ") curlman=$(echo "$curlman" | awk -F " " '{print $3}' | sed 's/^[ \t]*//') echo -e "${COLOR3}manpage:${ENDCOLOR} $curlman" fi fi } # Extract from AUR4 .info infoparser() { pkgname=$(jshon -Qe results < $1 -Qe Name -u) pkgver=$(jshon -Qe results < $1 -Qe Version -u) pkgbase=$(jshon -Qe results < $1 -Qe PackageBase -u) url=$(jshon -Qe results < $1 -Qe URL -u) licnum=$(($(jshon -Qe results < $1 -a -e License -l)-1)) license=$(while [ ${licnum} -ge '0' ]; do jshon -e results < $1 -a -e License -e ${licnum} -u ; ((licnum-=1)) ; done) groups=$(jshon -Qe results < $1 -Qe PackageBase -u) } # FIXME parser() { if [ -f "$1" ]; then if [[ $nosource == 1 ]]; then unset pkgname pkgver pkgrel arch checkdepends makedepends depends epoch pkgname=$(grep -o "^pkgname=\S*" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_.\n'); pkgver=$(grep -o "^pkgver=\S*" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_.\n'); pkgrel=$(grep -o "^pkgrel=\S*" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_.\n'); epoch=$(grep -o "^epoch=\S*" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_.\n'); _arch=$(grep "^arch=" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_. \n'); _checkdepends=$(grep "^checkdepends=" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_. \n'); _makedepends=$(grep "^makedepends=" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_. \n'); _depends=$(grep "^depends=" "$1" | awk -F = '{print $2}' | tr -dc 'a-z0-9-_. \n'); for _machine in $_arch; do arch+=("$_machine"); done for _pkg in $_checkdepends; do depends+=("$_pkg"); done for _pkg in $_makedepends; do makedepends+=("$_pkg"); done for _pkg in $_depends; do depends+=("$_pkg"); done echo "==> pkgname: $pkgname" echo "==> pkgver: $pkgver" echo "==> pkgrel: $pkgrel" echo "==> arch: ${arch[@]}" echo "==> checkdepends: ${checkdepends[@]}" echo "==> makedepends: ${makedepends[@]}" echo "==> depends: ${depends[@]}" return 0 else . "$1" fi else return 1 fi } # grep PKGBUILD arrays ($1 is array var) pkgbuildgrep() { grep "^${1}=" PKGBUILD 2>/dev/null | awk -F = '{print $2}' | tr -dc 'a-z0-9-_. \n'; } # Source apacman.conf file sourceapacmanconf() { [[ -r "$apacmanconf" ]] && . "$apacmanconf" [[ $noconfirm ]] && PACOPTS+=("--noconfirm") [[ $needed ]] && PACOPTS+=("--needed") [[ $skiptest ]] && MAKEPKGOPTS+=("--nocheck") [[ $skipinteg ]] && MAKEPKGOPTS+=("--skipinteg") [[ $ignorearch ]] && MAKEPKGOPTS+=("--ignorearch") export keepkeys noconfirm COLOR1 COLOR2 COLOR3 COLOR4 COLOR5 COLOR6 COLOR7 ENDCOLOR } # Source makepkg.conf file sourcemakepkgconf() { . "$makepkgconf" [[ -r "$usermakepkgconf" ]] && . "$usermakepkgconf" } # Parse IgnorePkg and --ignore, put in globally accessible ignoredpackages array getignoredpackages() { IFS=',' read -ra ignoredpackages <<< "$ignorearg" ignoredpackages+=( $(grep '^ *IgnorePkg' "$pacmanconf" | cut -d '=' -f 2-) ) } # Checks to see if $1 is an ignored package isignored() { [[ " ${ignoredpackages[@]} " =~ " $1 " ]] } # List installed packages getlistpackages() { $pacmanbin -Qi${pacmanarg} | grep -e "^Name " -e "^Installed Size " | \ awk '{if ($(NF-1) ~ /^[0-9]/) printf $(NF-1); print $NF}' | paste -s -d' \n' | \ sed -e 's/iB$//' -e 's/\.00K/K/' -e 's/\.00B/B/' | awk '{printf "%-10s %-40s\n",$2,$1}' | sort -h exit $? } # Tests whether package exists on the aur ($1 is name, $2 is dereferenced variable) existsinaur() { chosenpkg=$(echo "$1" | sed 's/\~$//' | awk -F "==" '{print $1}') val="${!2}" regexmatch="$(echo $val | tr -dc '0-9a-z-.\n')" if [[ $val != $regexmatch ]]; then matches=$(aurpkglist "$val") selectprovider "$val" $matches if [[ $providepkg ]]; then eval "$2=\"$providepkg\"" 2>/dev/null chosenpkg="$providepkg" fi fi rpcinfo "$chosenpkg" [[ "$(jshon -Qe resultcount -u < "$tmpdir/$chosenpkg.info")" != "0" ]] } # Tests whether $1 exists in pacman existsinpacman() { chosenpkg=$1 if [[ $regex = 1 ]]; then chosenpkg=$(selectprovider) fi $pacmanbin -Si -- "$chosenpkg" &>/dev/null } # Tests whether $1 is provided in pacman, sets globally accessibly providepkg var providedinpacman() { unset providepkg IFS=$'\n' read -rd '' -a providepkg < <($pacmanbin -Ssq -- "^$1$") selectprovider $1 "${providepkg[@]}" [[ -n $providepkg ]] } # Select option from numeric choice ($1 is num, $@ is array of choices) pickone() { n=1 maxnum=$1 shift choices=( $(echo $@) ) for v in ${choices[@]}; do echo "${n}) $v"; n=$((n+1)) done echo echo -n "Enter a selection (default=1): " read -r # Parse answer if [[ $REPLY ]]; then for num in $REPLY; do if [[ $num -le $maxnum ]] && [[ $num -ge 1 ]]; then num=$((num-1)) chosenone="${choices[$num]}" else err "Number \`$num' is not assigned to any of the options." fi done else chosenone="$choices" fi echo "$chosenone" } # Prompts options for virtual packages, $1 is package, $@ is array of packages selectprovider() { virtpkg=$1 shift virtual=($@) virtnum="${#virtual[@]}" if [[ $virtnum -eq 0 ]]; then return 1 elif [[ $virtnum -eq 1 ]]; then providepkg="$virtual" elif [[ $# -gt 1 ]]; then # Multiple providers provmsg="provide" [[ $regex = 1 ]] && provmsg="match" && unset regex echo -e "${COLOR5}:: ${COLOR1}There are $virtnum packages that $provmsg $virtpkg:${ENDCOLOR}" providepkg=$(pickone $virtnum ${virtual[@]}) fi } # Source old release ($1 is pkgver, $2 is pkgrel) checkrelease() { chistory=$(git rev-list --all) cmatch=$(git grep --all-match -e "pkgver = $1" -e "pkgrel = $2" ${chistory} -- .SRCINFO) chash=$(echo "$cmatch" | awk NR==1 | awk -F : '{print $1}') if [[ ! $chash ]]; then return 1 fi } # Parse AUR4 git repo relhistory() { chistory=$(git rev-list --all) cpkglog=$(git grep -A 1 -e "pkgver =" ${chistory} -- .SRCINFO) cversions=$(echo "$cpkglog" | awk '{$1=""; print $0}' | sed -e 's/^$/%%%/') cwtf=$(echo "$cversions" | sed -e 's/ pkgver = //' -e 's/ pkgrel = /-/') creleases=$(echo "$cwtf" | tr -d '\n' | sed -e 's/$/\n/' -e 's/%%%/\n/g') echo "$creleases" } # Select AUR package version ($1 is pkgname) selectrel() { release=( $(relhistory) ) relnum=${#release[@]} echo -e "${COLOR5}:: ${COLOR1}There are $relnum releases for $1:${ENDCOLOR}" pickone $relnum ${release[@]} } # Build old AUR releases ($1 is package name) clonehistory() { if deptest git; then git clone --quiet "${PKGURL}/${1}.git" cd "$1" if [ -z $2 ]; then selectrel "$1" relver="$chosenone" else relver="$2" fi if checkrelease ${relver%-*} ${relver##*-}; then echo -e "${COLOR5}:: ${COLOR1}Checking out $1 ${relver%-*}-${relver##*-}${ENDCOLOR}" git checkout --quiet "$chash" ls | sed "s/^/$1\//" else err "${COLOR7}error:${ENDCOLOR} package '$1' release '$relver' was not found" fi fi } # Tests whether $1 exists in a pacman group existsinpacmangroup() { [[ $($pacmanbin -Sgq "$1") ]] } # Tests whether $1 exists locally existsinlocal() { $pacmanbin -Qq -- "$1" &>/dev/null } # Scrapes .PKGINFO from local package ($1 is filename) scrapelocaldeps() { [[ -f "$1" ]] || err "${COLOR7}error:${ENDCOLOR} '$1': could not access file" dependencies=( $(pacman -T $(tar -x .PKGINFO -O -f "$1" 2>/dev/null | grep "^depend =" | awk -F " = " '{print $2}')) ) } # Scrapes the aur deps from PKGBUILDS and puts in globally available dependencies array scrapeaurdeps() { pkginfo "$1" "$preview" parser "$tmpdir/$1.PKGBUILD" [[ $skiptest = 1 ]] && unset checkdepends IFS=$'\n' dependencies=( $(echo -e "${depends[*]}\n${makedepends[*]}\n${checkdepends[*]}" | sed -e 's/=.*//' -e 's/>.*//' -e 's/<.*//'| sort -u) ) purgedepends=( $(echo -e "${makedepends[*]}\n${checkdepends[*]}" | sed -e 's/=.*//' -e 's/>.*//' -e 's/<.*//'| sort -u) ) unset IFS } # Finds dependencies of package $1 # Sets pacmandeps and aurdeps array, which can be accessed globally after function runs finddeps() { # loop through dependencies, if not installed, determine if pacman or aur deps pacmandeps=() aurdeps=() scrapeaurdeps "$1" [[ $buildonly = 1 || $purgebuild = 1 ]] && purgedeps+=( $($pacmanbin -T "${purgedepends[@]}") ) missingdeps=( $($pacmanbin -T "${dependencies[@]}") ) while [[ $missingdeps ]]; do checkdeps=() for dep in "${missingdeps[@]}"; do if [[ " $1 ${aurdeps[@]} ${pacmandeps[@]} " =~ " $dep " ]]; then continue fi if existsinpacman "$dep"; then pacmandeps+=("$dep") elif existsinaur "$dep" "dep"; then if [[ $aurdeps ]]; then aurdeps=("$dep" "${aurdeps[@]}") else aurdeps=("$dep") fi checkdeps+=("$dep") elif providedinpacman "$dep"; then pacmandeps+=("$providepkg") else [[ $option = "install" ]] && dne "Dependency \`$dep' of \`$1' does not exist." echo "Dependency \`$dep' of \`$1' does not exist." return 1 fi done missingdeps=() for dep in "${checkdeps[@]}"; do scrapeaurdeps "$dep" for depdep in "${dependencies[@]}"; do [[ $($pacmanbin -T "$depdep") ]] && missingdeps+=("$depdep") done done done return 0 } # Displays a progress bar ($1 is numerator, $2 is denominator, $3 is candy/normal) aurbar() { # Delete line printf "\033[0G" # Get vars for output beginline=" aur" beginbar="[" endbar="]" perc="$(($1*100/$2))" width="$(stty size)" width="${width##* }" infolen="$(($width*6/10))" [ $infolen -lt 50 ] && infolen=50 charsbefore="$((${#beginline}+${#1}+${#2}+3))" spaces="$(($infolen-$charsbefore))" barchars="$(($width-$infolen-${#beginbar}-${#endbar}-6))" hashes="$(($barchars*$perc/100))" dashes="$(($barchars-$hashes))" # Print output printf "$beginline %${spaces}s$1 $2 ${beginbar}" "" # ILoveCandy if [[ $3 = candy ]]; then for ((n=1; n<$hashes; n++)); do if (( (n==($hashes-1)) && ($dashes!=0) )); then (($n%2==0)) && printf "\e[1;33mc\e[0m" || printf "\e[1;33mC\e[0m" else printf "-" fi done for ((n=1; n<$dashes; n++)); do N=$(( $n+$hashes )) (($hashes>0)) && N=$(($N-1)) (($N%3==0)) && printf "o" || printf " " done else for ((n=0; n<$hashes; n++)); do printf "#" done for ((n=0; n<$dashes; n++)); do printf "-" done fi printf "%s %3s%%\r" ${endbar} ${perc} } aurpkglist() { if ! [[ -f "$tmpdir/packages.lst" ]]; then curl -Lfs "$PKGURL/packages.gz" | gunzip > "$tmpdir/packages.lst" fi grep -E "$1" "$tmpdir/packages.lst" | sort } rpcinfo() { if ! [[ -f "$tmpdir/$1.info" ]]; then curl -LfGs --data-urlencode "arg=$1" "$RPCURL=info" > "$tmpdir/$1.info" fi } pkglink() { rpcinfo $1 aurpkgpath=$(jshon -Q -e results -a -e URLPath -u < "$tmpdir/$1.info") [[ $aurpkgpath ]] && echo "${PKGURL}${aurpkgpath}" } absrepo() { $pacmanbin -Si -- "$1" 2>/dev/null | grep ^Repository | awk '{print $NF}' | awk NR==1 } # find pkgbase name for split packages ($1 is package repository, $2 is package name) absbase() { webpkg=$(curl -Lfs "$WEBURL/packages/$1/${makearch}/$2/"); cstatus=$? if [ $cstatus -eq 22 ]; then webpkg=$(curl -Lfs "$WEBURL/packages/$1/any/$2/"); cstatus=$? fi if [ $cstatus -eq 0 ]; then echo "$webpkg" | sed -e 's/<[^>]\+>/ /g' -e 's/^[ \t]*//' -e 's/[ \t]*$//' -e '/^$/d' | grep -A 1 "^Base Package:" | sed '1d' fi } # downloads source files ($1 is package repository, $2 is package name) abslink() { deptest rsync || err "${COLOR7}error:${ENDCOLOR} $option requires \`rsync'" rflags="-mrt --info=progress2 --no-motd --delete-after --no-p --no-o --no-g" rsync $rflags --include=/$1{,/$2} --exclude=/{$1/,}* ${ABSURL}::abs/{${makearch},any}/ . # try again if [ ! -d "$1/$2" ]; then pkgbase=$(absbase "$1" "$2") if [[ $pkgbase ]]; then [ -d "$1/$pkgbase" ] && rm -r "$1/$pkgbase" echo -e "${COLOR5}--> ${COLOR1}selected base: $pkgbase${ENDCOLOR}" rsync $rflags --include=/$1{,/$pkgbase} --exclude=/{$1/,}* ${ABSURL}::abs/{${makearch},any}/ . mv "$1/$pkgbase" "$1/$2" fi fi } # downloads pkgbuild ($1), edits if $2 is set pkginfo() { if ! [[ -f "$tmpdir/$1.PKGBUILD" ]]; then pkgpath=$(pkglink $1) basepath=$(echo ${pkgpath##*/} | sed 's/\.tar\.gz$//') [[ $basepath ]] || err "${COLOR7}error:${ENDCOLOR} package '$package' was not found" if [[ $legacy == 1 ]]; then curl -Lfs "${pkgpath%/*}/PKGBUILD" > "$tmpdir/$1.PKGBUILD" cstatus=$?; curlyq "$cstatus" "$1" else curl -Lfs "${pkgpath%/*/*}/plain/PKGBUILD?h=${basepath}" > "$tmpdir/$1.PKGBUILD" cstatus=$?; curlyq "$cstatus" "$1" fi if [[ $2 ]]; then # rename for syntax highlighting cp "$tmpdir/$1.PKGBUILD" "$tmpdir/PKGBUILD" confirm_edit "${COLOR6}Edit $1 PKGBUILD with \$editor? [Y/n]${ENDCOLOR} " "$tmpdir/PKGBUILD" mv "$tmpdir/PKGBUILD" "$tmpdir/$1.PKGBUILD" fi fi } # Checks if package is newer on aur ($1 is package name, $2 is local version) aurversionisnewer() { package="$1" rpcinfo "$package" unset aurversion if existsinaur "$package" "package"; then aurversion="$(jshon -Q -e results -a -e Version -u < "$tmpdir/$package.info")" if [[ "$(LC_ALL=C vercmp "$aurversion" "$2")" -gt 0 ]]; then return 0 fi fi return 1 } isoutofdate() { rpcinfo "$1" [[ "$(jshon -Q -e results -a -e OutOfDate -u < "$tmpdir/$1.info")" = "1" ]] } # Generate local AUR database aurgendb() { savecount=$(ls $savedir 2>/dev/null | wc -l) echo -e "${COLOR5}::${COLOR1} Generating AUR database... ($savecount)${ENDCOLOR}" progress "Generating AUR DB ($savecount)" runasroot mkdir -p ${database}/{local,raw} savedpkgs=$(ls ${savedir}/*-*-{any,${makearch}}.pkg.{tar,tar.xz} 2>/dev/null) runasroot repo-add ${database}/raw/aur.db.tar.gz $savedpkgs runasroot tar -xzf ${database}/raw/aur.files.tar.gz -C ${database}/local/ runasroot ln -s ${database}/raw/aur.db.tar.gz $pacmandb 2>/dev/null aurpkgfile echo -e "${COLOR5}::${COLOR1} Updated AUR database${ENDCOLOR}" [[ -z $option && -z $packageargs ]] && exit } # Update AUR pkgfile database aurpkgfile() { if ! deptest pkgfile; then return fi pkgdir=$(mktemp -d) if [[ -d ${database}/local ]]; then cd ${database}/local aurlist=$(ls) for aurpkg in $aurlist; do grep -v "^%" $aurpkg/files | sed 's/^/\//' > $pkgdir/$aurpkg done fi cd "$pkgdir" runasroot tar -czf ${database}/raw/pkgfile.tar.gz * cd - >/dev/null rm -r "$pkgdir" pkgfiledir=$(dirname "$pkgfiledb" 2>/dev/null) if [[ -d "$pkgfiledir" ]]; then runasroot ln -s ${database}/raw/pkgfile.tar.gz "$pkgfiledb" 2>/dev/null fi } # Update local AUR database ($1 is package, $2 is filename) aurlocaldb() { if [[ $nodatabase ]]; then return elif [[ ! -d $database ]] || [[ ! -f $pacmandb ]]; then runasroot mkdir -p ${database}/{local,raw} echo -e "${COLOR5}::${COLOR1} Checking AUR database${ENDCOLOR}" savecount=$(ls $savedir 2>/dev/null | wc -l) if [[ $savecount -gt 0 ]]; then echo -e "${COLOR7}warning:${ENDCOLOR} need to run ${COLOR1}apacman --gendb${ENDCOLOR} (found $savecount AUR files!)" else runasroot repo-add -q ${database}/raw/aur.db.tar.gz 2>/dev/null runasroot ln -s ${database}/raw/aur.db.tar.gz $pacmandb 2>/dev/null fi fi runasroot repo-add -q ${database}/raw/aur.db.tar.gz "$2" 2>/dev/null pkgnamever=$(echo "$2" | awk -F "$savedir/" '{print $2}' | sed "s/-any.pkg.tar.*//g;s/-${makearch}.pkg.tar.*//g") runasroot tar -C ${database}/local/ -x "$pkgnamever/" -zf ${database}/raw/aur.files.tar.gz && aurpkgfile } # List bundle package files listbundle() { if [[ $bundle ]]; then echo -e "${COLOR5}==>${ENDCOLOR} Packages to bundle" echo ${bundle[@]} | sed 's/ /\n/g' | tee "$tmpdir/bundle.lst" fi } # $1 is prompt, $2 is file confirm_edit() { if [[ (! -f "$2") || "$noconfirm" || "$noedit" ]]; then return fi echo -en "$1" if proceed; then $editor "$2" fi } # Output status of aur packages ($1 is 0 for success or 1 for failure) buildstatus() { if [[ $1 != 0 ]]; then echo echo -e "${COLOR7}==> ERROR:${ENDCOLOR} ${COLOR1}the build failed${ENDCOLOR}" code='8' fi echo -e "${COLOR5} ->${ENDCOLOR} ${COLOR1}Status${ENDCOLOR}" [[ $success ]] && echo -e "\t${COLOR4}built (${#success[@]}):${ENDCOLOR} ${success[@]}" [[ $failure ]] && echo -e "\t${COLOR7}failed (${#failure[@]}):${ENDCOLOR} ${failure[@]}" [[ $remains ]] && echo -e "\t${COLOR6}remain (${#remains[@]}):${ENDCOLOR} ${remains[@]}" echo "" [[ $nofail = 1 && $1 != 0 ]] && exit 9 } # Build install ($1 is package, $2 is dependency or explicit, $3 is filename) buildinstall() { if [[ $2 = dependency ]]; then runasroot $PACMAN ${PACOPTS[@]} --asdeps -U "$3" aurlocaldb "$1" "$3" [[ $buildonly = 1 ]] && bundle+=("$3") [[ $buildonly = 1 ]] && purgedeps+=("$1") elif [[ $2 = explicit ]]; then [[ $buildonly = 1 ]] && echo -e "${COLOR6}notice:${ENDCOLOR} $1 built -- not installing" [[ $buildonly = 1 ]] && bundle+=("$3") [[ $buildonly != 1 ]] && progress "Installing ${pkgnum}/${totalcount} $1" [[ $buildonly != 1 ]] && runasroot $PACMAN ${PACOPTS[@]} -U "$3" [[ $buildonly != 1 ]] && aurlocaldb "$1" "$3" fi } # Checks if aur cache is newer than aur ($1 is package, $2 is aur version) checkvcs() { cachefile=$(ls -t ${savedir}/${1}-*-{any,${makearch}}.pkg.{tar,tar.xz} 2>/dev/null | awk NR==1 | awk -F "${savedir}/${1}-" '{print $2}'); cachever=$(echo "$cachefile" | sed "s/-any.pkg.tar.*//g;s/-${makearch}.pkg.tar.*//g"); if [[ "$(LC_ALL=C vercmp "$cachever" "$2")" -gt 0 ]]; then echo -e "${COLOR7}warning:${ENDCOLOR} $1 -- ${COLOR7}verify cache newer than AUR${ENDCOLOR} ($pkgver-$pkgrel)" pkgfile="${savedir}/${1}-${cachefile}"; elif [[ "$(LC_ALL=C vercmp "$cachever" "$2")" -eq 0 ]]; then pkgfile="${savedir}/${1}-${cachefile}"; fi } # Checks if packages are in aur cache ($1 is package, $2 is dependency or explicit) checkcache() { unset pkgfile; if [ "$skipcache" != "1" ]; then sourcemakepkgconf pkgfile=$(ls ${savedir}/${1}-${pkgver}-${pkgrel}-{any,${makearch}}.pkg.{tar,tar.xz} 2>/dev/null | awk NR==1); fi if [ "$cachevcs" = "1" ]; then checkvcs $1 $pkgver-$pkgrel fi pkgnum=$((pkgnum+1)) if [ -f "$pkgfile" ]; then #progress "Installing ${pkgnum}/${totalcount} $1" cacheinstall "$1" "$2" "$pkgfile" else progress "Building ${pkgnum}/${totalcount} $1" aurinstall "$1" "$2" fi; } # Installs packages from cache ($1 is package, $2 is dependency or explicit, $3 is filename) cacheinstall() { if [ "$cachevcs" = "1" ]; then pkgrelease="$1-$cachever" else pkgrelease="$1-$pkgver-$pkgrel" fi if [[ $offline = '1' ]]; then offlinemsg="${COLOR4} offline${ENDCOLOR}" fi echo -e "${COLOR6}notice:${ENDCOLOR}${offlinemsg} installing $pkgrelease from cache" remains=(${remains[@]/$1/}) buildinstall $1 $2 $3 } # Retrieve PGP keys ($@ is ${validpgpkeys[@]}) export gpgconf checkpgpkeys() { if [[ $1 ]]; then gpg --fingerprint $@ 2>/dev/null fi }; export -f checkpgpkeys # Prompt to import PGP keys ($@ is ${validpgpkeys[@]}) askpgpkeys() { echo -e "\n${COLOR6}warning:${ENDCOLOR} One or more PGP signatures unknown" for pgpkey in $@; do echo -e "\t${COLOR7}${pgpkey}${ENDCOLOR}" done echo -en "${COLOR5}:: ${COLOR1}Verify PGP keys? [Y/n]${ENDCOLOR} " if ! [[ $noconfirm ]]; then proceed || exit else echo fi }; export -f askpgpkeys # Import PGP keys ($@ is ${validpgpkeys[@]}) addpgpkeys() { [ -f $HOME/.gnupg/gpg.conf ] || cp $gpgconf $HOME/.gnupg/ for pgpkey in $@; do echo -e "${COLOR6}trusting:${ENDCOLOR} ${COLOR7}${pgpkey}${ENDCOLOR}" gpg --recv-key $pgpkey done }; export -f addpgpkeys # Remove added PGP keys ($@ is ${validpgpkeys[@]}) removepgpkeys() { if ! [[ $keepkeys ]]; then keycheck=$(gpg --fingerprint $@ 2>/dev/null) if [[ $keycheck ]]; then echo -e "${COLOR5} -> ${COLOR1}Removed $# trusted keys${ENDCOLOR}" gpg --batch --yes --delete-keys $@ fi fi }; export -f removepgpkeys # Installs cached packages offline ($1 is package, $2 is dependency or explicit) offlineinstall() { cachedpkgs=$(ls ${savedir}/*-{any,${makearch}}.pkg.{tar,tar.xz} 2>/dev/null | awk -F "$savedir/" '{print $2}') cachedpkgs=$(echo "$cachedpkgs" | awk -F "-" '{for(i=1;i<=NF-3;++i) printf $i"-"; print " " $(NF-2) " " $(NF-1) " " $NF}' 2>/dev/null) cachedarray=$(echo "$cachedpkgs" | sed 's/- / /' | grep "^$1 " | sort -n | tail -n 1) if [[ $cachedarray ]]; then pkgver=$(echo "$cachedarray" | awk '{print $2}') pkgrel=$(echo "$cachedarray" | awk '{print $3}') pkgext=$(echo "$cachedarray" | awk '{print $4}') pkgfile=$(ls ${savedir}/${1}-${pkgver}-${pkgrel}-${pkgext} 2>/dev/null) fi if [ -f "$pkgfile" ]; then cacheinstall "$1" "$2" "$pkgfile" else echo "Package \`$1' does not exist in cache." exit 6 fi } # Sanity check for umask permissions ($1 is build directory) checkumask() { otherbits=$(ls -ld "$1" | awk '{print $1}' | cut -c 8,10) if [[ $otherbits != "rx" ]]; then mask=$(umask 2>/dev/null) if [[ $mask != *022 ]]; then echo -e "${COLOR6}warning:${ENDCOLOR} umask set to ${COLOR4}${mask}${ENDCOLOR} (should be 022)" fi rmdir "$1" err "${COLOR7}error:${COLOR1} no write permission in ${1}${ENDCOLOR}" fi } # Sanity check for tmpfs free disk space ($1 is build directory) checkcapacity() { capacity=$(df -P "$1" 2>/dev/null | tail -n 1 | awk '{print $5}' | tr -dc '[0-9]\n') if [[ $capacity -ge 99 ]]; then echo -e "${COLOR7}error:${COLOR1} no free space in ${1}${ENDCOLOR}" [[ "$warn" == 1 ]] || exit 7 elif [[ $capacity -gt 90 ]]; then echo -e "${COLOR6}warning:${ENDCOLOR} low disk space in ${1} (tmpfs)" fi } # Clean package source ($1 is package) cleanbuild() { whatlinkshere=$(ls -l --color=never "$builddir" | grep ^l | grep "/${1}$" | awk '{print $(NF-2)}') if [[ $whatlinkshere ]]; then echo -e "${COLOR3}notice:${ENDCOLOR} cleaning delayed until finished with $whatlinkshere" else [[ $verbose ]] && echo -e "${COLOR5}::${COLOR1} Cleaning build ${builddir}/$1 ${ENDCOLOR}" rm -rf "${builddir}/$1" rm "${tmpdir}/$1.info" "${tmpdir}/$1.PKGBUILD" fi } # Installs packages from aur ($1 is package, $2 is dependency or explicit) aurinstall() { if [[ $offline = '1' ]]; then offlineinstall "$1" "$2" else aurmakepkg "$1" "$2" fi } # Installs packages from aur ($1 is package, $2 is dependency or explicit) aurmakepkg() { unset validpgpkeys dir="${builddir}/$1" sourcemakepkgconf # Prepare the installation directory # If there is an old directory and aurversion is not newer, use old directory if parser "$dir/PKGBUILD" &>/dev/null && ! aurversionisnewer "$1" "$pkgver-$pkgrel"; then checkumask "$dir" checkcapacity "$dir" cd "$dir" else [[ -d "$dir" ]] && rm -rf "$dir" mkdir -p "$builddir" checkumask "$builddir" checkcapacity "$builddir" cd "$builddir" curl -Lfs "$(pkglink $1)" > "$1.tar.gz" cstatus=$?; curlyq "$cstatus" "$1" mkdir "$1" tar -xf "$1.tar.gz" -C "$1" --strip-components=1 cd "$1" if [[ $preview && -s "$tmpdir/$1.PKGBUILD" ]]; then cp "$tmpdir/$1.PKGBUILD" PKGBUILD fi # customizepkg if [[ -f "/etc/customizepkg.d/$1" ]] && deptest customizepkg; then echo "Applying customizepkg instructions..." customizepkg --modify fi fi # Check for split PKGBUILD pkgbase=($(pkgbuildgrep pkgbase)); pkgname=($(pkgbuildgrep pkgname)); if [[ "${pkgbase[@]}" ]]; then echo -e " ${COLOR5}->${ENDCOLOR}${COLOR1} Split package base: ${pkgbase[@]}${ENDCOLOR}"; if [[ "${#pkgname[@]}" -gt 1 ]]; then echo -e " ${COLOR5}->${ENDCOLOR}${COLOR1} PKGBUILD contains: ${pkgname[@]}${ENDCOLOR}"; for split in ${pkgname[@]}; do ln -s "${builddir}/$1" "${builddir}/$split" 2>/dev/null; done fi fi # Check for missing arch arch=($(pkgbuildgrep arch)); if [[ ! " ${arch[@]} " =~ " any " ]]; then if [[ ! " ${arch[@]} " =~ " ${CARCH} " ]]; then echo -e "${COLOR6}warning:$ENDCOLOR $CARCH missing from arch array" fi fi # Allow user to edit PKGBUILD confirm_edit "${COLOR6}Edit $1 PKGBUILD with \$editor? [Y/n]${ENDCOLOR} " PKGBUILD if ! [[ -f PKGBUILD ]]; then err "No PKGBUILD found in directory." fi # Allow user to edit .install unset install parser PKGBUILD confirm_edit "${COLOR6}Edit $install with \$editor? [Y/n]${ENDCOLOR} " "$install" # Installation (makepkg and pacman) rm -f *$PKGEXT if [[ $UID -eq 0 ]]; then id aurbuild >/dev/null 2>/dev/null || useradd -r -d /var/empty aurbuild mkdir -p /var/empty/.gnupg chown -R aurbuild:aurbuild . /var/empty/.gnupg if [[ $validpgpkeys ]]; then su aurbuild -c "gpg --refresh-keys ${validpgpkeys[*]}" keyfound=$(su aurbuild -c "checkpgpkeys ${validpgpkeys[*]}" 2>/dev/null) if ! [[ $keyfound ]]; then askpgpkeys "${validpgpkeys[*]}" su aurbuild -c "addpgpkeys ${validpgpkeys[*]}" fi su aurbuild -c "makepkg $MAKEPKGOPTS -f"; buildcheck=$? [[ $keyfound ]] || su aurbuild -c "removepgpkeys ${validpgpkeys[*]}" [[ $purgekeys ]] && [[ $keyfound ]] && su aurbuild -c "removepgpkeys ${validpgpkeys[*]}" else su aurbuild -c "makepkg $MAKEPKGOPTS -f"; buildcheck=$? fi else if [[ $validpgpkeys ]]; then gpg --refresh-keys "${validpgpkeys[@]}" keyfound=$(checkpgpkeys "${validpgpkeys[@]}" 2>/dev/null) if ! [[ $keyfound ]]; then askpgpkeys "${validpgpkeys[@]}" addpgpkeys "${validpgpkeys[@]}" fi makepkg $MAKEPKGOPTS -f; buildcheck=$? [[ $keyfound ]] || removepgpkeys "${validpgpkeys[@]}" [[ $purgekeys ]] && [[ $keyfound ]] && removepgpkeys "${validpgpkeys[@]}" else makepkg $MAKEPKGOPTS -f; buildcheck=$? fi fi # Build check remains=(${remains[@]/$1/}); if [[ $buildcheck -ne 0 ]]; then failure+=("$1") buildstatus 1 else success+=("$1") buildstatus 0 fi # Reparse PKGBUILD, possibly modified during build parser PKGBUILD # Save packages [ ${epoch} ] && epoch=${epoch}: pkgtar=$(ls $1-${epoch}${pkgver}*${PKGEXT} 2>/dev/null | tail -n 1) if [[ $pkgtar ]]; then [ -d $savedir ] || mkdir -p $savedir 2>/dev/null || runasroot mkdir -p $savedir echo -e "${COLOR5} -> ${COLOR1}Saving package:${ENDCOLOR} ${pkgtar}" cp ${pkgtar} $savedir/ 2>/dev/null || runasroot cp ${pkgtar} $savedir/ echo -e "${COLOR5} -> ${COLOR1}Installing ${1}${ENDCOLOR}" buildinstall $1 $2 ${savedir}/$pkgtar cleanbuild $1 elif [[ $nofail ]]; then cleanbuild $1 fi } # Passthrough for pkgfile pkgfilehandling() { if ! deptest pkgfile; then err "${COLOR7}error:${ENDCOLOR} $1 requires \`pkgfile'" return fi if [[ ! -f $pacmandb ]]; then echo -e "${COLOR7}warning:${ENDCOLOR} need to run ${COLOR1}apacman --gendb${ENDCOLOR}" fi if [[ $1 = -P* ]] && [[ $1 != -P ]]; then Parg=$(echo $1 | sed 's/P//g') fi shift pkgfile -C <(cat $pacmanconf | sed "$ a [$localrepo]") $Parg "$@" exit $? } # Install local packages (-U) localhandling() { pacmanarg="$1" shift for arg in $@; do if [ -f "$arg" ]; then localpkg+=("$arg") else args+=("$arg") fi done for pkg in ${localpkg[@]}; do scrapelocaldeps $pkg echo -e "${COLOR3}notice:${ENDCOLOR} installing dependencies for $pkg" if [[ $dependencies ]]; then $0 -S "${args[@]}" ${dependencies[@]} --asdeps --localinstall --needed fi done runasroot $pacmanbin $pacmanarg "${localpkg[@]}" } # Goes through all of the install tests and execution ($@ is packages to be installed) installhandling() { packageargs=("$@") getignoredpackages sourcemakepkgconf # Figure out all of the packages that need to be installed for package in "${packageargs[@]}"; do # Determine whether package is in pacman repos if ! [[ $auronly ]] && existsinpacman "$package"; then pacmanpackages+=("$package") elif ! [[ $auronly ]] && existsinpacmangroup "$package"; then pacmanpackages+=("$package") elif ! [[ $auronly ]] && providedinpacman "$package"; then pacmanpackages+=("$providepkg") elif ! [[ $noaur ]] && existsinaur "$package" "package"; then if finddeps "$package"; then # here is where dep dupes are created aurpackages+=("$package") aurdepends=("${aurdeps[@]}" "${aurdepends[@]}") pacmandepends+=("${pacmandeps[@]}") fi else dne "Package \`$package' does not exist." fi done # Check if any aur target packages are ignored for package in "${aurpackages[@]}"; do if isignored "$package"; then echo -ne "${COLOR5}:: ${COLOR1}$package is in IgnorePkg/IgnoreGroup. Install anyway?${ENDCOLOR} [Y/n] " if ! [[ $noconfirm ]]; then proceed || continue else echo fi fi aurtargets+=("$package") done # Check if any aur dependencies are ignored for package in "${aurdepends[@]}"; do if isignored "$package"; then echo -ne "${COLOR5}:: ${COLOR1}$package is in IgnorePkg/IgnoreGroup. Install anyway?${ENDCOLOR} [Y/n] " if ! [[ $noconfirm ]]; then if ! proceed; then echo "Unresolved dependency \`$package'" unset aurtargets break fi else echo fi fi done # First install the explicit pacman packages, let pacman prompt if [[ $pacmanpackages ]]; then echo -e "${COLOR6}Pacman Targets ($((${#pacmanpackages[@]}))):${ENDCOLOR} ${pacmanpackages[@]}" echo if [[ $buildonly = 1 ]]; then downfile=$($PACMAN -Sp -- "${pacmanpackages[@]}" | awk -v dir=$downdir -F "/" '{print dir"/"$NF}') bundle+=("${downfile}") runasroot $PACMAN "${PACOPTS[@]}" -Sw --cachedir $downdir -- "${pacmanpackages[@]}" else runasroot $PACMAN "${PACOPTS[@]}" -S -- "${pacmanpackages[@]}" fi fi if [[ -z $aurtargets ]]; then listbundle exit fi # Test if aurpackages are already installed; echo warning if so for pkg in "${aurtargets[@]}"; do if existsinlocal "$pkg"; then localversion="$($pacmanbin -Qs "$pkg" | grep -F "local/$pkg " | cut -d ' ' -f 2)" if ! aurversionisnewer "$pkg" "$localversion"; then if [ "$needed" = "1" ]; then [[ $localinstall ]] || echo -e "${COLOR6}notice:$ENDCOLOR $pkg-$localversion is up to date -- skipping" aurtargets=(${aurtargets[@]/$pkg/}); else echo -e "${COLOR6}warning:$ENDCOLOR $pkg-$localversion is up to date -- reinstalling" fi fi fi done # Echo warning if packages are out of date for pkg in "${aurtargets[@]}" "${aurdepends[@]}"; do if isoutofdate "$pkg"; then echo -e "${COLOR6}warning:$ENDCOLOR $pkg is flagged out of date" fi done # Prompt for aur packages and their dependencies num="$((${#aurdepends[@]}+${#aurtargets[@]}))" if [[ $num -eq 0 ]] && [[ $localinstall ]]; then true elif [[ $aurdepends ]]; then echo echo -e "${COLOR6}Aur Targets ($num):${ENDCOLOR} ${aurdepends[@]} ${aurtargets[@]}" else echo echo -e "${COLOR6}Aur Targets ($((${#aurtargets[@]}))):${ENDCOLOR} ${aurtargets[@]}" fi # Prompt for pacman dependencies if [[ $pacmandepends ]]; then IFS=$'\n' read -rd '' -a pacmandepends < \ <(printf "%s\n" "${pacmandepends[@]}" | sort -u) echo -e "${COLOR6}Pacman Targets (${#pacmandepends[@]}):${ENDCOLOR} ${pacmandepends[@]}" fi # Sanity check pkgnum="${#pacmandepends[@]}" totalcount="$((${#aurdepends[@]}+${#aurtargets[@]}+${#pacmandepends[@]}))" remains=($(printf "%s\n" "${aurdepends[@]}" "${aurtargets[@]}" | sort -u)) if [ "$totalcount" = "0" ]; then [[ $localinstall ]] || echo -e "${COLOR5}==>$ENDCOLOR nothing to do" exit 0 fi # Prompt to proceed [[ $buildonly = 1 ]] && phrasing="building" || phrasing="installation" echo -en "\n${COLOR5}:: ${COLOR1}Proceed with ${phrasing}? [Y/n]${ENDCOLOR} " if ! [[ $noconfirm ]]; then proceed || exit else echo fi # Install pacman dependencies if [[ $pacmandepends ]]; then if [[ $buildonly = 1 ]]; then downfile=$($PACMAN -Sp -- "${pacmandepends[@]}" | awk -v dir=$downdir -F "/" '{print dir"/"$NF}') bundle+=("${downfile}") fi progress "Installing ${pkgnum}/${totalcount} packages" runasroot $PACMAN --noconfirm --asdeps -S -- "${pacmandepends[@]}" || err "Installation failed." fi # Install aur dependencies if [[ $aurdepends ]]; then for dep in "${aurdepends[@]}"; do checkcache "$dep" "dependency" done fi # Install the aur packages for package in "${aurtargets[@]}"; do scrapeaurdeps "$package" if $pacmanbin -T "${dependencies[@]}" &>/dev/null; then checkcache "$package" "explicit" else echo "Dependencies for \`$package' are not met, not building..." fi done # Remove build dependencies if [[ $buildonly = 1 ]]; then purgedeps+=("${pacmandepends[@]}") fi if [[ $purgedeps ]]; then purgedepends=( $(echo -e "${purgedeps[*]}" | sort -u) ) progress "Removing ${#purgedepends[@]} build depends" runasroot $pacmanbin --noconfirm -Ru -- "${purgedepends[@]}" 2>/dev/null fi listbundle exit $code } run_quick_check() { bigurl="$RPCURL=multiinfo" for p in $($pacmanbin -Qqm); do bigurl="$bigurl&arg\[\]=$p" done parsed_aur="$(curl -s "$bigurl" | \ jshon -e results -a -e Name -u -p -e Version -u | \ sed 's/^$/-/' | paste -s -d '\t\n' | sort)" packages="$(expac -Q '%n\t%v' | sort)" comm -23 <(echo "$parsed_aur") <(echo "$packages") | cut -f 1 if [[ $auronly == 1 ]]; then return fi # see https://mailman.archlinux.org/pipermail/pacman-dev/2011-October/014673.html # (note to self, get that merged already...) if [[ -z $CHECKUPDATE_DB ]]; then CHECKUPDATE_DB="${TMPDIR:-/tmp}/checkup-db-${USER}/" fi eval $(awk '/DBPath/ {print $1$2$3}' $pacmanconf) DBPath="${DBPath:-/var/lib/pacman/}" mkdir -p "$CHECKUPDATE_DB" ln -s "${DBPath}/local" "$CHECKUPDATE_DB" &> /dev/null fakeroot $pacmanbin -Sqy --dbpath "$CHECKUPDATE_DB" &> /dev/null $pacmanbin -Qqu --dbpath "$CHECKUPDATE_DB" 2> /dev/null } # proceed with installation prompt proceed() { read -n 1 echo case "$REPLY" in 'Y'|'y'|'') return 0 ;; *) return 1 ;; esac }; export -f proceed # process busy loop nap() { while (( $(jobs | wc -l) >= 8 )); do jobs > /dev/null done } # Parse --config parameter early loadconfig() { for flag in $@; do if [[ $nextflag = 1 ]]; then apacmanconf="$flag" unset nextflag return elif [[ $flag = "--config" ]]; then nextflag='1' elif [[ $flag = --config* ]]; then apacmanconf="$flag" return fi done } # Unit testing env enabletesting() { savedir="$testdir" PACOPTS+=("-r" "$testdir") PACOPTS+=("--cachedir" "${testdir}/var/cache/pacman/pkg") PACOPTS+=("--dbpath" "${testdir}/var/lib/pacman") } # Wrap pacman parameters pacwrap() { if [[ $1 = -Q* ]]; then $pacmanbin "$@"; elif [[ $1 = -T* ]]; then $pacmanbin "$@"; elif [[ $1 = -U* ]]; then localhandling "$@" elif [[ $1 = -P* ]]; then pkgfilehandling "$@"; elif [[ $1 = --pkgfile ]]; then pkgfilehandling "$@"; else runasroot $pacmanbin "$@"; fi; exit $? } # Override defaults loadconfig $@ sourceapacmanconf # Argument parsing [[ $1 ]] || usage packageargs=() while [[ $1 ]]; do case "$1" in '-S') option=install ;; '-Ss') option=search ;; '-Ssq'|'-Sqs') option=search ; quiet='1' ;; '-Si') option=info ;; -S*u*) option=update ; escaperope='1' ; pacmanarg="$1" ;; '-G') option=download ;; -L*) option=list ; escaperope='1' ; pacmanarg="${1//-L}" ;; -W*) option=web ; pacmanarg="${1//-W}" ;; '--asdeps') asdeps='1' PACOPTS+=("--asdeps") ; export asdeps; unset asexplicit ;; '--asexplicit') asexplicit='1' PACOPTS+=("--asexplicit"); export asexplicit; unset asdeps ;; '--auronly') auronly='1' ; unset noaur ;; '--buildonly') buildonly='1' ;; '--cachevcs') cachevcs='1' ;; '--config') config='1' ; shift ;; --config=*) config='1' ; equals+=("--config") ;; '--devel') devel='1' ;; '--edit') unset noedit ;; '--force') force='1' PACOPTS+=("--force");; '--gendb') gendb='1' ;; '--ignore') ignorearg="$2" ; PACOPTS+=("--ignore" "$2") ; shift ;; --ignore=*) ignorearg="$1" ; equals+=("--ignore") ;; '--ignorearch') MAKEPKGOPTS+=("--ignorearch");; '--keepkeys') keepkeys='1' ; export keepkeys ;; '--legacy') legacy='1' ;; '--localinstall') localinstall='1' ;; '--needed') needed='1' PACOPTS+=("--needed");; '--noaur') noaur='1' ; unset auronly ;; '--noconfirm') noconfirm='1' PACOPTS+=("--noconfirm") ; export noconfirm ;; '--nodatabase') nodatabase='1' ;; '--noedit') noedit='1' ;; '--nofail') nofail='1' ;; '--noprogress') unset progress ;; '--nosource') nosource='1' ;; '--notify') progress='2' ;; '--pkgfile') pacwrap "$@" ;; '--preview') preview='1' ;; '--progress') progress='1' ;; '--purgebuild') purgebuild='1' ;; '--purgekeys') purgekeys='1' ;; '--quickcheck') quickcheck='1' ;; '--quiet') quiet='1' ;; '--savedir') savedir="$2" ; shift ;; --savedir=*) savedir="$1"; equals+=("--savedir") ;; '--skipcache') skipcache='1' ;; '--skipinteg') skipinteg='1' ; MAKEPKGOPTS+=("--skipinteg");; '--skiptest') skiptest='1' ; MAKEPKGOPTS+=("--nocheck");; '--testing') testing='1' ; enabletesting ;; '--warn') warn='1' ;; '-h'|'--help') usage ;; '-v'|'--verbose') verbose='1' ;; '-V'|'--version') version ;; '--') shift ; packageargs+=("$@") ; break ;; -D*) pacwrap "$@" ;; -P*) pacwrap "$@" ;; -Q*) pacwrap "$@" ;; -R*) pacwrap "$@" ;; -S*) pacwrap "$@" ;; -T*) pacwrap "$@" ;; -U*) pacwrap "$@" ;; -*) invalid "$@" ;; *) packageargs+=("$1") ;; esac shift done # Handles alternative syntax --flag=parameter for eqvar in "${equals[@]}"; do if [[ $eqvar = "--config" ]]; then apacmanconf=$(echo "$apacmanconf" | awk -F "=" '{print $2}') elif [[ $eqvar = "--ignore" ]]; then ignorearg=$(echo "$ignorearg" | awk -F "=" '{print $2}') PACOPTS+=("--ignore" "$ignorearg") elif [[ $eqvar = "--savedir" ]]; then savedir=$(echo "$savedir" | awk -F "=" '{print $2}') fi done # Set tmpfile stuff, clean tmpdir rm -rf "$tmpdir" &>/dev/null mkdir -p "$tmpdir" olddir="$PWD" cd # Determine architecture makearch=$(grep ^CARCH= "$makepkgconf" 2>/dev/null | grep -o -e =.*[0-9A-Za-z] | sed 's/^="//'); # Check for new packages if [[ $quickcheck == 1 ]]; then run_quick_check exit fi # Verbose mode [[ $verbose || $debug ]] && infoconf # List (-L) handling if [[ $option = list ]]; then getlistpackages fi # Generate DB (--gendb) handling if [[ $gendb = 1 ]]; then aurgendb fi # Sanity checks [[ $config && -z $apacmanconf ]] && err "${COLOR7}error:${ENDCOLOR} no config file specified (use -h for help)" [[ $option ]] || option="searchinstall" [[ $escaperope != 1 && -z $packageargs ]] && err "${COLOR7}error:${ENDCOLOR} must specify a package." [[ $auronly && $noaur ]] && err "Parameters --auronly and --noaur conflict." # Install (-S) handling if [[ $option = install ]]; then for pkg in ${packageargs[@]}; do regexmatch="$(echo $pkg | tr -dc '0-9a-z-.\n')" if [[ "$pkg" =~ ^/ ]]; then err "${COLOR7}error:${ENDCOLOR} invalid package name $pkg" elif [[ $regex = 1 ]]; then true elif [[ "$pkg" != "$regexmatch" ]]; then regex='1' echo -e "${COLOR6}notice:${ENDCOLOR} enabling regex mode ($pkg)" fi done installhandling "${packageargs[@]}" exit $? fi # Update (-Su) handling if [[ $option = update ]]; then getignoredpackages sourcemakepkgconf # Pacman update if ! [[ $auronly ]]; then runasroot $PACMAN "${PACOPTS[@]}" "$pacmanarg" fi # Aur update total=0 if ! [[ $noaur ]]; then echo -e "${COLOR5}:: ${COLOR1}Synchronizing aur database...${ENDCOLOR}" IFS=$'\n' read -rd '' -a packages < <($pacmanbin -Qm) newpackages=() checkignores=() extinctpkgs=() total="${#packages[@]}" grep -q '^ *ILoveCandy' "$pacmanconf" && bartype='candy' || bartype='normal' fi if [[ $devel ]]; then for ((i=0; i<$total; i++)); do aurbar "$((i+1))" "$total" "$bartype" pkg="${packages[i]%% *}" if isignored "$pkg"; then checkignores+=("${packages[i]}") continue elif ! existsinaur "$pkg" "pkg"; then extinctpkgs+=("${packages[i]}") continue fi pkginfo "$pkg" & nap done wait for ((i=0; i<$total; i++)); do pkg="${packages[i]%% *}" ver="${packages[i]##* }" if [[ ! -s "$tmpdir/$pkg.PKGBUILD" ]]; then continue fi if isignored "$pkg"; then continue fi unset _darcstrunk _cvsroot _gitroot _svntrunk _bzrtrunk _hgroot parser "$tmpdir/$pkg.PKGBUILD" if [[ "$(LC_ALL=C vercmp "$pkgver-$pkgrel" "$ver")" -gt 0 ]]; then newpackages+=("$pkg") elif [[ ${_darcstrunk} || ${_cvsroot} || ${_gitroot} || ${_svntrunk} || ${_bzrtrunk} || ${_hgroot} ]]; then newpackages+=("$pkg") fi done else for ((i=0; i<$total; i++)); do aurbar "$((i+1))" "$total" "$bartype" pkg="${packages[i]%% *}" rpcinfo "$pkg" & nap done wait for ((i=0; i<$total; i++)); do pkg="${packages[i]%% *}" ver="${packages[i]##* }" if isignored "$pkg"; then checkignores+=("${packages[i]}") elif ! existsinaur "$pkg" "pkg"; then extinctpkgs+=("${packages[i]}") elif aurversionisnewer "$pkg" "$ver"; then newpackages+=("$pkg") fi done fi echo [[ $noaur ]] || echo -e "${COLOR5}:: ${COLOR1}Starting full aur upgrade...${ENDCOLOR}" # Check and output ignored package update info for package in "${checkignores[@]}"; do if aurversionisnewer "${package%% *}" "${package##* }"; then echo -e "${COLOR6}warning:${ENDCOLOR} ${package%% *}: ignoring package upgrade (${package##* } => $aurversion)" fi done # Alert packages no longer in AUR if [[ $extinctpkgs ]]; then for package in "${extinctpkgs[@]}"; do listextinct+=("${package%% *}") done echo "" echo -e "${COLOR6}Unresolvable (${#listextinct[@]}):${ENDCOLOR} ${listextinct[@]}" echo "" fi # Now for the installation part if [[ $newpackages ]]; then auronly='1' installhandling "${newpackages[@]}" fi [[ $noaur ]] || echo " local database is up to date" exit $code fi # Download (-G) handling if [[ $option = download ]]; then cd "$olddir" for package in "${packageargs[@]}"; do if ! [[ $noaur ]] && existsinaur "$package" "package"; then pkglist+=("$package") elif ! [[ $auronly ]] && existsinpacman "$package"; then abslist+=("$package") elif [[ $noaur ]]; then dne "Package \`$package' does not exist in ABS." elif [[ $auronly ]]; then dne "Package \`$package' does not exist in AUR." else dne "Package \`$package' does not exist in ABS+AUR." fi done [[ $abslist ]] && echo -e "${COLOR6}notice:$ENDCOLOR sourcing from ${COLOR4}[ABS]$ENDCOLOR" for package in "${abslist[@]}"; do pkgrepo=$(absrepo "$package") abslink "$pkgrepo" "$package" [ -d "$package" ] && rm -r "$package" if [ -d "$pkgrepo/$package" ]; then mv "$pkgrepo/$package" "$package" rmdir "$pkgrepo" ls "$package" | awk -v package="$package" '{print package"/"$0}' else err "${COLOR7}error:${ENDCOLOR} failed to retrieve package \`$package'" fi done [[ $pkglist ]] && echo -e "${COLOR6}notice:$ENDCOLOR sourcing from ${COLOR3}[AUR]$ENDCOLOR" for package in "${pkglist[@]}"; do if [[ $package = *~ ]]; then pkgname="${package%\~}" [ -d "$pkgname" ] && rm -rf "${pkgname}/.git" [ -d "$pkgname" ] && rm -r "$pkgname" clonehistory "$pkgname" if [ ! -f "PKGBUILD" ]; then err "${COLOR7}error:${ENDCOLOR} failed to retrieve package \`$pkgname' release $pkgver" fi elif [[ $package = *==* ]]; then pkgname=$(echo "$package" | awk -F "==" '{print $1}') pkgver=$(echo "$package" | awk -F "==" '{print $2}') [ -d "$pkgname" ] && rm -rf "${pkgname}/.git" [ -d "$pkgname" ] && rm -r "$pkgname" clonehistory "$pkgname" "$pkgver" if [ ! -f "PKGBUILD" ]; then err "${COLOR7}error:${ENDCOLOR} failed to retrieve package \`$pkgname' release" fi else curl -Lfs "$(pkglink $package)" > "$package.tar.gz" cstatus=$?; curlyq "$cstatus" "$package" [ -d "$package" ] && rm -rf "${package}/.git" [ -d "$package" ] && rm -r "$package" if [ -f "$package.tar.gz" ]; then mkdir "$package" tar -xzvf "$package.tar.gz" -C "$package" --strip-components=1 else err "${COLOR7}error:${ENDCOLOR} failed to retrieve package \`$package'" fi fi done exit fi # Search (-Ss) handling if [[ $option = search || $option = searchinstall ]]; then # Pacman searching if ! [[ $auronly ]]; then if [[ $quiet ]]; then results="$($pacmanbin -Ssq -- "${packageargs[@]}")" else results="$($pacmanbin -Ss -- "${packageargs[@]}")" results="$(sed -r "s|^[^ ][^/]*/|$S${COLOR3}&$S${COLOR1}|" <<< "$results")" results="$(sed -r "s|^([^ ]+) ([^ ]+)(.*)$|\1 $S${COLOR2}\2$S${ENDCOLOR}\3|" <<< "$results")" results="$(sed -e "s| \[|$S${COLOR4}&|" -e "s|\]|&$S${ENDCOLOR}|" <<< "$results")" fi if [[ $option = search ]]; then echo -e "$results" | fmt -"$_WIDTH" -s else # interactive echo -e "$results" | fmt -"$_WIDTH" -s | nl -v 0 -w 1 -s ' ' -b 'p^[^ ]' fi | sed '/^$/d' pacname=( $($pacmanbin -Ssq -- "${packageargs[@]}") ) pactotal="${#pacname[@]}" else pactotal=0 fi # Aur searching and tmpfile preparation if ! [[ $noaur ]]; then for package in "${packageargs[@]}"; do curl -LfGs --data-urlencode "arg=$package" "$RPCURL=search" | \ jshon -Q -e results -a -e Name -u -p -e Version -u -p -e NumVotes -u -p -e Description -u | \ sed 's/^$/-/' | paste -s -d "\t\t\t\n" | sort -nr -k 3 > "$tmpdir/$package.search" & done wait cp "$tmpdir/${packageargs[0]}.search" "$tmpdir/search.results" for ((i=1 ; i<${#packageargs[@]} ; i++)); do regexmatch="$(echo ${packageargs[$i]} | tr -dc '0-9A-Za-z-.\n')" if [[ ${packageargs[$i]} != $regexmatch ]]; then echo -e "${COLOR6}notice:${ENDCOLOR} enabling regex mode (${packageargs[$i]})" grep --color=always -E "${packageargs[$i]}" "$tmpdir/search.results" > "$tmpdir/search.results-2" else grep -xFf "$tmpdir/search.results" "$tmpdir/${packageargs[$i]}.search" > "$tmpdir/search.results-2" fi mv "$tmpdir/search.results-2" "$tmpdir/search.results" done sed -i '/^$/d' "$tmpdir/search.results" # Check versioning localpkgs=$(pacman -Q) for pkg in $(awk '{print $1}' "$tmpdir/search.results"); do localver=$(echo "$localpkgs" | grep -E "^${pkg}[[:space:]]" 2>/dev/null | awk '{print $2}'); if [ ! -z "$localver" ]; then searchver=$(grep -E "^${pkg}[[:space:]]" "$tmpdir/search.results" | awk '{print $2}') if [ "$searchver" = "$localver" ]; then sed -i "s|$pkg[[:space:]]$searchver|& [installed]|" "$tmpdir/search.results" elif [[ "$(LC_ALL=C vercmp "$searchver" "$localver")" -gt 0 ]]; then sed -i "s|$pkg[[:space:]]$searchver|& [installed: $localver]|" "$tmpdir/search.results" else sed -i "s|$pkg[[:space:]]$searchver|& [local: $localver]|" "$tmpdir/search.results" fi fi done # Prepare tmp file and arrays IFS=$'\n' read -rd '' -a aurname < <(cut -f 1 "$tmpdir/search.results") aurtotal="${#aurname[@]}" alltotal="$(($pactotal+$aurtotal))" else alltotal="$pactotal" fi # Exit if there are no matches if [[ $alltotal = 0 ]]; then echo -e "${COLOR5}==>${COLOR7} no matches${ENDCOLOR}" exit 4 fi # Echo out the -Ss formatted package information IFS=$'\t\n' if [[ $option = search ]]; then if [[ $quiet ]]; then printf "%s\n" ${aurname[@]} elif [[ -s "$tmpdir/search.results" ]]; then resultsaur="$(printf "${COLOR3}aur/${COLOR1}%s ${COLOR2}%s${ENDCOLOR} (%s)\n %s\n" $(cat "$tmpdir/search.results"))" resultsaur="$(sed -e "s| \[|$S${COLOR4}&|" -e "s|\]|&$S${ENDCOLOR}|" <<< "$resultsaur")" echo -e "$resultsaur" fi else # interactive if [[ $quiet ]]; then nl -v ${pactotal:-0} -w 1 -s ' ' <(cut -f 1 "$tmpdir/search.results") elif [[ -s "$tmpdir/search.results" ]]; then resultsaur="$(printf "%d ${COLOR3}aur/${COLOR1}%s ${COLOR2}%s${ENDCOLOR} (%s)\n %s\n" $(nl -v ${pactotal:-0} -w 1 < "$tmpdir/search.results"))" resultsaur="$(sed -e "s| \[|$S${COLOR4}&|" -e "s|\] |&$S${ENDCOLOR}|" <<< "$resultsaur")" echo -e "$resultsaur" fi fi | fmt -"$_WIDTH" -s unset IFS # Prompt and install selected numbers if [[ $option = searchinstall ]]; then pkglist=() allpackages=( "${pacname[@]}" "${aurname[@]}" ) # Prompt for numbers echo echo -e "${COLOR2}Type numbers to install. Separate each number with a space.${ENDCOLOR}" echo -ne "${COLOR2}Numbers: ${ENDCOLOR}" read -r # Parse answer if [[ $REPLY ]]; then for num in $REPLY; do if [[ $num -lt $alltotal ]]; then pkglist+=("${allpackages[$num]}") else err "Number \`$num' is not assigned to any of the packages." fi done fi # Call installhandling to take care of the packages chosen installhandling "${pkglist[@]}" fi # Remove the tmpfiles rm -f "$tmpdir/*search" &>/dev/null rm -f "$tmpdir/search.results" &>/dev/null rm -f "$tmpdir/packages.lst" &>/dev/null exit fi # Info (-Si) handling if [[ $option = info ]]; then # Pacman info check sourcemakepkgconf for package in "${packageargs[@]}"; do if ! [[ $auronly ]] && existsinpacman "$package"; then results="$($pacmanbin -Si -- "$package")" results="$(sed -r "s|^(Repository[^:]*:)(.*)$|\1$S${COLOR3}\2$S${ENDCOLOR}|" <<< "$results")" results="$(sed -r "s|^(Name[^:]*:)(.*)$|\1$S${COLOR1}\2$S${ENDCOLOR}|" <<< "$results")" results="$(sed -r "s|^(Version[^:]*:)(.*)$|\1$S${COLOR2}\2$S${ENDCOLOR}|" <<< "$results")" results="$(sed -r "s|^(URL[^:]*:)(.*)$|\1$S${COLOR4}\2$S${ENDCOLOR}|" <<< "$results")" results="$(sed -r "s|^[^ ][^:]*:|$S${COLOR1}&$S${ENDCOLOR}|" <<< "$results")" echo -e "$results" exit elif ! [[ $noaur ]]; then # Check to see if it is in the aur pkginfo "$package" "$preview" [[ -s "$tmpdir/$package.PKGBUILD" ]] || err "${COLOR7}error:${ENDCOLOR} package '$package' was not found" parser "$tmpdir/$package.PKGBUILD" # Clean temp files [[ $debug ]] || rm "$tmpdir/$package.PKGBUILD" "$tmpdir/$package.info" # Echo out the -Si formatted package information # Retrieve each element in order and echo them immediately echo -e "${COLOR1}Repository : ${COLOR3}aur" echo -e "${COLOR1}Name : $pkgname" echo -e "${COLOR1}Version : ${COLOR2}$pkgver-$pkgrel" echo -e "${COLOR1}URL : ${COLOR4}$url" echo -e "${COLOR1}AUR : ${COLOR4}$PKGURL/packages/$pkgname/" echo -e "${COLOR1}Licenses : ${ENDCOLOR}${license[@]}" echo -e "${COLOR1}Groups : ${ENDCOLOR}${groups[@]:-None}" echo -e "${COLOR1}Provides : ${ENDCOLOR}${provides[@]:-None}" echo -e "${COLOR1}Depends On : ${ENDCOLOR}${depends[@]}" echo -e "${COLOR1}Make Depends : ${ENDCOLOR}${makedepends[@]}" echo -e -n "${COLOR1}Optional Deps : ${ENDCOLOR}" len="${#optdepends[@]}" if [[ $len -eq 0 ]]; then echo "None" else for ((i=0 ; i<$len ; i++)); do if [[ $i = 0 ]]; then echo "${optdepends[$i]}" else echo -e " ${optdepends[$i]}" fi done fi echo -e "${COLOR1}Conflicts With : ${ENDCOLOR}${conflicts[@]:-None}" echo -e "${COLOR1}Replaces : ${ENDCOLOR}${replaces[@]:-None}" echo -e "${COLOR1}Architecture : ${ENDCOLOR}${arch[@]}" echo -e "${COLOR1}Description : ${ENDCOLOR}$pkgdesc" echo else err "${COLOR7}error:${ENDCOLOR} package '$package' was not found" fi done fi # Web Comments (-W) handling if [[ $option = web ]]; then sourcemakepkgconf for package in "${packageargs[@]}"; do if ! [[ $auronly ]] && existsinpacman "$package"; then echo -e "${COLOR7}error:${ENDCOLOR} comments unavailable for non-AUR package '$package'" elif ! [[ $noaur ]]; then # Check to see if it is in the aur curl -Lfs "$PKGURL/packages/$package/?comments=all" > "$tmpdir/$package.html" cstatus=$?; curlyq "$cstatus" "$package" [[ -s "$tmpdir/$package.html" ]] || err "${COLOR7}error:${ENDCOLOR} package '$package' was not found" div="%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" separator="${COLOR3}${div}${div}${ENDCOLOR}" header="${COLOR4}*******************************${ENDCOLOR}" comments="$(sed '/