aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xspm314
1 files changed, 314 insertions, 0 deletions
diff --git a/spm b/spm
new file mode 100755
index 0000000..3ad4803
--- /dev/null
+++ b/spm
@@ -0,0 +1,314 @@
+#!/bin/sh
+
+msg() { echo "[${name:-...}] $@"; }
+msgerr() { echo "[${name:-...}] ERROR: $@"; exit 1; }
+
+spm_build() {
+ needarg $1
+ if [ ! -d "$1" ]; then
+ msgerr "'$1' directory not exist."
+ fi
+
+ rm -f $HERE/$packagename
+ cd "$1"
+
+ # move all files in etc/ to .new suffix
+ if [ -d etc ]; then
+ for d in $(find etc -type f); do
+ [ -f $d ] || continue
+ case $d in *.new) continue;; esac
+ mv $d $d.new
+ done
+ fi
+
+ # -J for xz
+ # -z for gzip
+ # -j for bzip2
+ msg "Packaging $PWD."
+ tar -c -z -f $HERE/$packagename * || {
+ msgerr "Failed packaging $PWD."
+ }
+
+ tar -tvf $HERE/$packagename
+ msg "Package created: $HERE/$packagename."
+
+ exit 0
+}
+
+spm_install() {
+ checkdbdir
+ needarg $1
+ if [ "$(id -u)" != 0 ] || [ "$FAKEROOTKEY" ]; then
+ msgerr "root required to install package into system."
+ fi
+
+ if [ ! -f "$1" ]; then
+ msgerr "Package '$1' not exist."
+ fi
+
+ pkgname=${1##*/}
+
+ name=${pkgname%#*}
+ version=${pkgname#*#}; version=${version%%-*}
+ release=${pkgname##*-}; release=${release%.spm}
+
+ if [ "$name#$version-$release.spm" != "$pkgname" ]; then
+ msgerr "Valid 'spm' package format is '<name>#<version>-<release>.spm'"
+ fi
+
+ # if upgrade but not already installed, exit
+ if [ "$upgrade" ] && [ ! -f $PKGDB/$name ]; then
+ msgerr "Package '$name' not installed, use '-i' to install."
+ fi
+
+ # if already installed and not an upgrade, exit
+ if [ -f $PKGDB/$name ] && [ ! "$upgrade" ]; then
+ msgerr "Package '$name' is installed, use '-u' to reinstall/upgrade."
+ fi
+
+ # check if package is corrupt
+ msg "Verify package..."
+ tar -tvf "$1" > $SPMDIR/files.list 2>/dev/null || {
+ msg "Package '$1' is corrupted. Aborted."
+ rm -f $SPMDIR/files.list
+ exit 1
+ }
+
+ # check conflicting files
+ msg "Checking for conflicts..."
+ rm -f $SPMDIR/conflict.list
+ awk '{print $6}' $SPMDIR/files.list | while read -r line; do
+ [ "$line" = "${line%.new}.new" ] && line=${line%.new}
+ # instant conflict if cross, mean file to directory and vice versa
+ case $line in
+ */[|*/[[) continue;; # TODO: fix detected '[' and '[[' as conflicted
+ */) if [ -e "${SPM_ROOT%/}"/"$line" ] && [ ! -d "${SPM_ROOT%/}"/"$line" ]; then
+ echo "$line" >> $SPMDIR/conflict.list; continue
+ fi;;
+ *) if [ -e "${SPM_ROOT%/}"/"$line" ] && [ -d "${SPM_ROOT%/}"/"$line" ] && [ ! -L "${SPM_ROOT%/}"/"$line" ]; then
+ echo "$line" >> $SPMDIR/conflict.list; continue
+ fi;;
+ esac
+ if [ -e "${SPM_ROOT%/}"/"$line" ]; then
+ case $line in */) continue;; esac # if directory not conflict
+ if [ "$upgrade" ] && grep -qx "$line" $PKGDB/$name; then
+ continue # if upgrade and exist in previous version then not conflict
+ else
+ echo "$line" >> $SPMDIR/conflict.list
+ fi
+ fi
+ done
+
+ if [ -f "$SPMDIR/conflict.list" ] && [ ! "$SPM_FORCEINSTALL" ]; then
+ cat "$SPMDIR/conflict.list"
+ msg "File conflict found. Enable 'SPM_FORCEINSTALL' env to force install."
+ rm -f "$SPMDIR/conflict.list"
+ exit 1
+ fi
+
+ msg "$([ $upgrade ] && echo Upgrading || echo Installing) package..."
+ rm -f $SPMDIR/install.list
+ tar -xvhpf "$1" -C "${SPM_ROOT%/}"/ | while read -r line; do
+ if [ "$line" = "${line%.new}.new" ]; then
+ line=${line%.new}
+ # if file not exist or same file, just move it
+ if [ ! -e "$SPM_ROOT/$line" ] || diff "$SPM_ROOT/$line".new "$SPM_ROOT/$line" >/dev/null; then
+ mv -f "$SPM_ROOT/$line".new "$SPM_ROOT/$line"
+ fi
+ fi
+ echo "$line" >> $SPMDIR/install.list
+ done
+
+ if [ "$upgrade" ]; then
+ cd $PKGDB
+ # remove files from old package thats not in new package
+ tail -n+2 $name > $SPMDIR/old.list
+ grep -Fxv -f $SPMDIR/install.list $SPMDIR/old.list | tac | while read -r line; do
+ case $line in
+ */) grep -x "$line" * | grep -v $name: >/dev/null || rmdir "${SPM_ROOT%/}"/"$line";;
+ *) rm "${SPM_ROOT%/}"/"$line";;
+ esac
+ done
+ rm -f $SPMDIR/old.list
+ cd - >/dev/null
+ fi
+
+ # register package into db
+ mkdir -p $PKGDB
+ echo "$version-$release" > $PKGDB/$name
+ cat $SPMDIR/install.list >> $PKGDB/$name
+ rm -f $SPMDIR/install.list
+
+ # permission
+ mkdir -p $PERMDIR $OWNDIR
+ rm -f $PERMDIR/$name $OWNDIR/$name
+ grep ^d $SPMDIR/files.list | awk '{print $1,$2,$6}' | while read -r perms owner dir; do
+ [ "$perms" = "drwxr-xr-x" ] || echo "$(cvperms $perms) $dir" >> $PERMDIR/$name
+ [ "$owner" = "root/root" ] || echo "$owner $dir" | sed 's,/,:,' >> $OWNDIR/$name
+ done
+ rm -f $SPMDIR/files.list
+
+ # correct dir permission
+ [ "$(ls -1 $PERMDIR)" ] && {
+ cat $PERMDIR/* | while read -r perms dir; do
+ [ -d "${SPM_ROOT%/}"/"$dir" ] || continue
+ chmod "$perms" "${SPM_ROOT%/}"/"$dir"
+ done
+ }
+ # correct dir ownership
+ [ "$(ls -1 $OWNDIR)" ] && {
+ cat $OWNDIR/* | while read -r owner dir; do
+ [ -d "${SPM_ROOT%/}"/"$dir" ] || continue
+ chown "$owner" "${SPM_ROOT%/}"/"$dir"
+ done
+ }
+
+ [ -x /sbin/ldconfig ] && {
+ /sbin/ldconfig -r "${SPM_ROOT:-/}"
+ }
+
+ msg "Package '${pkgname%.spm}' $([ $upgrade ] && echo upgraded. || echo installed.)"
+
+ exit 0
+}
+
+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"
+}
+
+
+spm_remove() {
+ checkdbdir
+ needarg $1
+ if [ ! -s $PKGDB/$1 ]; then
+ msgerr "Package '$1' not installed."
+ fi
+
+ cd $PKGDB
+ tail -n+2 $1 | tac | while read -r line; do
+ case $line in
+ */) grep -x "$line" * | grep -v $1: >/dev/null || rmdir "${SPM_ROOT%/}"/"$line";;
+ *) rm "${SPM_ROOT%/}"/"$line";;
+ esac
+ done
+
+ rm -f $1 $PERMDIR/$1 $OWNDIR/$1
+ msg "Package '$1' removed."
+
+ exit 0
+}
+
+spm_allinstalled() {
+ checkdbdir
+ for i in $PKGDB/*; do
+ echo "${i##*/} $(head -n1 $i)"
+ done
+ exit 0
+}
+
+spm_listfiles() {
+ checkdbdir
+ needarg $1
+ tail -n+2 $PKGDB/$1
+ exit 0
+}
+
+spm_owner() {
+ checkdbdir
+ needarg $1
+ set -- ${1#/}
+ cd $PKGDB
+ grep $1 * | tr ':' ' ' | column -t
+ exit 0
+}
+
+checkdbdir() {
+ if [ ! -d $PKGDB ]; then
+ msgerr "Database directory '$PKGDB' not exist. Aborted"
+ fi
+}
+
+needarg() {
+ [ "$1" ] || {
+ msgerr "This operation need argument(s). Aborted."
+ }
+}
+
+spm_help() {
+ cat << EOF
+usage: ${0##*/} -[a|b|h|i|l|r|o|u] <arg(s)>
+
+options:
+ -a print all installed packages
+ -b <path> build <path> directory into package
+ -h print this help message
+ -i <file> install <file> package into system
+ -l <pkg> list files installed by <pkg>
+ -r <name> remove installed <name> from system
+ -o <file> print owner of <file>
+ -u <file> re-install/upgrade <pkg>
+
+environments:
+ SPM_ROOT override default root (/) location
+ SPM_FORCEINSTALL force package installation
+
+EOF
+exit 0
+}
+
+if [ "$SPM_ROOT" ]; then
+ if [ ! -d "$SPM_ROOT" ]; then
+ msgerr "'$SPM_ROOT' directory not exist."
+ fi
+ SPM_ROOT=$(realpath $SPM_ROOT)
+fi
+
+HERE=$PWD
+SPMDIR=$SPM_ROOT/var/lib/spm
+PKGDB=$SPMDIR/db
+PERMDIR=$SPMDIR/perms
+OWNDIR=$SPMDIR/owner
+packagename="package.spm"
+
+if [ "$1" ]; then
+ case $1 in
+ -b) spm_build $2;;
+ -i) spm_install $2;;
+ -u) upgrade=1; spm_install $2;;
+ -r) spm_remove $2;;
+ -a) spm_allinstalled;;
+ -l) spm_listfiles $2;;
+ -o) spm_owner $2;;
+ -h) spm_help;;
+ esac
+else
+ echo "run '${0##*/} -h' to see help message."
+ exit 0
+fi
+
+exit 0