Files
scratchpkg/scratch
2019-06-14 23:57:48 +08:00

1537 lines
35 KiB
Bash
Executable File

#!/bin/bash
#
# 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='\e[0;31m'
GREEN='\e[0;32m'
YELLOW='\e[0;33m'
CYAN='\e[0;36m'
PURPLE='\e[0;35m'
CRESET='\e[0m'
nocolor() {
RED=
GREEN=
YELLOW=
CYAN=
PURPLE=
CRESET=
}
msg() {
echo -e "${GREEN}==>${CRESET} $1"
}
msgerr() {
echo -e "${RED}==> ERROR:${CRESET} $1"
}
msginst() {
echo -e "[${GREEN}i${CRESET}] $1"
}
msgmiss() {
echo -e "[${YELLOW}m${CRESET}] $1"
}
msgnoinst() {
echo -e "[ ] $1"
}
msgwarn() {
echo -e "${YELLOW}==> WARNING:${CRESET} $1"
}
needroot() {
if [ $UID != 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
}
pushd() {
command pushd $1 &>/dev/null
}
popd() {
command popd &>/dev/null
}
vercomp() {
if [ "$1" = "$2" ]; then
return 0 # same version
elif [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ]; then
return 1 # $1 lower than $2
else
return 2 # $1 higher than $2
fi
}
installed_pkg_info() {
if isinstalled $2; then
grep ^$1 $INDEX_DIR/$2/.pkginfo | cut -d " " -f3-
fi
}
allinstalled() {
for i in $INDEX_DIR/*; do
if isinstalled ${i##*/}; then
echo ${i##*/}
fi
done
}
confirm() {
read -r -p "$1 (Y/n) " response
case "$response" in
[Nn][Oo]|[Nn]) echo "$2"; exit 2 ;;
*) : ;;
esac
}
checktool() {
if ! type -p $1 &>/dev/null; then
msgerr "'$1' not exist in your system!"
exit 1
fi
}
needarg() {
if [ -z "$*" ]; then
msgerr "This operation required an arguments!"
exit 1
fi
}
scratch_cat() {
if PPATH=$(getportpath "$1"); then
cat "$PPATH/$BUILD_SCRIPT"
else
msgerr "Port '$1' not exist."
exit 1
fi
}
isinstalled() {
if [ -s $INDEX_DIR/$1/.pkginfo ] && [[ $(grep $1 $INDEX_DIR/$1/.pkginfo) ]]; then
return 0
else
return 1
fi
}
settermtitle() {
echo -en "\033]0;$*\a"
}
scratch_missingdep() {
local pkg d
for pkg in $(allinstalled); do
if [ $(getportpath "$pkg") ]; then
depends=$(grep "^# depends[[:blank:]]*:" $(getportpath "$pkg")/$BUILD_SCRIPT | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' | tr ' ' '\n' | awk '!a[$0]++')
fi
if [ "$depends" ]; then
for d in ${depends[@]}; do
if ! isinstalled $d; then
msd+=($d)
fi
done
fi
if [ ${#msd[@]} -gt 0 ]; then
echo -e "${GREEN}$pkg${CRESET} missing ${RED}${msd[@]}${CRESET}"
fi
unset depends msd
done
}
scratch_integrity() {
if [ "$1" ]; then
pushd /
if [ -f $INDEX_DIR/$1/.files ]; then
while read -r line; do
if [ ! -e "$line" ]; then
MISSING_FILE=yes
if [ -L "$line" ]; then
echo -e "${YELLOW}broken symlink${CRESET} $1: /$line"
else
echo -e "${RED}file missing${CRESET} $1: /$line"
fi
fi
done < <(cat $INDEX_DIR/$1/.files)
else
echo "Package '$1' not installed."
exit 1
fi
popd
else
pushd /
for pkg in $(allinstalled); do
while read -r line; do
if [ ! -e "$line" ]; then
MISSING_FILE=yes
if [ -L "$line" ]; then
echo -e "${YELLOW}broken symlink${CRESET} $pkg: /$line"
else
echo -e "${RED}file missing${CRESET} $pkg: /$line"
fi
fi
done < <(cat $INDEX_DIR/$pkg/.files)
done
popd
fi
[ "$UID" != "0" ] && msg "${YELLOW}(check integrity is recommended run as root or using sudo)${CRESET}"
if [ "$1" ]; then
p="Package '$1'"
else
p="Your system"
fi
[ ! "$MISSING_FILE" ] && msg "$p files is consistent with package tree."
}
scratch_listinst() {
local pkg
for pkg in $(allinstalled); do
echo $pkg
done
}
scratch_listorphan() {
local pkg dep
tmpallpkg=$(mktemp)
tmpalldep=$(mktemp)
for pkg in $(allinstalled); do
echo $pkg >> $tmpallpkg
dep="$dep $(grep "^# depends[[:blank:]]*:" $(getportpath $pkg)/$BUILD_SCRIPT 2>/dev/null | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' | tr ' ' '\n' | awk '!a[$0]++')"
done
echo $dep | tr ' ' '\n' | sort | uniq > $tmpalldep
grep -xvF -f $tmpalldep $tmpallpkg
rm $tmpalldep $tmpallpkg
}
scratch_lock() {
local pkg
needroot "Locking package"
for pkg in "$@"; do
if ! isinstalled $pkg; then
msgerr "Package '$pkg' is not installed."
elif [ -f $INDEX_DIR/$pkg/.lock ]; then
msgerr "Package '$pkg' already locked."
else
touch $INDEX_DIR/$pkg/.lock && msg "Successfully locked package '$pkg'."
fi
done
}
scratch_unlock() {
local pkg
needroot "Unlocking package"
for pkg in "$@"; do
if ! isinstalled $pkg; then
msgerr "Package '$pkg' is not installed."
elif [ ! -f $INDEX_DIR/$pkg/.lock ]; then
msgerr "Package '$pkg' is not locked."
else
rm -f $INDEX_DIR/$pkg/.lock && msg "Successfully unlocked package '$pkg'."
fi
done
}
scratch_listlocked() {
local pkg
for pkg in $(allinstalled); do
if [ -f "$INDEX_DIR"/$pkg/.lock ]; then
echo -e "$pkg"
fi
done
}
scratch_depends() {
local dep
if [ $(getportpath "$1") ]; then
depends=$(grep "^# depends[[:blank:]]*:" $(getportpath "$1")/$BUILD_SCRIPT | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' | tr ' ' '\n' | awk '!a[$0]++')
else
msgerr "Port '$1' not exist."
exit 1
fi
#isinstalled ${depends[0]}
for dep in ${depends[@]}; do
if isinstalled $dep; then
msginst "$dep"
elif getportpath $dep >/dev/null; then
msgnoinst "$dep"
else
msgmiss "$dep"
fi
done
}
scratch_isorphan() {
needarg $1
for pkg in $(allinstalled); do
pkgpath=$(getportpath $pkg)
#echo $pkgpath
if [ $pkgpath ]; then
depend=$(grep "^# depends[[:blank:]]*:" $pkgpath/$BUILD_SCRIPT | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' | tr ' ' '\n' | awk '!a[$0]++')
for dep in ${depend[@]}; do
if [ $dep = $1 ]; then
return 1
fi
done
fi
unset depend dep
done
return 0
}
scratch_dependent() {
local port all dep pname
needarg $1
for port in ${PORT_REPO[@]}; do
if [ -d $port ]; then
for all in $port/*/$BUILD_SCRIPT; do
[ -f $all ] || continue
depend=$(grep "^# depends[[:blank:]]*:" $all | sed 's/^# depends[[:blank:]]*:[[:blank:]]*//' | tr ' ' '\n' | awk '!a[$0]++')
for dep in ${depend[@]}; do
if [ $dep = $1 ]; then
GDP=yes
pname=$(dirname $all)
pname=${pname##*/}
if isinstalled $pname; then
msginst "$pname"
else
msgnoinst "$pname"
fi
fi
done
done
fi
done
[ "$GDP" ] && return 0 || return 1
}
scratch_own() {
local arg
arg=${1/\/}
grep -R $arg $INDEX_DIR/*/.files | sed "s:$INDEX_DIR/::" | sed "s:/.files::" | tr : " " | column -t
}
scratch_files() {
if ! isinstalled $1; then
msg "Package'$1' not installed."
else
while read -r line; do
echo "$line"
done < <(cat $INDEX_DIR/$1/.files)
fi
}
scratch_sync() {
checktool httpup
needroot "Updating ports"
if [ ! -e "$REPO_FILE" ]; then
msgerr "Repo file not found! ($REPO_FILE)"
exit 1
fi
while read repodir repourl junk; do
case $repodir in
""|"#"*) continue ;;
esac
if [ -n "$repodir" ] && [ -n "$repourl" ]; then
httpup sync $repourl $repodir
if [ $? != 0 ]; then
msgerr "Failed sync from $repourl"
exit 1
fi
fi
done < "$REPO_FILE"
}
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_search() {
needarg $@
case $1 in
-*) msgerr "Invalid pattern '$1'"
return 1 ;;
esac
local port found OUTPUT
for port in ${PORT_REPO[@]}; do
if [ -d $port ]; then
pushd $port
OUTPUT=$(grep -R description | grep "$BUILD_SCRIPT:# description[[:blank:]]*:" | sed "s/$BUILD_SCRIPT:# description[[:blank:]]*://" | grep -i "$1" | cut -d '/' -f1 | sort)
popd
if [ -n "$OUTPUT" ]; then
found=yes
for out in ${OUTPUT[@]}; do
if [ -f $port/$out/$BUILD_SCRIPT ]; then
pushd $port/$out
description=$(grep "^# description[[:blank:]]*:" $BUILD_SCRIPT | sed 's/^# description[[:blank:]]*:[[:blank:]]*//')
. $BUILD_SCRIPT
popd
if [ -n "$name" ] && [ -n "$version" ] && [ -n "$release" ]; then
portname=$(basename $port)
search_result="${PURPLE}($portname)${CRESET} $name ${CYAN}$version-$release${CRESET} $description"
if isinstalled $name; then
echo -e "[${GREEN}*${CRESET}] $search_result"
else
echo -e "[ ] $search_result"
fi
unset description name version release
fi
fi
done
fi
fi
done
if [ ! "$found" ]; then
msg "No matching package found."
fi
}
scratch_foreignpkg() {
for pkg in $(allinstalled); do
if ! getportpath $pkg >/dev/null; then
iname=$(installed_pkg_info name $pkg)
iversion=$(installed_pkg_info version $pkg)
irelease=$(installed_pkg_info release $pkg)
echo -e "$iname ${GREEN}$iversion${CRESET}-${CYAN}$irelease${CRESET}"
fi
unset iname iversion irelease
done
}
scratch_info() {
[ $1 ] || return 0
version="-"
release="-"
iver="-"
irel="-"
if isinstalled $1; then
iver=$(installed_pkg_info version $1)
irel=$(installed_pkg_info release $1)
INSTALLED=1
fi
portpath=$(getportpath $1)
if [ -n "$portpath" ]; then
. $portpath/$BUILD_SCRIPT
PORTEXIST=1
else
portpath="-"
fi
if [ "$INSTALLED" != 1 ] && [ "$PORTEXIST" != 1 ]; then
return 0
fi
echo -e "name: \t\t$1 \t$([[ $PORTEXIST = 1 ]] || echo \( foreignpkg \))"
echo -e "version: \t$version \t( installed: $iver )"
echo -e "release: \t$release \t( installed: $irel )"
echo -e "port path: \t$portpath"
}
scratch_trigger() {
needroot "Run trigger"
if [ -z "$@" ]; then
for i in trig_{1..12}; do
eval $i=1
done
else
pre_triggers $@
fi
post_triggers
}
post_triggers() {
if [ "$trig_12" = 1 ]; then
echo "trigger: Running mkdirs..."
for mkd in $INDEX_DIR/*/.pkgmkdirs; do
[ -s $mkd ] || continue
while read dir mode uid gid junk; do
# Ignore comments and blank lines
case "$dir" in
""|\#*) continue ;;
esac
if [ -e "$dir" ]; then
if [ "$uid" != '-' ]; then
getent passwd $uid >/dev/null
if [[ "$?" = 0 ]]; then
chown "$uid" "$dir"
fi
fi
if [ "$gid" != '-' ]; then
getent group $gid >/dev/null
if [[ "$?" = 0 ]]; then
chgrp "$gid" "$dir"
fi
fi
if [ "$mode" != '-' ]; then
chmod "$mode" "$dir"
fi
fi
done < "$mkd"
done
fi
if [ "$trig_11" = 1 ] && [ $(type -p fc-cache) ]; then
echo "trigger: Updating fontconfig cache..."
fc-cache -s
fi
if [ "$trig_10" = 1 ] && [ $(type -p gdk-pixbuf-query-loaders) ]; then
echo "trigger: Probing GDK-Pixbuf loader modules..."
gdk-pixbuf-query-loaders --update-cache
fi
if [ "$trig_9" = 1 ] && [ $(type -p gio-querymodules) ]; then
echo "trigger: Updating GIO module cache..."
gio-querymodules /usr/lib/gio/modules
fi
if [ "$trig_8" = 1 ] && [ $(type -p 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 ] && [ $(type -p 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 ] && [ $(type -p 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 ] && [ $(type -p 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 &>/dev/null
else
rm -f $dir/icon-theme.cache
rmdir --ignore-fail-on-non-empty $dir
fi
done
fi
if [ "$trig_4" = 1 ] && [ $(type -p udevadm) ]; then
echo "trigger: Updating hardware database..."
udevadm hwdb --update
fi
if [ "$trig_3" = 1 ] && [ $(type -p mkfontdir) ] && [ $(type -p mkfontscale) ]; then
echo "trigger: Updating X fontdir indices..."
for dir in $(find /usr/share/fonts -maxdepth 1 -type d \( ! -path /usr/share/fonts -a ! -name X11 \)) /usr/share/fonts/X11/*; do
rm -f $dir/fonts.{scale,dir} $dir/.uuid
rmdir --ignore-fail-on-non-empty $dir
[[ -d $dir ]] || continue
mkfontdir $dir
mkfontscale $dir
done
fi
if [ "$trig_2" = 1 ] && [ $(type -p update-desktop-database) ]; then
echo "trigger: Updating desktop file MIME type cache..."
update-desktop-database --quiet
fi
if [ "$trig_1" = 1 ] && [ $(type -p update-mime-database) ]; then
echo "trigger: Updating the MIME type database..."
update-mime-database /usr/share/mime
fi
}
pre_triggers() {
local pkg
# mime db
if [ "$trig_1" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/mime/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_1=1
break
fi
done
fi
# desktop db
if [ "$trig_2" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/applications/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_2=1
break
fi
done
fi
# mkfontdir
if [ "$trig_3" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/fonts/[^/]*/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_3=1
break
fi
done
fi
# hwdb
if [ "$trig_4" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^etc/udev/hwdb.d/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_4=1
break
fi
done
fi
# icon caches
if [ "$trig_5" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/icons/[^/]*/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_5=1
break
fi
done
fi
# gtk3 immodules
if [ "$trig_6" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/lib/gtk-3.0/3.0.0/immodules/.*.so $INDEX_DIR/$pkg/.files)" ]; then
trig_6=1
break
fi
done
fi
# gtk2 immodules
if [ "$trig_7" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/lib/gtk-2.0/2.10.0/immodules/.*.so $INDEX_DIR/$pkg/.files)" ]; then
trig_7=1
break
fi
done
fi
# gsettings schema
if [ "$trig_8" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/glib-2.0/schemas/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_8=1
break
fi
done
fi
# gio modules
if [ "$trig_9" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/lib/gio/modules/.*.so $INDEX_DIR/$pkg/.files)" ]; then
trig_9=1
break
fi
done
fi
# gdk-pixbuf
if [ "$trig_10" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/lib/gdk-pixbuf-2.0/2.10.0/loaders/.*.so $INDEX_DIR/$pkg/.files)" ]; then
trig_10=1
break
fi
done
fi
# font caches
if [ "$trig_11" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.files" ] && [ "$(grep ^usr/share/fonts/[^/]*/$ $INDEX_DIR/$pkg/.files)" ]; then
trig_11=1
break
fi
done
fi
# makedirs
if [ "$trig_12" != "1" ]; then
for pkg in $@; do
if [ -s "$INDEX_DIR/$pkg/.pkgmkdirs" ]; then
trig_12=1
break
fi
done
fi
}
scratch_build() {
local OPTS
if [ -z "$1" ]; then
echo "Please specify package to build."
return 1
fi
while [ "$1" ]; do
if [[ "$1" =~ ^-(f|w|m|o|x|l)$ ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^--(no-prebuild|force-rebuild|skip-mdsum|download|extract|keep-work|log)$ ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^--(pkgdir|srcdir|logdir)= ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^-. ]]; then
echo "Unrecognize option. ($1)"
return 1
else
PKGNAME=$1
fi
shift
done
pushd $(getportpath $PKGNAME)
if [ $? = 0 ]; then
settermtitle "Building $PKGNAME..."
pkgbuild ${OPTS[@]} || return 1
settermtitle "Building $PKGNAME done"
else
echo "Package '$PKGNAME' not found."
return 1
fi
return 0
}
scratch_install() {
local pkg i int pkgcount count IPKG OPTS REINSTALL done_pkg
needroot "Installing package"
if [ -z "$1" ]; then
echo "Please specify package(s) to install."
return 1
fi
while [ "$1" ]; do
if [[ "$1" =~ ^-(c|v|-verbose|-ignore-conflict)$ ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^--(no-preinstall|no-postinstall) ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^-(r|-reinstall)$ ]]; then
OPTS+=($1)
REINSTALL=1
elif [[ "$1" =~ ^-(d|-no-dep)$ ]]; then
NO_DEP=1
elif [[ "$1" = "--yes" ]] || [[ "$1" = "-y" ]]; then
NOCONFIRM=1
elif [[ "$1" =~ ^-. ]]; then
echo "Unrecognize option. ($1)"
return 1
else
PKGNAME+=($1)
fi
shift
done
# if reinstall, dont calculate dep, just reinstall it then exit
if [ "$REINSTALL" = 1 ]; then
for ii in ${PKGNAME[@]}; do
if [ ! $(getportpath $ii) ]; then
echo "Package '$ii' not found."
elif ! isinstalled $ii; then
echo "Package '$ii' not installed."
else
pushd $(getportpath $ii)
settermtitle "Reinstalling $ii..."
pkgbuild ${OPTS[@]}
if [ $? != 0 ]; then
error=1
break
fi
done_pkg+=($ii)
popd
fi
done
settermtitle "Triggering install hook"
if [ ${#done_pkg[@]} -gt 0 ]; then
scratch_trigger ${done_pkg[@]}
fi
settermtitle "Reinstalling done"
[ "$error" = 1 ] && return 1 || return 0
fi
if [ "$NO_DEP" = 1 ]; then
for ii in ${PKGNAME[@]}; do
if [ ! $(getportpath $ii) ]; then
echo "Package '$ii' not found."
elif isinstalled $ii; then
echo "Package '$ii' already installed."
return 0
else
pushd $(getportpath $ii)
settermtitle "Installing $ii..."
pkgbuild -i ${OPTS[@]}
if [ $? != 0 ]; then
error=1
break
fi
done_pkg+=($ii)
popd
fi
done
settermtitle "Triggering install hook"
if [ ${#done_pkg[@]} -gt 0 ]; then
scratch_trigger ${done_pkg[@]}
fi
settermtitle "Installing done"
[ "$error" = 1 ] && return 1 || return 0
fi
for i in ${PKGNAME[@]}; do
if [ ! $(getportpath $i) ]; then
echo "Package '$i' not found."
elif isinstalled $i; then
echo "Package '$i' already installed."
else
IPKG+=($i)
fi
done
if [ "${#IPKG[@]}" = 0 ]; then
return 0
fi
echo "Resolving dependencies..."
INST="$(pkgdeplist -l -q ${IPKG[@]} | awk '{print $2}')"
if [ "$INST" ]; then
echo
pkgcount=0
for pkg in $INST; do
pkgcount=$(( pkgcount + 1 ))
echo -en "[${GREEN}i${CRESET}] $pkg "
done
echo; echo
echo "( $pkgcount install )"
echo
if [ ! "$NOCONFIRM" ]; then
confirm "Continue install package(s)?" "Package installation cancelled."
echo
fi
error=0
count=0
total=$(echo $INST | wc -w)
for int in ${INST[@]}; do
count=$(( count + 1 ))
portpathh=$(getportpath $int)
if [ "$portpathh" ]; then
pushd $portpathh
settermtitle "[ $count/$total ] installing $int..."
pkgbuild -i ${OPTS[@]}
if [ $? != 0 ]; then
error=1
count=$(( count - 1 ))
break
fi
done_pkg+=($int)
popd
else
msgwarn "Skipping missing package: $int"
fi
unset portpathh
done
settermtitle "Triggering install hook"
if [ ${#done_pkg[@]} -gt 0 ]; then
scratch_trigger ${done_pkg[@]}
fi
settermtitle "$count/$total package(s) installed"
return "$error"
fi
}
outdatepkg() {
local pkg
for pkg in $(allinstalled); do
if [ ! -e "$INDEX_DIR/$pkg/.lock" ] && getportpath $pkg >/dev/null; then
. $(getportpath $pkg)/$BUILD_SCRIPT
iversion=$(installed_pkg_info version $pkg)
irelease=$(installed_pkg_info release $pkg)
if [ "$release" != "$irelease" ] || [ "$version" != "$iversion" ]; then
echo $name
fi
unset iversion irelease
fi
done
}
scratch_remove() {
local pkg i IPKG OPTS
needroot "Removing package"
if [ -z "$1" ]; then
echo "Please specify package(s) to remove."
return 1
fi
while [ "$1" ]; do
if [[ "$1" =~ ^--(no-postremove|no-preremove)$ ]]; then
OPTS+=($1)
elif [[ "$1" = "--yes" ]] || [[ "$1" = "-y" ]]; then
NOCONFIRM=1
elif [[ "$1" =~ ^-. ]]; then
echo "Unrecognize option. ($1)"
return 1
else
PKGNAME+=($1)
fi
shift
done
for i in ${PKGNAME[@]}; do
if ! isinstalled $i; then
echo "Package '$i' not installed."
else
IPKG+=($i)
fi
done
if [ "${#IPKG[@]}" = 0 ]; then
return 0
fi
if [ "$IPKG" ]; then
echo "Removing packages..."
echo
pkgcount=0
count=0
for pkg in ${IPKG[@]}; do
pkgcount=$(( pkgcount + 1 ))
echo -en "[${RED}x${CRESET}] $pkg "
done
echo; echo
echo "( $pkgcount remove )"
echo
if [ ! "$NOCONFIRM" ]; then
confirm "Continue remove package(s)?" "Package removing cancelled."
echo
fi
for pkg in ${IPKG[@]}; do
count=$(( count + 1 ))
pre_triggers $pkg
settermtitle "[ $count/$pkgcount ] Removing $pkg..."
pkgdel $pkg ${OPTS[@]} || return 1
done
settermtitle "Triggering remove hook"
post_triggers
settermtitle "$pkgcount package(s) removed"
fi
}
scratch_sysup() {
local d UPGPKG NEWPKG PKGOUTDATE OPTS done_pkg
needroot "Upgrading package"
while [ "$1" ]; do
if [[ "$1" =~ ^--(no-postupgrade|no-preupgrade|no-backup)$ ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^-(c|v|-verbose|-ignore-conflict)$ ]]; then
OPTS+=($1)
elif [ "$1" = "--yes" ] || [ "$1" = "-y" ]; then
NOCONFIRM=1
elif [ "$1" = "--np-dep" ] || [ "$1" = "-d" ]; then
NODEP=1
elif [ "$1" = "--sync" ] || [ "$1" = "-s" ]; then
SYNC=1
elif [[ "$1" =~ ^-. ]]; then
echo "Unrecognize option. ($1)"
exit 1
fi
shift
done
if [ "$SYNC" = 1 ]; then
scratch_sync
fi
echo "Checking for outdated packages..."
PKGOUTDATE=$(outdatepkg)
if [ ! "$PKGOUTDATE" ]; then
echo "All package is up to date."
return 0
fi
UPGPKG=0
NEWPKG=0
if [ "$NODEP" != 1 ]; then
echo "Resolving dependencies..."
DEP=$(pkgdeplist ${PKGOUTDATE[@]} -l | awk '{print $2}')
echo
for d in $DEP; do
if [ "$(echo $PKGOUTDATE | tr ' ' '\n' | grep -x $d)" = "$d" ]; then
echo -ne "[${GREEN}u${CRESET}] $d "
WILLINSTALL+=($d)
UPGPKG=$(( UPGPKG + 1 ))
elif ! isinstalled $d && [ $(getportpath "$d") ]; then
echo -ne "[${CYAN}n${CRESET}] $d "
WILLINSTALL+=($d)
NEWPKG=$(( NEWPKG + 1 ))
fi
done
else
echo
for dd in ${PKGOUTDATE[@]}; do
echo -ne "[${GREEN}u${CRESET}] $dd "
WILLINSTALL+=($dd)
UPGPKG=$(( UPGPKG + 1 ))
done
fi
echo
echo
echo "( $UPGPKG upgrade, $NEWPKG new install )"
echo
if [ ! "$NOCONFIRM" ]; then
confirm "Continue upgrade/install these package(s)?" "Package upgrade cancelled."
echo
fi
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 ))
pushd $(getportpath $inst)
if ! isinstalled $inst; then
settermtitle "[ $count/$total ] Installing $inst..."
pkgbuild -i ${OPTS[@]}
if [ $? != 0 ]; then
error=1
count=$(( count - 1 ))
break
fi
else
settermtitle "[ $count/$total ] Upgrading $inst..."
pkgbuild -u ${OPTS[@]}
if [ $? != 0 ]; then
error=1
count=$(( count - 1 ))
break
fi
fi
done_pkg+=($inst)
done
settermtitle "Triggering install hook"
if [ ${#done_pkg[@]} -gt 0 ]; then
scratch_trigger ${done_pkg[@]}
fi
settermtitle "$count/$total package(s) upgraded"
return $error
}
scratch_upgrade() {
local pkg done_pkg
needroot "Upgrading package"
needarg "$@"
while [ "$1" ]; do
if [[ "$1" =~ ^--(no-postupgrade|no-preupgrade|no-backup)$ ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^-(c|v|-ignore-conflict|-verbose) ]]; then
OPTS+=($1)
elif [[ "$1" =~ ^-(-no-dep|d)$ ]]; then
NO_DEP=1
elif [[ "$1" = "--yes" ]] || [[ "$1" = "-y" ]]; then
NOCONFIRM=1
elif [[ "$1" =~ ^-. ]]; then
echo "Unrecognize option. ($1)"
exit 1
else
PKGNAME+=($1)
fi
shift
done
for pkg in ${PKGNAME[@]}; do
if ! isinstalled $pkg; then
msgerr "Package '$pkg' not installed."
return 1
fi
if [ ! $(getportpath $pkg) ]; then
msgerr "Package '$pkg' not exist."
return 1
fi
. $(getportpath $pkg)/$BUILD_SCRIPT
if [ "$(installed_pkg_info version $pkg)-$(installed_pkg_info release $pkg)" = "$version-$release" ]; then
msg "Package '$pkg' is up-to-date."
return 0
fi
done
if [ -z "$NO_DEP" ]; then
echo "Resolving dependencies..."
DEP=$(pkgdeplist -l -n ${PKGNAME[@]} | awk '{print $2}')
for dep in $DEP; do
if ! isinstalled $dep; then
if [ $(getportpath $dep) ]; then
NEWPKG+=($dep)
fi
fi
done
fi
echo
count=0
for i in ${NEWPKG[@]}; do
count=$(( count + 1 ))
echo -en "[${CYAN}n${CRESET}] $i "
done
for i in ${PKGNAME[@]}; do
count=$(( count + 1 ))
echo -en "[${GREEN}u${CRESET}] $i "
done
echo
echo
echo "( ${#PKGNAME[@]} upgrade, ${#NEWPKG[@]} new install )"
echo
total=$count
count=0
if [ ! "$NOCONFIRM" ]; then
confirm "Continue upgrade/install these package(s)?" "Package upgrade cancelled."
echo
fi
if [ ${#NEWPKG[@]} -gt 0 ]; then
for newpkg in ${NEWPKG[@]}; do
count=$(( count + 1 ))
pushd $(getportpath $newpkg)
settermtitle "[ $count/$total ] Installing $newpkg..."
pkgbuild -i ${OPTS[@]}
if [ $? != 0 ]; then
error=1
count=$(( count - 1 ))
break
fi
done_pkg+=($newpkg)
popd
done
fi
for pkg in ${PKGNAME[@]}; do # upgrade all target packages
count=$(( count + 1 ))
pushd $(getportpath $pkg)
settermtitle "[ $count/$total ] Upgrading $pkg..."
pkgbuild -u ${OPTS[@]}
if [ $? != 0 ]; then
error=1
count=$(( count - 1 ))
break
fi
done_pkg+=($pkg)
popd
done
settermtitle "triggering upgrade hook"
if [ ${#done_pkg[@]} -gt 0 ]; then
scratch_trigger ${done_pkg[@]}
fi
settermtitle "$count/$total package(s) upgraded"
return $error
}
scratch_outdate() {
local pkg
for pkg in $(allinstalled); do
if [ $(getportpath $pkg) ]; then
. $(getportpath $pkg)/$BUILD_SCRIPT
iversion=$(installed_pkg_info version $pkg)
irelease=$(installed_pkg_info release $pkg)
[ -f "$INDEX_DIR/$pkg/.lock" ] && ITSLOCK="[locked]"
outdatemsg="$name ${RED}$iversion-$irelease${CRESET} => ${GREEN}$version-$release${CRESET} ${CYAN}$ITSLOCK${CRESET}"
newerinstmsg="$name ${RED}$iversion-$irelease${CRESET} => ${GREEN}$version-$release${CRESET} ${YELLOW}[newer installed]${CRESET} ${CYAN}$ITSLOCK${CRESET}"
if [ "$version" != "$iversion" ]; then
vercomp $version $iversion
if [ $? = 2 ]; then
echo -e "$outdatemsg"
OUTDATE=yes
elif [ $? = 1 ]; then
echo -e "$newerinstmsg"
OUTDATE=yes
fi
elif [ "$release" != "$irelease" ]; then
vercomp $release $irelease
if [ $? = 2 ]; then
echo -e "$outdatemsg"
OUTDATE=yes
elif [ $? = 1 ]; then
echo -e "$newerinstmsg"
OUTDATE=yes
fi
fi
unset ITSLOCK
fi
done
[ ! "$OUTDATE" ] && msg "All package is up to date."
}
clearpkgcache() {
if [ ${#ALL_PACKAGES[@]} -gt 0 ]; then
for pkg in ${ALL_PACKAGES[@]}; do
rm -v $PACKAGE_DIR/$pkg
done
fi
if [ ${#ALL_SOURCES[@]} -gt 0 ]; then
for src in ${ALL_SOURCES[@]}; do
rm -v $SOURCE_DIR/$src
done
fi
}
getpkgcache() {
COMPRESSION_MODE="xz"
[ -f /etc/scratchpkg.conf ] && . /etc/scratchpkg.conf
for list in "$PACKAGE_DIR"/*; do
[ -f "$list" ] && ALL_PACKAGES+=($(basename $list))
done
for list in "$SOURCE_DIR"/*; do
[ -f "$list" ] && ALL_SOURCES+=($(basename $list))
done
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
PORT_PACKAGES+=($name-$version-$release.spkg.tar.$COMPRESSION_MODE)
if [ -n "$source" ]; then
for src in ${source[@]}; do
if [ $(echo $src | grep -E "(ftp|http|https)://") ]; then
if [ $(echo $src | grep -E "::(ftp|http|https)://") ]; then
sourcename="$(echo $src | awk -F '::' '{print $1}')"
else
sourcename="$(echo $src | rev | cut -d / -f 1 | rev)"
fi
SOURCE_NAMES+=($sourcename)
fi
done
fi
done
fi
done
for i in ${PORT_PACKAGES[@]}; do
for pkg in ${!ALL_PACKAGES[@]}; do
if [ "${ALL_PACKAGES[pkg]}" = "$i" ]; then
unset 'ALL_PACKAGES[pkg]'
break
fi
done
done
for a in ${SOURCE_NAMES[@]}; do
for src in ${!ALL_SOURCES[@]}; do
if [ "${ALL_SOURCES[src]}" = "$a" ]; then
unset 'ALL_SOURCES[src]'
break
fi
done
done
}
scratch_cache() {
getpkgcache
if [ ${#ALL_PACKAGES[@]} -gt 0 ]; then
ALL_PACKAGES_SIZE=$(pushd "$PACKAGE_DIR" && du -ch ${ALL_PACKAGES[@]} | grep total | awk '{print $1}' && popd)
else
ALL_PACKAGES_SIZE=0M
fi
if [ ${#ALL_SOURCES[@]} -gt 0 ]; then
ALL_SOURCES_SIZE=$(pushd "$SOURCE_DIR" && du -ch ${ALL_SOURCES[@]} | grep total | awk '{print $1}' && popd)
else
ALL_SOURCES_SIZE=0M
fi
[ ${#ALL_PACKAGES[@]} -gt 0 ] && (echo ${ALL_PACKAGES[@]} | tr ' ' '\n')
[ ${#ALL_SOURCES[@]} -gt 0 ] && (echo ${ALL_SOURCES[@]} | tr ' ' '\n')
echo
echo -e "Package caches ($ALL_PACKAGES_SIZE)"
echo -e "Source caches ($ALL_SOURCES_SIZE)"
echo
if [ ${#ALL_PACKAGES[@]} -gt 0 ] || [ ${#ALL_SOURCES[@]} -gt 0 ]; then
confirm "Clear old caches?" "Old caches is keep."
needroot "Clear old caches"
clearpkgcache
fi
}
scratch_path() {
needarg $@
if PPATH=$(getportpath "$1"); then
echo "$PPATH"
else
msgerr "Port '$1' not exist."
exit 1
fi
}
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
}
usage_extra() {
cat << EOF
Usage:
$(basename $0) <operation> [ <port/pattern/file> ]
Operation:
depends <port> show depends of a package
search <pattern> search packages in port's repos
lock <port> lock packages from upgrade
unlock <port> unlock packages from upgrade
cat <port> view a package build scripts
dependent <port> show package's dependent
own <file> show package's owner of file
files <port> show list files of installed package
path <port> show package's buildscripts path
readme <port> print readme file if exist
info <port> print ports info
sync update port's repo
dup print duplicate ports in repo
listinst list installed package in system
listorphan list orphan package
integrity check integrity of package's files
outdate check for outdated packages
cache print leftover cache
missingdep check for mising dependency of installed package
foreignpkg print package installed without port in repo
listlocked print locked packages
EOF
}
usage_build() {
cat << EOF
Usage:
$(basename $0) build [ <pkgname> <options> ]
Options:
-f, --force-rebuild force rebuild
-m, --skip-mdsum skip md5sum check for sources
-x, --extract extract only
-w, --keep-work keep woring directory
-o, --download download source files only
-l, --log log build process
--redownload re-download source files
--srcdir=<path> override default SOURCE_DIR
--pkgdir=<path> override default PACKAGE_DIR
--logdir=<path> override default LOG_DIR
--no-prebuild skip pre-build script
EOF
}
usage_upgrade() {
cat << EOF
Usage:
$(basename $0) upgrade [ <pkgname> <options> ]
Options:
-d, --no-dep skip installing dependencies (new dependencies)
-c, --ignore-conflict skip file conflict check
-v, --verbose print install process
-y, --yes dont ask confirmation
--no-backup skip backup configuration file
--no-preupgrade skip pre-upgrade script
--no-postupgrade skip post-upgrade script
EOF
}
usage_sysup() {
cat << EOF
Usage:
$(basename $0) sysup <options>
Options:
-d, --no-dep skip installing dependencies (new dependencies)
-c, --ignore-conflict skip file conflict check
-v, --verbose print install process
-s, --sync sync ports before upgrades
-y, --yes dont ask confirmation
--no-backup skip backup configuration file
--no-preupgrade skip pre-upgrade script
--no-postupgrade skip post-upgrade script
EOF
}
usage_remove() {
cat << EOF
Usage:
$(basename $0) remove [ <pkgname> <options> ]
Options:
-v, --verbose print removed files
-y, --yes dont ask confirmation
--no-preremove skip pre-remove script
--no-postremove skip post-remove script
EOF
}
usage_install() {
cat << EOF
Usage:
$(basename $0) install [ <pkgname> <options> ]
Options:
-d, --no-dep skip installing dependencies
-c, --ignore-conflict skip file conflict check
-r, --reinstall reinstall installed package
-v, --verbose print install files
-y, --yes dont ask confirmation
--no-preinstall skip pre-install script
--no-postinstall skip post-install script
EOF
}
usage_help() {
cat << EOF
Usage:
$(basename $0) help <operation>
Operation:
build build package
install install packages
upgrade upgrade packages
sysup full system upgrades
remove remove packages
extra various extra options
EOF
}
scratch_help() {
if [ -z "$1" ]; then
usage_help
return 0
else
if [ "$(type -t usage_$1)" ]; then
usage_$1
else
usage_help
fi
fi
return 0
}
main() {
if [ "$(type -t scratch_$mode)" = "function" ]; then
scratch_$mode $@
else
echo "Run 'scratch help' to see available operations and options"
return 5
fi
return $?
}
BUILD_SCRIPT="spkgbuild"
INDEX_DIR="/var/lib/scratchpkg/index"
REPO_FILE="/etc/scratchpkg.repo"
SOURCE_DIR="/var/cache/scratchpkg/sources"
PACKAGE_DIR="/var/cache/scratchpkg/packages"
if [ ! -f "$REPO_FILE" ]; then
msgerr "repo file not exist. ($REPO_FILE)"
exit 1
else
while read -r repodir repourl junk; do
case $repodir in
""|"#"*) continue ;;
esac
PORT_REPO+=($repodir)
done < "$REPO_FILE"
fi
mode=$1
shift
for opt in $@; do
case $opt in
--nocolor) nocolor ;;
--*) MAINOPTS+=($opt) ;;
-*) for (( i=1; i<${#opt}; i++ )); do MAINOPTS+=(-${opt:$i:1}); done ;;
*) MAINOPTS+=($opt) ;;
esac
done
main ${MAINOPTS[@]}
exit $?