Files
scratchpkg/scratch
2022-07-02 07:00:17 +08:00

1525 lines
35 KiB
Bash
Executable File

#!/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 <https://www.gnu.org/licenses/>.
#
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 -R $@ $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; 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 -w $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> [<arg>]
Options:
install <ports> <arg> 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 <ports> <arg> 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 <ports> <arg> remove installed ports (use pkgdel arg)
-y skip ask user confirmation
sysup <arg> 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 <ports> print all dependencies for ports
-q skip installed ports
--exclude=* exclude dependencies, comma separated
build <ports> <arg> 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 <pattern> find ports in repo
cat <port> print spkgbuild
depends <port> print dependencies
dependent <port> print dependent
path <port> print path in repo
provide <file> print port's provided file
readme <port> print readme file, if exist
files <port> print files installed
info <port> print information
locate <file> print location of file in ports repo
isinstalled <port> 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 <opts> print scratchpkg configs
help print this help msg
Global options:
--append-repo=<repo path> append custom local repo path (can use multiple times)
--prepend-repo=<repo path> prepend custom local repo path (can use multiple times)
--override-repo=<repo path> override repo in $REPO_FILE with custom local repo (can use multiple times)
--repo-file=<repo file> use custom repo file (default: $REPO_FILE)
--config-file=<config file> use custom config file (default: $CONFIG_FILE)
--alias-file=<alias file> use custom alias file (default: $ALIAS_FILE)
--mask-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 $?