#!/bin/sh
# TazPkg - Tiny autonomous zone packages manager, hg.slitaz.org/tazpkg
# install - TazPkg module
# Install packages

. /lib/libtaz.sh
. /usr/lib/slitaz/libpkg.sh
. /usr/libexec/tazpkg/getenv
SAVE_CACHE_DIR="$CACHE_DIR"
. /usr/libexec/tazpkg/find-depends
log_pkg() {
debug "\nlog_pkg('$1')\n  PACKAGE='$PACKAGE'\n  VERSION='$VERSION'\n  EXTRAVERSION='$EXTRAVERSION'"
local extra
[ "$1" == 'Installed' ] && \
extra=" - $(fgrep " $PACKAGE-$VERSION" "$PKGS_DB/installed.$SUM" | awk '{print $1}')"
debug "  extra='$extra'"
[ -w "$LOG" ] &&
echo "$(date +'%F %T') - $1 - $PACKAGE ($VERSION$EXTRAVERSION)$extra">> $LOG
}
equivalent_pkg() {
local i rep rules rule out
rules=$(for rep in $PRIORITY; do
grep -hs "^$1=" "$rep/packages.equiv"
done | sed "s|^$1=||")
debug ">rules='$rules'"
for rule in $rules; do
debug ">rule='$rule'"
case $rule in
*:*)
debug '-- x:x'
out="${rule#*:}"
awk -F$'\t' -vp="${rule%:*}" '$1==p{exit 1}' "$PKGS_DB/installed.info" || break
debug '-- x:x /'
;;
*)
debug '-- x'
out="$rule"
awk -F$'\t' -vp="$rule" '$1==p{exit 1}' "$PKGS_DB/installed.info" || break
debug '-- x /'
;;
esac
unset out
done
debug '--'
echo "${out:-$1}"
}
install_all_deps() {
debug "\ninstall_all_deps('$1')"
local TMP_DIR DEPENDS num missing_packages equiv pkg answer dir found pkgfile
DEPENDS=$(
TMP_DIR=$(mktemp -d); cd "$TMP_DIR"
cpio --quiet -i receipt >/dev/null 2>&1
. ./receipt; echo $DEPENDS
rm -rf "$TMP_DIR"
) < "$1"
unset num missing_packages
for depend in $DEPENDS; do
debug "  depend='$depend'"
equiv=$(equivalent_pkg $depend)
debug "  equiv='$equiv'\n"
if [ ! -d "$INSTALLED/$equiv" ]; then
missing_packages="$missing_packages $equiv"
num=$((num+1))
elif [ ! -f "$INSTALLED/$equiv/receipt" ]; then
[ -z "$quiet" ] && _ 'WARNING! Dependency loop between "%s" and "%s".' "$PACKAGE" "$equiv"
fi
done
[ -z "$num" ] && return
title "$(_ 'Tracking dependencies for package "%s"' "$PACKAGE")"
[ -z "$quiet" ] && \
for pkg in $missing_packages; do
_ 'Missing package "%s"' "$pkg"
done
footer "$(_p \
'%s missing package to install.' \
'%s missing packages to install.' "$num" \
"$num")"
if [ "$AUTO_INSTALL_DEPS" == 'yes' ] || [ -n "$quiet" ]; then
answer=0
[ -n "$noconfirm" ] && answer=1
else
newline
confirm "$(_ 'Install all missing dependencies? (y/N)')"
answer=$?
newline
fi
debug "  answer='$answer'"
dir="$(dirname "$1")"
debug "  dir='$dir'"
[ "$dir" == '/home/boot/packages' ] && local='yes'
debug "  local='$local'"
if [ "$answer" -eq 0 -a -z "$nodeps" ]; then
debug "  let's install missing packages"
for pkg in $missing_packages; do
debug "  pkg='$pkg'"
if [ ! -d "$INSTALLED/$pkg" ]; then
found='0'
if [ -n "$local" ]; then
[ -z "$quiet" ] && _ 'Checking if package "%s" exists in local list...' "$pkg"
tempd="$(mktemp -d)"; cd "$tempd"
for pkgfile in $dir/$pkg-*.tazpkg; do
[ -e "$pkgfile" ] || continue
cpio -F "$pkgfile" -i receipt >/dev/null 2>&1
name=$(. ./receipt; echo $PACKAGE)
rm receipt
if [ "$name" == "$pkg" ]; then
found='1'
tazpkg install "$pkgfile"
fi
done
rm -r "$tempd"
fi
debug "    found='$found'"
[ "$found" -eq 0 ] && tazpkg get-install "$pkg"
fi
done
else
newline
_ 'Leaving dependencies for package "%s" unresolved.' "$PACKAGE"
_ 'The package will be installed but will probably not work.'
newline
fi
}
extract_package() {
action 'Extracting package...'
cpio -idm --quiet < "$1" && rm -f "$1"
if [ -f fs.cpio.lzma ]; then
unlzma < fs.cpio.lzma | cpio -idm --quiet && rm fs.cpio.lzma
elif [ -f fs.cpio.gz ]; then
zcat fs.cpio.gz | cpio -idm --quiet && rm fs.cpio.gz
fi
status
}
print_short_description() {
local short_desc=''
for LC in $LANG ${LANG%_*}; do
[ -e "$PKGS_DB/packages-desc.$LC" ] &&
short_desc=$(awk -F$'\t' -vp="$1" '$1==p{print $2; exit}' "$PKGS_DB/packages-desc.$LC")
done
[ -z "$short_desc" -a -s "$PKGS_DB/packages.info" ] &&
short_desc=$(awk -F$'\t' -vp="$1" '$1==p{print $4; exit}' "$PKGS_DB/packages.info")
[ -z "$short_desc" ] && short_desc="$SHORT_DESC"
longline "$short_desc"
}
grepesc() {
sed 's/\[/\\[/g'
}
call_pre_install() {
local tmp
if grep -q '^pre_install()' "$1"; then
action 'Execute pre-install commands...'
tmp="$(mktemp)"
cp "$1" "$tmp"
sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
( . "$tmp"; pre_install "$root" )
status
rm "$tmp"
fi
}
call_post_install() {
local tmp
if grep -q '^post_install()' "$1"; then
action 'Execute post-install commands...'
tmp="$(mktemp)"
cp "$1" "$tmp"
sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
( . "$tmp"; post_install "$root" )
status
rm "$tmp"
fi
}
install_package() {
debug "\ninstall_package('$1')"
local dir
PACKAGE_FILE="$1"
TMP_DIR="$(mktemp -d)"
{ cd "$TMP_DIR"; cpio --quiet -i receipt >/dev/null 2>&1; } < "$PACKAGE_FILE"
(
. "$TMP_DIR/receipt"
cat > "$TMP_DIR/receipt.var" <<EOT
PACKAGE="$PACKAGE"
VERSION="$VERSION"
EXTRAVERSION="$EXTRAVERSION"
CATEGORY="$CATEGORY"
SHORT_DESC="$SHORT_DESC"
WEB_SITE="$WEB_SITE"
TAGS="$TAGS"
DEPENDS="$DEPENDS"
CONFIG_FILES="$CONFIG_FILES"
PACKED_SIZE="$PACKED_SIZE"
UNPACKED_SIZE="$UNPACKED_SIZE"
EOT
rm "$TMP_DIR/receipt"
)
. "$TMP_DIR/receipt.var"
mkdir -p "$INSTALLED/$PACKAGE"
find "$INSTALLED/$PACKAGE" -type f \( ! -name modifiers ! -name files.list \) -delete
touch "$PKGS_DB/installed.$SUM"
sed -i "/ $(basename "$PACKAGE_FILE")$/d" "$PKGS_DB/installed.$SUM" 2>/dev/null
cd "$(dirname "$PACKAGE_FILE")"
$CHECKSUM "$(basename "$PACKAGE_FILE")">> "$PKGS_DB/installed.$SUM"
install_all_deps "$PACKAGE_FILE"
if [ -n "$cookmode" ]; then
f=${PACKAGE_FILE%/*}; f=${f%/*}; f=${f##*/}
if [ "$f" == "$(cat /etc/slitaz-release)" ]; then
_ 'Installing (web/cache): %s' "$(basename $PACKAGE_FILE .tazpkg)"
else
_ 'Installing (pkg/local): %s' "$(basename $PACKAGE_FILE .tazpkg)"
fi
fi
if [ -n "$sequence" ]; then
title 'Installation of package "%s" (%s)' "$PACKAGE" "$sequence"
else
title 'Installation of package "%s"' "$PACKAGE"
fi
if [ -z "$quiet" ]; then
print_short_description "$PACKAGE"
separator '-'
fi
action 'Copying package...'
cp "$PACKAGE_FILE" "$TMP_DIR"
status
cd "$TMP_DIR"
extract_package "$(basename "$PACKAGE_FILE")"
. "$TMP_DIR/receipt.var"
cd "$INSTALLED"
IFS=$'\n'
if [ -f "$PACKAGE/files.list" ]; then
while read file; do
grep -q "^$(echo "$file" | grepesc)$" "$TMP_DIR/files.list" && continue
for i in $(cat "$PACKAGE/modifiers" 2>/dev/null;
fgrep -sl "$PACKAGE" */modifiers | cut -d/ -f1); do
grep -qs "^$(echo "$file" | grepesc)$" "$i/files.list" && continue 2
done
echo "$file"
done < "$PACKAGE/files.list"> "$TMP_DIR/files2remove.list"
fi
unset IFS
action 'Remember modified packages...'
{
check=false
for i in $(fgrep -v [ $TMP_DIR/files.list); do
[ -e "$root$i" ] || continue
[ -d "$root$i" ] && continue
echo "- $i"
check=true
done ;
$check && \
for i in *; do
[ "$i" == "$PACKAGE" ] && continue
[ -s "$i/files.list" ] || continue
awk "{ printf \"$i %s\\n\",\$1 }" < "$i/files.list"
done;
} | awk '
{
if ($1 == "-" || file[$2] != "") {
file[$2] = file[$2] " " $1
if ($1 != "-") {
if (pkg[$1] == "") all = all " " $1
pkg[$1] = pkg[$1] " " $2
}
}
}
END {
for (i = split(all, p, " "); i > 0; i--)
for (j = split(pkg[p[i]], f, " "); j > 0; j--)
printf "%s %s\n",p[i],f[j];
}
' | while read dir file; do
if grep -qs "^$dir$" "$PACKAGE/modifiers"; then
rm "$TMP_DIR/$file" 2>/dev/null
continue
fi
grep -qs "^$PACKAGE$" "$dir/modifiers" && continue
if [ -s "$dir/volatile.cpio.gz" ]; then
zcat "$dir/volatile.cpio.gz" | cpio -t --quiet | \
grep -q "^${file#/}$" && continue
fi
echo "$PACKAGE">> "$dir/modifiers"
done
status
cd "$TMP_DIR"
for file in receipt files.list description.txt $CHECKSUM; do
[ -f "$file" ] && cp "$file" "$INSTALLED/$PACKAGE"
done
call_pre_install "$INSTALLED/$PACKAGE/receipt"
if [ -n "$CONFIG_FILES" ]; then
action 'Saving configuration files...'
debug "\n"
cd fs
local config_file
for config_file in $CONFIG_FILES; do
debug "  config_file: '$config_file'"
find ${config_file#/} -type f 2>/dev/null
done | cpio -o -H newc --quiet | gzip -9 > "$INSTALLED/$PACKAGE/volatile.cpio.gz"
cd ..
if [ -z "$newconf" ]; then
debug "  no '--newconf': clean official config files"
for config_file in $CONFIG_FILES; do
for config_file_official in $(find "fs$config_file" ! -type d 2>/dev/null | sed 's|^fs||'); do
if [ -e "$root$config_file_official" ]; then
debug "    official '$config_file_official' will be skipped"
rm "fs$config_file_official"
else
debug "    official '$config_file_official' will be written"
fi
done
done
fi
:; status
fi
if [ -n "$(ls fs/* 2>/dev/null)" ]; then
action 'Installing package...'
debug '\n  resolving destination links in source'
IFS=$'\n'
for dir in $(find fs -type d | sed 's|^fs||;/^$/d'); do
if ldir=$(readlink -n $root$dir); then
debug "  * mv 'fs$dir'\n    -> 'fs${dir%/*}/$ldir'"
mkdir -p "fs${dir%/*}/${ldir%/*}"
mv "fs$dir" "fs${dir%/*}/$ldir"
fi
done
unset IFS
debug '  copying folders and files to destination'
cp -af fs/* "$root/"
status
fi
if [ -s files2remove.list ]; then
action 'Removing old files...'
while read file; do
dir="$root$file"
rm -f "$dir"
while [ "$dir" != "$root/" ]; do
dir=$(dirname "$dir")
rmdir "$dir" 2>/dev/null || break
done
done < files2remove.list
:; status
fi
action "Removing all tmp files..."
cd ..; rm -rf "$TMP_DIR"
status
call_post_install "$INSTALLED/$PACKAGE/receipt"
local fl="$INSTALLED/$PACKAGE/files.list" upd=0 udesk umime uicon uschm ukrnl ukrnlfs
fgrep    /usr/share/applications/    "$fl" | fgrep -q .desktop && udesk='yes'
fgrep -q /usr/share/mime             "$fl" && umime='yes'
fgrep -q /usr/share/icon/hicolor     "$fl" && uicon='yes'
fgrep    /usr/share/glib-2.0/schemas "$fl" | fgrep -q .xml && uschm='yes'
fgrep    /usr/lib/gdk-pixbuf         "$fl" | fgrep -q .so && upixb='yes'
if fgrep -q /lib/modules             "$fl"; then
ukrnl='yes'
if fgrep -q /kernel/fs/ "$fl"; then
ukrnlfs='yes'
fi
fi
if [ -n "$udesk$umime$uicon$uschm$upixb$ukrnl" ]; then
action 'Update system databases...'
upd=1
fi
[ -n "$udesk" ] && chroot "$root/" /usr/bin/update-desktop-database /usr/share/applications 2>/dev/null
[ -n "$umime" ] && chroot "$root/" /usr/bin/update-mime-database /usr/share/mime
[ -n "$uicon" ] && chroot "$root/" /usr/bin/gtk-update-icon-cache /usr/share/icons/hicolor
[ -n "$uschm" ] && chroot "$root/" /usr/bin/glib-compile-schemas /usr/share/glib-2.0/schemas 2>&1 | fgrep -v '/apps/'
[ -n "$upixb" ] && chroot "$root/" /usr/bin/gdk-pixbuf-query-loaders --update-cache
if [ -n "$ukrnlfs" ]; then
for i in $(awk -F/ '{if($6=="fs" && $8~$7)print $7}' "$fl" | sort -u); do
touch "$root/etc/filesystems"
grep -q "^$i\$" "$root/etc/filesystems" || echo "$i">> "$root/etc/filesystems"
done
fi
[ -n "$ukrnl" ] && grep '/lib/modules' "$fl" | cut -d'/' -f4 | uniq | xargs chroot "$root/" /sbin/depmod -a
[ "$upd" -eq 1 ] && status
SIZES=$(echo $PACKED_SIZE $UNPACKED_SIZE | sed 's|\.0||g')
DEPENDS=$(echo $DEPENDS)
PKG_SUM="$(fgrep " $PACKAGE-$VERSION$EXTRAVERSION.tazpkg" "$PKGS_DB/installed.$SUM" | cut -d' ' -f1)"
ii="$PKGS_DB/installed.info"
sed -i "/^$PACKAGE	/d" "$ii"
cat >> "$ii" <<EOT
$PACKAGE	$VERSION$EXTRAVERSION	$CATEGORY	$SHORT_DESC	$WEB_SITE	$TAGS	$SIZES	$DEPENDS	$PKG_SUM
EOT
TEMP_FILE="$(mktemp)"
sort "$ii"> "$TEMP_FILE"; mv -f "$TEMP_FILE" "$ii"; chmod a+r "$ii"; unset ii
cd "$CUR_DIR"
footer "$(_ 'Package "%s" (%s) is installed.' "$PACKAGE" "$VERSION$EXTRAVERSION")"
log_pkg Installed
[ -s "$UP_LIST" ] && sed -i "/^$PACKAGE\$/d" "$UP_LIST"
}
PACKAGE=$(
tmp_dir=$(mktemp -d); cd "$tmp_dir"
cpio --quiet -i receipt >/dev/null 2>&1
. ./receipt; echo $PACKAGE
rm -rf "$tmp_dir"
) < "$1"
if grep -qs "^$PACKAGE$" "$BLOCKED"; then
_ 'Package "%s" blocked.' "$PACKAGE"
exit 1
fi
if [ -z "$forced" ]; then
debug "\ncheck for installed package '$PACKAGE'"
awk -F$'\t' -vpv="$PACKAGE" '$1==pv { exit 1 }' "$PKGS_DB/installed.info"
if [ "$?" -eq 1 ]; then
if [ -z "$quiet" ]; then
newline
_ '"%s" package is already installed.' "$(colorize 34 "$PACKAGE")"
longline "$(_ 'You can use the --forced option to force installation.')"
newline
fi
exit 1
fi
fi
install_package "$(realpath "$1")"
