#!/bin/sh # # scratchpkg # # Copyright (c) 2018 by Emmett1 (emmett1.2miligrams@gmail.com) # # 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 . # RED='\033[31m' GREEN='\033[32m' YELLOW='\033[33m' CYAN='\033[36m' PURPLE='\033[35m' CRESET='\033[0m' nocolor() { RED= GREEN= YELLOW= CYAN= PURPLE= CRESET= } msg() { printf "${GREEN}==>${CRESET} %s\n" "$1" } msginst() { printf "[${GREEN}i${CRESET}] %s\n" "$1" } msgmiss() { printf "[${YELLOW}m${CRESET}] %s\n" "$1" } msgnoinst() { printf "[-] %s\n" "$1" } msgerr() { printf "${RED}==> ERROR:${CRESET} %s\n" "$1" >&2 } msgwarn() { printf "${YELLOW}==> WARNING:${CRESET} %s\n" "$1" >&2 } needroot() { if [ "$(id -u)" != 0 ]; then if [ "$#" -eq 0 ]; then needroot "This operation" else msgerr "$* need root access!" fi exit 1 fi } getportpath() { for repo in $PORT_REPO; do if [ -f "$repo/$1/$BUILD_SCRIPT" ]; then dirname "$repo/$1/$BUILD_SCRIPT" return 0 fi done return 1 } vercomp() { if [ "$1" = "$2" ]; then return 0 # same version elif [ "$1" = "$(echo "$1\n$2" | sort -V | head -n1)" ]; then return 1 # $1 lower than $2 else return 2 # $1 higher than $2 fi } get_iver() { head -n1 $PKGDB_DIR/$1 2>/dev/null | awk '{print $1}' } get_irelease() { head -n1 $PKGDB_DIR/$1 2>/dev/null | awk '{print $2}' } allinstalled() { for i in $PKGDB_DIR/*; do echo ${i##*/} done } deps_alias() { [ -f "$ALIAS_FILE" ] || { echo $@ return } while [ "$1" ]; do if [ "$(grep -w ^$1 $ALIAS_FILE)" ]; then getalias=$(grep -w ^$1 $ALIAS_FILE | awk '{print $2}') [ "$getalias" ] && echo "$getalias" else echo "$1" fi shift unset getalias done } get_depends() { ppath=$(getportpath $1) || return 0 deps=$(grep "^# depends[[:blank:]]*:" $ppath/$BUILD_SCRIPT \ | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' \ | tr ' ' '\n' \ | awk '!a[$0]++' \ | sed 's/,//') deps_alias $deps } confirm() { printf "$1 (Y/n) " read -r response case "$response" in [Nn][Oo]|[Nn]) echo "$2"; return 2 ;; *) : ;; esac return 0 } checktool() { if ! command -v $1 >/dev/null; then msgerr "'$1' not exist in your system!" exit 1 fi } needarg() { [ "$*" ] || { msgerr "This operation required an arguments!" exit 1 } } settermtitle() { printf "\033]0;$*\a" } scratch_integrity() { if [ "$1" ]; then cd / if [ -f $PKGDB_DIR/$1 ]; then tail -n+2 $PKGDB_DIR/$1 | while read -r line; do if [ ! -e "$line" ]; then if [ -L "$line" ]; then printf "${YELLOW}broken symlink${CRESET} $1: /$line" else printf "${RED}file missing${CRESET} $1: /$line" fi fi done else echo "Package '$1' not installed." exit 1 fi cd - >/dev/null else cd / for pkg in $(allinstalled); do tail -n+2 $PKGDB_DIR/$pkg | while read -r line; do if [ ! -e "$line" ]; then if [ -L "$line" ]; then echo "broken symlink $pkg: /$line" else echo "missing file $pkg: /$line" fi fi done done cd - >/dev/null fi } scratch_locate() { needarg $@ for repo in $PORT_REPO; do grep -Ri $@ $repo/*/.pkgfiles 2>/dev/null | sed 's/:/ /;s/\/\.pkgfiles//' | awk '{print $1,$4}' done } scratch_isorphan() { needarg $@ for pkg in $(allinstalled); do if depend=$(get_depends $pkg); then for dep in $depend; do if [ $dep = $1 ]; then return 1 fi done fi unset depend dep done return 0 } scratch_sync() { portsync } cvperms() { # converts symbolic to numeric permissions # required an input (symbolic, eg: drwxr-xr-x) s=0; n=0; count=0 for i in $(echo "$1" | sed -e 's/\(.\)/\1\n/g'); do count=$((count+1)) case $i in d) ;; r) n=$((n+4));; w) n=$((n+2));; x) n=$((n+1));; s) [ $count = 4 ] && s=$((s+4)) || s=$((s+2)); n=$((n+1));; t) s=$((s+1));n=$((n+1));; S) s=$((s+2));; T) s=$((s+1));; esac [ "$count" = 4 ] && { user=$n; n=0 } [ "$count" = 7 ] && { group=$n; n=0 } [ "$count" = 10 ] && { other=$n; n=0 } done echo "$s$user$group$other" } fixperms() { needroot "Fix permissions" for i in $PKGDBPERMS_DIR/*; do [ -s $i ] || continue while read -r perms own dir junk; do chmod $(cvperms $perms) /$dir echo $own | while IFS=/ read -r o g; do chown $o:$g /$dir done done < $i done } scratch_trigger() { needroot "Run trigger" if [ -z "$*" ]; then for i in $(seq 12); do eval trig_$i=1 done else pre_triggers $@ fi post_triggers } post_triggers() { if [ "$trig_11" = 1 ] && [ $(command -v fc-cache) ]; then echo "trigger: Updating fontconfig cache..." fc-cache -s fi if [ "$trig_10" = 1 ] && [ $(command -v gdk-pixbuf-query-loaders) ]; then echo "trigger: Probing GDK-Pixbuf loader modules..." gdk-pixbuf-query-loaders --update-cache fi if [ "$trig_9" = 1 ] && [ $(command -v gio-querymodules) ]; then echo "trigger: Updating GIO module cache..." gio-querymodules /usr/lib/gio/modules fi if [ "$trig_8" = 1 ] && [ $(command -v glib-compile-schemas) ]; then echo "trigger: Compiling GSettings XML schema files..." glib-compile-schemas /usr/share/glib-2.0/schemas fi if [ "$trig_7" = 1 ] && [ $(command -v gtk-query-immodules-2.0) ]; then echo "trigger: Probing GTK2 input method modules..." gtk-query-immodules-2.0 --update-cache fi if [ "$trig_6" = 1 ] && [ $(command -v gtk-query-immodules-3.0) ]; then echo "trigger: Probing GTK3 input method modules..." gtk-query-immodules-3.0 --update-cache fi if [ "$trig_5" = 1 ] && [ $(command -v gtk-update-icon-cache) ]; then echo "trigger: Updating icon theme caches..." for dir in /usr/share/icons/* ; do if [ -e $dir/index.theme ]; then gtk-update-icon-cache -q $dir 2>/dev/null else rm -f $dir/icon-theme.cache rmdir --ignore-fail-on-non-empty $dir fi done fi if [ "$trig_4" = 1 ] && [ $(command -v udevadm) ]; then echo "trigger: Updating hardware database..." udevadm hwdb --update fi if [ "$trig_3" = 1 ] && [ $(command -v mkfontdir) ] && [ $(command -v mkfontscale) ]; then echo "trigger: Updating X fontdir indices..." for dir in $(find /usr/share/fonts -maxdepth 1 -type d \( ! -path /usr/share/fonts \)); do rm -f $dir/fonts.scale $dir/fonts.dir $dir/.uuid rmdir --ignore-fail-on-non-empty $dir [ -d "$dir" ] || continue mkfontdir $dir mkfontscale $dir done fi if [ "$trig_2" = 1 ] && [ $(command -v update-desktop-database) ]; then echo "trigger: Updating desktop file MIME type cache..." update-desktop-database --quiet fi if [ "$trig_1" = 1 ] && [ $(command -v update-mime-database) ]; then echo "trigger: Updating the MIME type database..." update-mime-database /usr/share/mime fi fixperms } pre_triggers() { # mime db if [ "$trig_1" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/mime/$ $PKGDB_DIR/$pkg)" ]; then trig_1=1 break fi done fi # desktop db if [ "$trig_2" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/applications/$ $PKGDB_DIR/$pkg)" ]; then trig_2=1 break fi done fi # mkfontdir if [ "$trig_3" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/fonts/$ $PKGDB_DIR/$pkg)" ]; then trig_3=1 break fi done fi # hwdb if [ "$trig_4" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^etc/udev/hwdb.d/$ $PKGDB_DIR/$pkg)" ]; then trig_4=1 break fi done fi # icon caches if [ "$trig_5" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/icons/$ $PKGDB_DIR/$pkg)" ]; then trig_5=1 break fi done fi # gtk3 immodules if [ "$trig_6" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/lib/gtk-3.0/3.0.0/immodules/.*.so $PKGDB_DIR/$pkg)" ]; then trig_6=1 break fi done fi # gtk2 immodules if [ "$trig_7" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/lib/gtk-2.0/2.10.0/immodules/.*.so $PKGDB_DIR/$pkg)" ]; then trig_7=1 break fi done fi # gsettings schema if [ "$trig_8" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/glib-2.0/schemas/$ $PKGDB_DIR/$pkg)" ]; then trig_8=1 break fi done fi # gio modules if [ "$trig_9" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/lib/gio/modules/.*.so $PKGDB_DIR/$pkg)" ]; then trig_9=1 break fi done fi # gdk-pixbuf if [ "$trig_10" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/lib/gdk-pixbuf-2.0/2.10.0/loaders/.*.so $PKGDB_DIR/$pkg)" ]; then trig_10=1 break fi done fi # font caches if [ "$trig_11" != "1" ]; then for pkg in $@; do if [ -s "$PKGDB_DIR/$pkg" ] && [ "$(grep ^usr/share/fonts/$ $PKGDB_DIR/$pkg)" ]; then trig_11=1 break fi done fi } scratch_build() { while [ "$1" ]; do case $1 in -i|-u|-r|-g|-p) ;; --log) LOG=1;; -*) OPTS="$OPTS $1";; *) PKGNAME="$PKGNAME $1";; esac shift done [ "$PKGNAME" ] || { echo "Please specify package(s) to build." return 1 } for pkg in $PKGNAME; do ppath=$(getportpath $pkg) || { echo "Package '$pkg' not found." return 1 } cd $ppath settermtitle "Building $pkg..." if [ "$LOG" ]; then pkgbuild $OPTS | tee /var/log/pkgbuild.log || { settermtitle "Building $pkg failed." return 1 } else pkgbuild $OPTS || { settermtitle "Building $pkg failed." return 1 } fi settermtitle "Building $pkg done." cd - >/dev/null done } scratch_install() { needroot "Installing package" while [ "$1" ]; do case $1 in -i|-u) ;; -r) REINSTALL=1;; -o) DOWNLOAD_ONLY=1; OPTS="$OPTS $1";; -y) NOCONFIRM=1;; -n) NO_DEP=1;; --exclude=*) EXOPT=$1;; -*) OPTS="$OPTS $1";; *) PKGNAME="$PKGNAME $1";; esac shift done [ "$PKGNAME" ] || { echo "Please specify package(s) to install." return 1 } # if reinstall, dont calculate dep, just reinstall it then exit if [ "$REINSTALL" = 1 ]; then error=0 for ii in $PKGNAME; do if [ ! $(getportpath $ii) ]; then echo "Package '$ii' not found." elif ! scratch_isinstalled $ii; then echo "Package '$ii' not installed." else cd $(getportpath $ii) settermtitle "Reinstalling $ii..." pkgbuild $OPTS -r || { error=1 break } done_pkg="$done_pkg $ii" cd - >/dev/null fi done run_trigger settermtitle "Package(s) reinstalled." return "$error" fi if [ "$NO_DEP" = 1 ]; then error=0 for ii in $PKGNAME; do if [ ! $(getportpath $ii) ]; then echo "Package '$ii' not found." elif scratch_isinstalled $ii; then echo "Package '$ii' already installed." continue else cd $(getportpath $ii) settermtitle "Installing $ii..." pkgbuild -i $OPTS || { error=1 break } done_pkg="$done_pkg $ii" cd - >/dev/null fi done run_trigger settermtitle "Package(s) installed." return "$error" fi for i in $PKGNAME; do if [ ! $(getportpath $i) ]; then echo "Package '$i' not found." elif scratch_isinstalled $i; then echo "Package '$i' already installed." else IPKG="$IPKG $i" fi done [ "$IPKG" ] || return 0 echo "Resolving dependencies..." INST="$(scratch_deplist -q $IPKG $EXOPT)" if [ "$INST" ]; then echo pkgcount=0 for pkg in $INST; do pkgcount=$(( pkgcount + 1 )) printf "[${GREEN}i${CRESET}] $pkg " done echo; echo echo "( $pkgcount install )" echo if [ ! "$NOCONFIRM" ]; then confirm "Continue install package(s)?" "Package installation cancelled." || exit $? echo fi error=0 count=0 total=$(echo $INST | wc -w) for int in $INST; do count=$(( count + 1 )) if portpathh=$(getportpath $int); then cd $portpathh settermtitle "[ $count/$total ] installing $int..." run_preinstallsh pkgbuild -i $OPTS || { error=1 count=$(( count - 1 )) break } run_postinstallsh done_pkg="$done_pkg $int" cd - >/dev/null else msgwarn "Skipping missing package: $int" fi unset portpathh done run_trigger settermtitle "$count/$total package(s) installed." return "$error" fi } scratch_remove() { needroot "Removing package" while [ "$1" ]; do case $1 in -y|--yes) NOCONFIRM=1;; -*) OPTS="$OPTS $1";; *) PKGNAME="$PKGNAME $1";; esac shift done [ "$PKGNAME" ] || { echo "Please specify package(s) to remove." return 1 } for i in $PKGNAME; do if ! scratch_isinstalled $i; then echo "Package '$i' not installed." else IPKG="$IPKG $i" fi done [ "$IPKG" ] || return 0 echo "Removing packages..." echo pkgcount=0 count=0 for pkg in $IPKG; do pkgcount=$(( pkgcount + 1 )) printf "[${RED}x${CRESET}] $pkg " done echo; echo echo "( $pkgcount remove )" echo [ "$NOCONFIRM" ] || { confirm "Continue remove package(s)?" "Package removing cancelled." || exit $? echo } for pkg in $IPKG; do count=$(( count + 1 )) pre_triggers $pkg settermtitle "[ $count/$pkgcount ] Removing $pkg..." pkgdel $pkg $OPTS || { error=1 break } done settermtitle "Triggering remove hook..." post_triggers settermtitle "$pkgcount package(s) removed." } outdatepkg() { OLDIFS=$IFS IFS=, for i in ${1#*=}; do exclude="$exclude $i"; done IFS=$OLDIFS for pkg in $(allinstalled); do echo $exclude | grep -qw $pkg && continue if [ -f "$MASK_FILE" ] && [ $(grep -Ev '^(#|$| )' $MASK_FILE | grep -x $pkg) ]; then continue fi getportpath $pkg >/dev/null || continue . $(getportpath $pkg)/$BUILD_SCRIPT if [ ! "$name" ] || [ ! "$version" ]; then continue fi iversion=$(get_iver $pkg) irelease=$(get_irelease $pkg) if [ "$release" != "$irelease" ] || [ "$version" != "$iversion" ]; then echo $name fi unset iversion irelease version release done } scratch_sysup() { needroot "Upgrading package" while [ "$1" ]; do case $1 in -i|-u|-r) ;; -o) DOWNLOAD_ONLY=1; OPTS="$OPTS $1";; -y) NOCONFIRM=1;; -n) NODEP=1;; --exclude=*) EXOPT=$1;; -*) OPTS="$OPTS $1";; esac shift done echo "Checking for outdated packages..." PKGOUTDATE=$(outdatepkg $EXOPT) [ "$PKGOUTDATE" ] || { echo "All packages are up to date." return 0 } [ "$(echo $PKGOUTDATE | tr ' ' '\n' | grep -x scratchpkg)" ] && { echo msgerr "Please upgrade 'scratchpkg' first." return 1 } UPGPKG=0 NEWPKG=0 if [ "$NODEP" != 1 ]; then echo "Resolving dependencies..." DEP=$(scratch_deplist $PKGOUTDATE $EXOPT | awk '{print $2}') echo for d in $DEP; do if [ "$(echo $PKGOUTDATE | tr ' ' '\n' | grep -x $d)" = "$d" ]; then printf "[${GREEN}u${CRESET}] $d " WILLINSTALL="$WILLINSTALL $d" UPGPKG=$(( UPGPKG + 1 )) elif ! scratch_isinstalled $d && [ "$(getportpath "$d")" ]; then printf "[${CYAN}n${CRESET}] $d " WILLINSTALL="$WILLINSTALL $d" NEWPKG=$(( NEWPKG + 1 )) fi done else echo for dd in $PKGOUTDATE; do printf "[${GREEN}u${CRESET}] $dd " WILLINSTALL="$WILLINSTALL $dd" UPGPKG=$(( UPGPKG + 1 )) done fi echo; echo echo "( $UPGPKG upgrade, $NEWPKG new install )" echo [ "$NOCONFIRM" ] || { confirm "Continue upgrade/install these package(s)?" "Package upgrade cancelled." || exit $? echo } error=0 count=0 total=$(echo $WILLINSTALL | wc -w) for inst in $WILLINSTALL; do # install all required dependencies and target packages itself count=$(( count + 1 )) cd $(getportpath $inst) if ! scratch_isinstalled $inst; then settermtitle "[ $count/$total ] Installing $inst..." run_preinstallsh pkgbuild -i $OPTS || { error=1 count=$(( count - 1 )) break } run_postinstallsh else settermtitle "[ $count/$total ] Upgrading $inst..." run_preinstallsh pkgbuild -u $OPTS || { error=1 count=$(( count - 1 )) break } run_postinstallsh fi cd - >/dev/null done_pkg="$done_pkg $inst" done run_trigger settermtitle "$count/$total package(s) upgraded." return "$error" } run_trigger() { # if using -o (download only), dont run trigger if [ ! "$DOWNLOAD_ONLY" ]; then [ "$done_pkg" ] && { settermtitle "Triggering install hook..." scratch_trigger $done_pkg } fi } run_preinstallsh() { # if using -o (download only), dont run pre-install.sh script if [ ! "$DOWNLOAD_ONLY" ]; then [ -f ./pre-install.sh ] && sh ./pre-install.sh fi } run_postinstallsh() { # if using -o (download only), dont run post-install.sh script if [ ! "$DOWNLOAD_ONLY" ]; then [ -f ./post-install.sh ] && sh ./post-install.sh fi } scratch_upgrade() { needroot "Upgrading package" while [ "$1" ]; do case $1 in -i|-r) ;; -y) NOCONFIRM=1;; -o) DOWNLOAD_ONLY=1; OPTS="$OPTS $1";; -d) NO_DEP=1;; --exclude=*) EXOPT=$1;; -*) OPTS="$OPTS $1";; *) PKGNAME="$PKGNAME $1";; esac shift done [ "$PKGNAME" ] || { echo "Please specify package(s) to upgrade." return 1 } for pkg in $PKGNAME; do if ! scratch_isinstalled $pkg; then echo "Package '$pkg' not installed." continue elif [ ! $(getportpath $pkg) ]; then echo "Package '$pkg' not exist." continue else . $(getportpath $pkg)/$BUILD_SCRIPT if [ "$(get_iver $pkg)-$(get_irelease $pkg)" = "$version-$release" ]; then echo "Package '$pkg' is up to date." continue fi fi upkg="$upkg $pkg" done [ "$upkg" ] || return 0 UPGPKG=0 NEWPKG=0 if [ "$NODEP" != 1 ]; then echo "Resolving dependencies..." DEP=$(scratch_deplist $upkg $EXOPT | awk '{print $2}') echo for d in $DEP; do if [ "$(echo $upkg | tr ' ' '\n' | grep -x $d)" = "$d" ]; then printf "[${GREEN}u${CRESET}] $d " WILLINSTALL="$WILLINSTALL $d" UPGPKG=$(( UPGPKG + 1 )) elif ! scratch_isinstalled $d && [ "$(getportpath "$d")" ]; then printf "[${CYAN}n${CRESET}] $d " WILLINSTALL="$WILLINSTALL $d" NEWPKG=$(( NEWPKG + 1 )) fi done else echo for dd in $upkg; do printf "[${GREEN}u${CRESET}] $dd " WILLINSTALL="$WILLINSTALL $dd" UPGPKG=$(( UPGPKG + 1 )) done fi echo; echo echo "( $UPGPKG upgrade, $NEWPKG new install )" echo [ "$NOCONFIRM" ] || { confirm "Continue upgrade/install these package(s)?" "Package upgrade cancelled." || exit $? echo } error=0 count=0 total=$(echo $WILLINSTALL | wc -w) for inst in $WILLINSTALL; do # install all required dependencies and target packages itself count=$(( count + 1 )) cd $(getportpath $inst) if ! scratch_isinstalled $inst; then settermtitle "[ $count/$total ] Installing $inst..." run_preinstallsh pkgbuild -i $OPTS || { error=1 count=$(( count - 1 )) break } run_postinstallsh else settermtitle "[ $count/$total ] Upgrading $inst..." run_preinstallsh pkgbuild -u $OPTS || { error=1 count=$(( count - 1 )) break } run_postinstallsh fi cd - >/dev/null done_pkg="$done_pkg $inst" done run_trigger settermtitle "$count/$total package(s) upgraded." return "$error" } scratch_isinstalled() { [ "$1" ] || return 1 [ -f "$PKGDB_DIR/$1" ] || return 1 return 0 } scratch_outdate() { for pkg in $(allinstalled); do if [ "$(getportpath $pkg)" ]; then . $(getportpath $pkg)/$BUILD_SCRIPT if [ -z "$name" ] || [ -z "$version" ]; then continue fi iversion=$(get_iver $pkg) irelease=$(get_irelease $pkg) if [ -f "$MASK_FILE" ] && [ $(grep -Ev '^(#|$| )' $MASK_FILE | grep $pkg) ]; then ITSLOCK="[masked]" fi outdatemsg="$name $iversion-$irelease => $version-$release $ITSLOCK" newerinstmsg="$name $iversion-$irelease => $version-$release [newer installed] $ITSLOCK" if [ "$version" != "$iversion" ]; then vercomp $version $iversion if [ $? = 2 ]; then echo "$outdatemsg" OUTDATE=yes elif [ $? = 1 ]; then echo "$newerinstmsg" OUTDATE=yes fi elif [ "$release" != "$irelease" ]; then vercomp $release $irelease if [ $? = 2 ]; then echo "$outdatemsg" OUTDATE=yes elif [ $? = 1 ]; then echo "$newerinstmsg" OUTDATE=yes fi fi unset ITSLOCK name version fi done [ ! "$OUTDATE" ] && msg "All packages are up to date." } scratch_search() { needarg $@ arg=$* for repo in $PORT_REPO; do [ -d $repo ] || continue out=$(grep -R "# description" $repo/*/$BUILD_SCRIPT | grep -i "$arg" | awk -F : '{print $1}' | sort) [ "$out" ] || continue found=1 for line in $out; do repo=$(echo $line | rev | awk -F / '{print $3}' | rev) desc=$(grep "^# description[[:blank:]]*:" $line | sed 's/^# description[[:blank:]]*:[[:blank:]]*//') . $line if scratch_isinstalled $name; then ins="[${GREEN}*${CRESET}]" else ins="[ ]" fi printf "$ins ${PURPLE}($repo)${CRESET} $name ${CYAN}$version-$release${CRESET}: $desc\n" unset repo desc name version release build done unset out done if [ ! "$found" ]; then msg "No matching package found." fi } scratch_cache() { needroot "Clear old caches" allcachepkg=/tmp/.allcachepkg.$$ allcachesrc=/tmp/.allcachesrc.$$ keepcachepkg=/tmp/.keepcachepkg.$$ keepcachesrc=/tmp/.keepcachesrc.$$ diffcachepkg=/tmp/.diffcachepkg.$$ diffcachesrc=/tmp/.diffcachesrc.$$ touch \ $allcachepkg \ $allcachesrc \ $keepcachepkg \ $keepcachesrc \ $diffcachepkg \ $diffcachesrc if [ "$(find $PACKAGE_DIR -mindepth 1 -print -quit 2>/dev/null)" ]; then for list in "$PACKAGE_DIR"/*; do basename $list >> "$allcachepkg" done fi if [ "$(find $SOURCE_DIR -mindepth 1 -print -quit 2>/dev/null)" ]; then for list in "$SOURCE_DIR"/*; do basename $list >> "$allcachesrc" done fi for repo in $PORT_REPO; do if [ "$(find $repo/*/ -mindepth 1 -print -quit 2>/dev/null)" ]; then # check directory if its not empty for port in $repo/*/$BUILD_SCRIPT; do . $port echo "$name-$version-$release.spkg.tar.$COMPRESSION_MODE" >> "$keepcachepkg" if [ "$source" ]; then for src in $source; do if echo $src | grep -Eq "(ftp|http|https)://"; then if echo $src | grep -Eq "::(ftp|http|https)://"; then sourcename="$(echo $src | awk -F '::' '{print $1}')" else sourcename="$(echo $src | rev | cut -d / -f 1 | rev)" fi echo $sourcename >> "$keepcachesrc" fi done fi done fi done grep -Fxv -f "$keepcachepkg" "$allcachepkg" > "$diffcachepkg" grep -Fxv -f "$keepcachesrc" "$allcachesrc" > "$diffcachesrc" cat $diffcachepkg cat $diffcachesrc if [ -s "$diffcachepkg" ]; then cd "$PACKAGE_DIR" sizepkg=$(du -ch $(cat $diffcachepkg) | grep total | awk '{print $1}') cd - >/dev/null else sizepkg=0M fi if [ -s "$diffcachesrc" ]; then cd "$SOURCE_DIR" sizesrc=$(du -ch $(cat $diffcachesrc) | grep total | awk '{print $1}') cd - >/dev/null else sizesrc=0M fi echo "Total package cache size: $sizepkg" echo "Total source cache size : $sizesrc" if [ -s "$diffcachepkg" ] || [ -s "$diffcachesrc" ]; then echo confirm "Clear old caches?" "Old caches is kept." && { for i in $(cat $diffcachepkg); do [ -e "$PACKAGE_DIR/$i" ] && rm -v "$PACKAGE_DIR/$i" done for i in $(cat $diffcachesrc); do [ -e "$SOURCE_DIR/$i" ] && rm -v "$SOURCE_DIR/$i" done } fi rm -f \ "$allcachepkg" \ "$allcachesrc" \ "$keepcachepkg" \ "$keepcachesrc" \ "$diffcachepkg" \ "$diffcachesrc" } scratch_deplist() { OLDIFS=$IFS IFS=, while [ "$1" ]; do case $1 in -q) quick=1;; --exclude=*) for i in ${1#*=}; do exclude="$exclude $i"; done;; -*) ;; *) PKG="$PKG $1";; esac shift done IFS=$OLDIFS [ "$PKG" ] || { echo "Please specify package(s) to list dependencies." return 1 } for p in $PKG; do if [ "$(getportpath $p)" ]; then PPKG="$PPKG $p" else [ "$quick" = 1 ] || msgerr "Package '$p' not exist." fi done for p in $PPKG; do deplist $p done [ "$DEP" ] || return 0 if [ "$quick" = 1 ]; then echo $DEP | tr ' ' '\n' else for p in $DEP; do if scratch_isinstalled $p; then echo "[*] $p" else echo "[-] $p" fi done if [ "$MISSINGDEP" ]; then for m in $MISSINGDEP; do echo "Missing deps: $m" | sed 's/(/ (/' done fi fi } deplist() { # skip excluded dependencies if echo $exclude | tr " " "\n" | grep -qx $1; then return 0 fi # check currently process for circular dependencies # for circular dependencies, found first will take precedence [ "$CHECK" ] && { if echo $CHECK | tr " " "\n" | grep -qx $1; then return 0 fi } # add package to currently process CHECK="$CHECK $1" # check dependencies for i in $(get_depends $1); do if [ "$quick" = 1 ] && scratch_isinstalled $i; then continue else if ! echo $DEP | tr " " "\n" | grep -qx $i; then if ! getportpath $i >/dev/null; then MISSINGDEP="$MISSINGDEP $i($1)" else deplist $i fi fi fi done # add dependency to list checked dep if ! echo $DEP | tr " " "\n" | grep -qx $1; then if [ "$quick" = 1 ]; then scratch_isinstalled $1 || DEP="$DEP $1" else DEP="$DEP $1" fi fi # delete item from loop process CHECK=$(echo $CHECK | sed "s/$1//") } scratch_cat() { needarg $@ if PPATH=$(getportpath "$1"); then cat "$PPATH/$BUILD_SCRIPT" else msgerr "Port '$1' not exist." return 1 fi } scratch_dependent() { needarg $@ if [ "$(getportpath $1)" ]; then grep -R "# depends[[:blank:]]*:" $PORT_REPO \ | sed "s,:# depends[[:blank:]]*:[[:blank:]]*,#|,;s, ,|,g;s,$,|,g" \ | grep "|$1|" \ | awk -F "#" '{print $1}' \ | rev \ | awk -F / '{print $2}' \ | rev else msgerr "Port '$1' not exist." return 1 fi } scratch_depends() { needarg $@ if getportpath "$1" >/dev/null; then depends=$(get_depends $1) else msgerr "Port '$1' not exist." return 1 fi for dep in $depends; do if scratch_isinstalled $dep; then msginst "$dep" elif getportpath $dep >/dev/null; then msgnoinst "$dep" else msgmiss "$dep" fi done } scratch_dup() { dup=$(find $PORT_REPO -type d -print | grep -Exv "($(echo $PORT_REPO | tr ' ' '|'))" | \ rev | cut -d '/' -f1 | rev | sort | uniq -d) if [ "$dup" ]; then for dp in $dup; do for repo in $PORT_REPO; do [ -d $repo/$dp ] && echo "$repo/$dp" done done else msg "No duplicate ports found." fi } scratch_foreign() { for pkg in $(allinstalled); do if ! getportpath $pkg >/dev/null; then iversion=$(get_iver $pkg) irelease=$(get_irelease $pkg) echo "$pkg $iversion-$irelease" fi unset pkg iversion irelease done } scratch_info() { needarg $@ ppath=$(getportpath $1) || return 1 . $ppath/$BUILD_SCRIPT desc=$(grep "^# description[[:blank:]]*:" $ppath/$BUILD_SCRIPT | sed 's/^# description[[:blank:]]*:[[:blank:]]*//') maint=$(grep "^# maintainer[[:blank:]]*:" $ppath/$BUILD_SCRIPT | sed 's/^# maintainer[[:blank:]]*:[[:blank:]]*//') homep=$(grep "^# homep[[:blank:]]*:" $ppath/$BUILD_SCRIPT | sed 's/^# homepage[[:blank:]]*:[[:blank:]]*//') deps=$(get_depends $1 | tr '\n' ' ') echo "Name: $1" echo "Path: $ppath" echo "Version: $version" echo "Release: $release" echo "Description: $desc" echo "Maintainer: $maint" echo "Homepage: $homep" echo "Dependencies: $deps" echo "Installed: $(get_iver $1)-$(get_irelease $1)" } scratch_installed() { for all in $(allinstalled); do echo "$all $(get_iver $all)-$(get_irelease $all)" done } scratch_missingdep() { for pkg in $(allinstalled); do if getportpath "$pkg" >/dev/null; then depends=$(get_depends $pkg) fi if [ "$depends" ]; then for d in $depends; do if ! scratch_isinstalled $d; then if [ -z "$msd" ]; then msd="$d" else msd="$msd $d" fi fi done fi [ "$msd" ] && echo "$pkg: $msd" unset depends msd done } scratch_orphan() { tmpallpkg="/tmp/.pkgquery_allpkg.$$" tmpalldep="/tmp/.pkgquery_alldep.$$" for pkg in $(allinstalled); do echo $pkg >> $tmpallpkg dep="$dep $(get_depends $pkg)" done echo $dep | tr ' ' '\n' | sort | uniq > "$tmpalldep" grep -xvF -f "$tmpalldep" "$tmpallpkg" rm "$tmpalldep" "$tmpallpkg" } scratch_path() { needarg $@ if PPATH=$(getportpath "$1"); then echo "$PPATH" else msgerr "Port '$1' not exist." return 1 fi } scratch_provide() { needarg $@ arg=$(echo $1 | sed "s/^\///") grep -R "$arg" $PKGDB_DIR/* \ | sed "s:$PKGDB_DIR/::" \ | tr : "\t" } scratch_readme() { needarg $@ if PPATH=$(getportpath "$1"); then if [ -f "$PPATH/readme" ]; then cat "$PPATH/readme" else msgerr "Port '$1' does not have readme." fi else msgerr "Port '$1' not exist." exit 1 fi } scratch_printconfig() { echo "MAINOPTS: $MAINOPTS" echo "REPO_FILE: $REPO_FILE" echo "MASK_FILE: $MASK_FILE" echo "CONFIG_FILE: $CONFIG_FILE" echo "CFLAGS: $CFLAGS" echo "CXXFLAGS: $CXXFLAGS" echo "MAKEFLAGS: $MAKEFLAGS" echo "CURL_OPTS: $CURL_OPTS" echo "COMPRESSION_MODE: $COMPRESSION_MODE" echo "NO_STRIP: $NO_STRIP" echo "IGNORE_MDSUM: $IGNORE_MDSUM" echo "KEEP_LIBTOOL: $KEEP_LIBTOOL" echo "KEEP_LOCALE: $KEEP_LOCALE" echo "KEEP_DOC: $KEEP_DOC" echo "SOURCE_DIR: $SOURCE_DIR" echo "PACKAGE_DIR: $PACKAGE_DIR" echo "PORT_REPO:" for i in $PORT_REPO; do echo " $i" done } scratch_files() { needarg $@ if scratch_isinstalled $1; then cat "$PKGDB_DIR/$1" else msg "Package '$1' not installed." fi } scratch_help() { cat << EOF Usage: $(basename $0) [] Options: install install ports (use pkgbuild arg, except '-i' & '-u') -r reinstall -n skip dependencies -y skip ask user confirmation -o fetch sources only --exclude=* exclude dependencies, comma separated upgrade upgrade ports (use pkgbuild arg, except '-i' & '-r') -n skip dependencies -y skip ask user confirmation -o fetch sources only --exclude=* exclude dependencies, comma separated remove remove installed ports (use pkgdel arg) -y skip ask user confirmation sysup full system upgrade (use pkgbuild arg, except '-i', '-r' & '-u') -n skip dependencies -y skip ask user confirmation -o fetch sources only --exclude=* exclude dependencies, comma separated deplist print all dependencies for ports -q skip installed ports --exclude=* exclude dependencies, comma separated build build ports (use pkgbuild arg, except '-i', '-u', '-r', '-g', & '-p') --log log build process (/var/log/pkgbuild.log) trigger [ports] run system trigger search find ports in repo cat print spkgbuild depends print dependencies dependent print dependent path print path in repo provide print port's provided file readme print readme file, if exist files print files installed info print information locate print location of file in ports repo isinstalled check whether port is installed (status 0=installed, 1=not installed) sync update ports database outdate print outdated ports cache print and clear old pkg and src caches integrity check installed port integrity dup print duplicate ports in repo installed print all installed ports missingdep print missing dependencies orphan print orphan installed ports foreign print foreign ports printconfig print scratchpkg configs help print this help msg Global options: --append-repo= append custom local repo path (can use multiple times) --prepend-repo= prepend custom local repo path (can use multiple times) --override-repo= override repo in $REPO_FILE with custom local repo (can use multiple times) --repo-file= use custom repo file (default: $REPO_FILE) --config-file= use custom config file (default: $CONFIG_FILE) --alias-file= use custom alias file (default: $ALIAS_FILE) --mask-file= use custom mask file (default: $MASK_FILE) --nocolor disable colour for output EOF } print_runhelp_msg() { echo "Run '$(basename $0) help' to see available options." exit 2 } # check for 'pkgadd', required for package database path command -v pkgadd >/dev/null 2>&1 || { echo "'pkgadd' not found in \$PATH!" exit 1 } mode=$1 [ "$mode" ] || { print_runhelp_msg } shift for opt in $@; do case $opt in --nocolor) nocolor;; --append-repo=*) APPENDREPO="$APPENDREPO ${opt#*=}";; --prepend-repo=*) PREPENDREPO="$PREPENDREPO ${opt#*=}";; --override-repo=*) OVERRIDEREPO="$OVERRIDEREPO ${opt#*=}";; --repo=*) PORT_REPO="$PORT_REPO ${opt#*=}";; --repo-file=*) REPO_FILE="${opt#*=}";; --alias-file=*) ALIAS_FILE="${opt#*=}";; --config-file=*) CONFIG_FILE="${opt#*=}";; --*) MAINOPTS="$MAINOPTS $opt";; -*) char=${#opt}; count=1 while [ "$count" != "$char" ]; do count=$((count+1)) MAINOPTS="$MAINOPTS -$(printf '%s' $opt | cut -c $count)" done;; *) MAINOPTS="$MAINOPTS $opt";; esac shift done BUILD_SCRIPT="spkgbuild" PKGDB_DIR="$(pkgadd --print-dbdir)" PKGDBPERMS_DIR="${PKGDB_DIR}.perms" REPO_FILE="${REPO_FILE:-/etc/scratchpkg.repo}" ALIAS_FILE="${ALIAS_FILE:-/etc/scratchpkg.alias}" MASK_FILE="${MASK_FILE:-/etc/scratchpkg.mask}" CONFIG_FILE="${CONFIG_FILE:-/etc/scratchpkg.conf}" # default value from pkgbuild SOURCE_DIR="/var/cache/scratchpkg/sources" PACKAGE_DIR="/var/cache/scratchpkg/packages" WORK_DIR="/var/cache/scratchpkg/work" CURL_OPTS="" COMPRESSION_MODE="xz" NO_STRIP="no" IGNORE_MDSUM="no" KEEP_LIBTOOL="no" KEEP_LOCALE="no" KEEP_DOC="no" if [ -f "$REPO_FILE" ]; then for repodir in $(grep -Ev '^(#|$)' "$REPO_FILE" | awk '{print $1}'); do PORT_REPO="$PORT_REPO $repodir" done fi if [ "$OVERRIDEREPO" ]; then PORT_REPO="$OVERRIDEREPO" else PORT_REPO="$PREPENDREPO $PORT_REPO $APPENDREPO" fi for f in $REPO_FILE $ALIAS_FILE $MASK_FILE $CONFIG_FILE; do if [ ! -f "$f" ]; then msgerr "file not found: $CONFIG_FILE" exit 3 fi done . "$CONFIG_FILE" if [ "$(command -v scratch_$mode)" ]; then scratch_$mode $MAINOPTS else print_runhelp_msg fi exit $?