kiss/kiss

295 lines
8.1 KiB
Plaintext
Raw Normal View History

2019-06-13 14:48:08 +00:00
#!/bin/sh
#
# kiss - package manager for kiss linux.
die() {
2019-06-14 10:38:19 +00:00
printf '\033[31m!>\033[m %s\n' "$@" >&2
2019-06-13 14:48:08 +00:00
exit 1
}
log() {
printf '\033[32m=>\033[m %s\n' "$@"
}
source_type() {
[ -z "$1" ] && return 1 # No file.
2019-06-14 10:38:19 +00:00
[ -f "$1" ] && return 2 # Local file.
[ -f "$src_dir/${1##*/}" ] && return 3 # Cached downloaded file.
[ -z "${1##git:*}" ] && return 4 # Git repository.
[ -z "${1##*://*}" ] && return 5 # Remote file.
2019-06-13 14:48:08 +00:00
}
2019-06-18 08:05:15 +00:00
pkg_clean() {
2019-06-18 18:39:40 +00:00
rm -rf -- "$mak_dir" "$pkg_dir" \
2019-06-19 06:20:37 +00:00
"$cac_dir/manifest-$$" "$cac_dir/tar" "$cac_dir/checksums-$$"
2019-06-18 08:05:15 +00:00
}
2019-06-13 16:40:50 +00:00
pkg_search() {
set -f
# shellcheck disable=2086,2046
set -- "$1" $(IFS=:; find $KISS_PATH -maxdepth 1 -name "$1")
2019-06-13 16:40:50 +00:00
set +f
[ -z "$2" ] && die "Package '$1' not in any repository."
rep_dir=${2%/$1}
}
2019-06-13 14:48:08 +00:00
pkg_setup() {
2019-06-13 16:40:50 +00:00
pkg_search "$1"
cd "$rep_dir/$1" || die "'$rep_dir/$1' not accessible"
2019-06-13 14:48:08 +00:00
[ -f sources ] || die "Sources file not found."
[ -x build ] || die "Build file not found or not executable."
2019-06-19 13:45:37 +00:00
[ -f licenses ] || die "License file not found or empty."
2019-06-13 14:48:08 +00:00
read -r ver rel < version || die "Version file not found."
pkg=${name:=$1}\#$ver-$rel.tar.gz
}
pkg_depends() {
[ -f depends ] && while read -r dep opt; do
2019-06-15 06:19:20 +00:00
pkg_list "$dep" || {
2019-06-15 06:22:17 +00:00
[ "$1" = install ] && [ "$opt" = make ] && continue
2019-06-15 06:19:20 +00:00
2019-06-14 06:28:32 +00:00
case $missing in
*" $dep,"*) ;;
*) missing="$missing $dep,"
2019-06-14 06:28:32 +00:00
pkg_setup "$dep"
pkg_depends ;;
esac
2019-06-15 06:19:20 +00:00
}
done < depends
2019-06-13 14:48:08 +00:00
}
pkg_sources() {
src_dir=$cac_dir/sources/$name
2019-06-24 07:35:37 +00:00
mkdir -p "$src_dir"
2019-06-13 14:48:08 +00:00
while read -r src _; do
case $(source_type "$src"; echo $?) in
4) git clone "${src##git:}" "$mak_dir" ;;
5) wget -P "$src_dir" "$src" || die "Failed to download $src." ;;
0|1) die "Source file '$src' not found." ;;
esac
done < sources
}
pkg_checksum() {
while read -r src _; do
case $(source_type "$src"; echo $?) in
2) src_path=$src ;;
3) src_path=$src_dir/${src##*/} ;;
4) continue
esac
(cd "${src_path%/*}" >/dev/null; sha256sum "${src##*/}") ||
die "Failed to generate checksums."
done < sources > "${1-checksums}"
}
pkg_verify() {
2019-06-19 06:20:37 +00:00
pkg_checksum "$cac_dir/checksums-$$"
2019-06-18 18:39:40 +00:00
2019-06-19 06:20:37 +00:00
cmp -s "$cac_dir/checksums-$$" checksums ||
2019-06-19 07:20:59 +00:00
die "Checksum mismatch, run '$kiss checksum $name'."
2019-06-13 14:48:08 +00:00
}
pkg_extract() {
while read -r src dest; do
[ "$dest" ] && mkdir -p "$mak_dir/$dest"
case $(source_type "$src"; echo $?)-$src in
2-*) cp -f "$src" "$mak_dir/$dest" ;;
2019-06-23 05:41:47 +00:00
3-*.tar*|3-*.tgz)
2019-06-13 14:48:08 +00:00
tar xf "$src_dir/${src##*/}" -C "$mak_dir/$dest" \
--strip-components 1 || die "Couldn't extract ${src##*/}" ;;
[01]-*) die "${src##*/} not found."
esac
done < sources
}
pkg_build() {
(cd "$mak_dir"; "$OLDPWD/build" "$pkg_dir") || die "Build failed."
cp -Rf "$rep_dir/$name" "$pkg_db"
log "Sucessfully built $pkg." 2> "$pkg_db/$name/manifest"
}
pkg_strip() {
log "Stripping unneeded symbols from binaries and libraries."
find "$pkg_dir" -type f | while read -r binary; do
case $(file -bi "$binary") in
application/x-sharedlib*|application/x-pie-executable*)
strip_opts=--strip-unneeded
;;
application/x-archive*) strip_opts=--strip-debug ;;
application/x-executable*) strip_opts=--strip-all ;;
*) continue ;;
esac
2019-06-22 15:58:58 +00:00
strip "$strip_opts" "$binary" 2>/dev/null
2019-06-13 14:48:08 +00:00
done
}
pkg_manifest() {
2019-06-18 08:01:06 +00:00
# Store the file and directory list of the package.
# Directories have a trailing '/' and the list is sorted in reverse.
2019-06-18 08:38:46 +00:00
(cd "$pkg_dir" && find ./* -type d -exec printf '%s/\n' {} + -or -print) |
sort -r | sed -e ss.ss | tee manifest > "$pkg_db/$name/manifest"
2019-06-13 14:48:08 +00:00
}
pkg_tar() {
tar zpcf "$bin_dir/$pkg" -C "$pkg_dir" . || die "Failed to create package."
2019-06-17 06:41:31 +00:00
log "Use '$kiss install $name' to install the package."
2019-06-13 14:48:08 +00:00
}
2019-06-17 07:18:36 +00:00
pkg_conflicts() {
log "Checking for package conflicts."
# Extract manifest from tarball and strip directories.
2019-06-23 19:05:45 +00:00
tar xf "$bin_dir/$pkg" -O "./var/db/$kiss/$name/manifest" |
2019-06-18 08:01:06 +00:00
while read -r line; do
2019-06-19 06:20:37 +00:00
[ "${line%%*/}" ] && printf '%s\n' "$line" >> "$cac_dir/manifest-$$"
2019-06-18 08:01:06 +00:00
done
2019-06-17 07:18:36 +00:00
# Compare extracted manifest to all installed manifests.
# If there are matching lines (files) there's a package
# conflict.
for db in "$sys_db"/*; do
[ "$name" = "${db##*/}" ] && continue
grep -Fxf "$cac_dir/manifest-$$" "$db/manifest" 2>/dev/null &&
2019-06-17 07:18:36 +00:00
die "Package '$name' conflicts with '${db##*/}'."
done
}
2019-06-13 14:48:08 +00:00
pkg_install() {
[ -f "$bin_dir/$pkg" ] || args b "$name"
2019-06-17 07:18:36 +00:00
pkg_conflicts
# Create a backup of 'tar' so it isn't removed during
# package installation.
cp "$(command -v tar)" "$cac_dir"
2019-06-17 07:18:36 +00:00
log "Removing previous version of package if it exists."
pkg_remove
2019-06-17 07:18:36 +00:00
"$cac_dir/tar" kpxf "$bin_dir/$pkg" -C "$sys_dir/" 2>/dev/null
2019-06-13 14:48:08 +00:00
"$sys_db/$name/post-install" 2>/dev/null
log "Installed ${pkg%.tar.gz}"
}
pkg_remove() {
pkg_list "${1:-${name-null}}" || return 1
2019-06-13 14:48:08 +00:00
# Create a backup of 'rm' and 'rmdir' so they aren't
2019-06-16 16:59:21 +00:00
# removed during package removal.
cp "$(command -v rm)" "$cac_dir"
cp "$(command -v rmdir)" "$cac_dir"
2019-06-13 14:48:08 +00:00
while read -r file; do
2019-06-16 15:22:57 +00:00
[ "${file%/*}" = /etc ] && continue
2019-06-13 14:48:08 +00:00
if [ -d "$sys_dir$file" ]; then
"$cac_dir/rmdir" "$sys_dir$file" 2>/dev/null || continue
2019-06-13 14:48:08 +00:00
else
"$cac_dir/rm" -f -- "$sys_dir$file" || log "Failed to remove $file."
2019-06-13 14:48:08 +00:00
fi && log "Removed $file"
done < "$sys_db/${1:-$name}/manifest"
# Use the backup of 'rm' to remove 'rmdir' and itself.
"$cac_dir/rm" "$cac_dir/rmdir" "$cac_dir/rm"
2019-06-13 14:48:08 +00:00
}
pkg_updates() {
for item in "$sys_db/"*; do
2019-06-14 05:58:09 +00:00
pkg_search "${item##*/}"
2019-06-13 14:48:08 +00:00
read -r db_ver db_rel < "$item/version"
read -r re_ver re_rel < "$rep_dir/${item##*/}/version"
[ "$db_ver-$db_rel" != "$re_ver-$re_rel" ] &&
printf '%s\n' "${item##*/} $re_ver-$re_rel"
done
}
pkg_list() {
[ "$1" ] && { [ -d "$sys_db/$1" ]; return "$?"; }
for item in "$sys_db/"*; do
read -r version release 2>/dev/null < "$item/version" &&
printf '%s\n' "${item##*/} $version-$release"
done
}
args() {
2019-06-23 18:01:10 +00:00
[ -w "$KISS_ROOT/" ] || case $1 in
i*|r*) die "No write permissions to \$KISS_ROOT."
esac
case $1 in b*|c*|i*) pkg_setup "${2-null}"; esac
2019-06-13 14:48:08 +00:00
case $1 in
2019-06-17 06:41:31 +00:00
b*) [ -f checksums ] ||
die "Checksums missing, run '$kiss checksum $name'"
2019-06-13 14:48:08 +00:00
pkg_depends
2019-06-14 06:28:32 +00:00
[ -n "$missing" ] && die "Missing dependencies:${missing%,}"
2019-06-13 14:48:08 +00:00
pkg_sources
pkg_verify
pkg_extract
pkg_build
2019-06-14 06:28:32 +00:00
2019-06-13 14:48:08 +00:00
[ -f nostrip ] || pkg_strip
2019-06-14 06:28:32 +00:00
2019-06-13 14:48:08 +00:00
pkg_manifest
pkg_tar ;;
c*) pkg_sources
pkg_checksum
log "Generated checksums." ;;
2019-06-15 06:19:20 +00:00
i*) pkg_depends install
pkg_install ;;
2019-06-13 14:48:08 +00:00
l*) pkg_list "$2" ;;
r*) pkg_remove "${2-null}" || die "Package '${2-null}' not installed." ;;
2019-06-13 14:48:08 +00:00
u*) pkg_updates ;;
2019-06-24 07:35:37 +00:00
v*) log "$kiss 0.1.8" ;;
2019-06-13 14:48:08 +00:00
2019-06-17 06:41:31 +00:00
*) log "$kiss [b|c|i|l|r|u] [pkg]" \
2019-06-13 14:48:08 +00:00
"build: Build a package." \
"checksum: Generate checksums." \
2019-06-13 17:26:22 +00:00
"install: Install a package (Runs build if needed)." \
2019-06-13 14:48:08 +00:00
"list: List packages." \
"remove: Remove a package." \
"update: Check for updates."
esac
}
main() {
2019-06-18 08:05:15 +00:00
trap pkg_clean EXIT INT
2019-06-17 06:41:31 +00:00
kiss=${0##*/}
sys_db=${sys_dir:=$KISS_ROOT}/var/db/$kiss
2019-06-13 14:48:08 +00:00
[ -z "$KISS_PATH" ] && die "Set \$KISS_PATH to a repository location."
2019-06-13 15:11:59 +00:00
2019-06-17 06:41:31 +00:00
mkdir -p "${cac_dir:=${XDG_CACHE_HOME:=$HOME/.cache}/$kiss}" \
"${mak_dir:=$cac_dir/build-$$}" \
2019-06-13 16:40:50 +00:00
"${bin_dir:=$cac_dir/bin}" \
"${pkg_db:=${pkg_dir:=$cac_dir/pkg-$$}/var/db/$kiss}" ||
die "Couldn't create directories."
2019-06-13 14:48:08 +00:00
args "$@"
}
main "$@"