#!/bin/sh -e [ -n "$2" ] || { \ echo " usage: $(basename $0) [--bootstrap=] [] options: --bootstrap= use as the lowest layer in the overlay stack. commands: pl, pull acquire and patch package source code. cf, config, configure configure the package. mk, make build the package. in, inst, install install the package to its overlay. un, uninst, uninstall remove the package overlay. ad, add pull, configure, make, and install the package to its overlay. rm, remove delete the package version's overlay, source code, and signature. up [additional lmr flags] symlink the package into the system root with lmr, passing along flags. dn, down remove the package symlinks from the system root with lmr. do chroot into the package filesystem overlay and run . mt, mount mounts the package filesystem overlay at the given path. um, umount unmounts the package filesystem overlay at the given path. vr, ver, version print the default version for the given package. bl, built list all built versions for the given package. dp, deps, dependencies list package dependencies and their inferred versions. " && exit 0; } # if this is running on an interactive terminal (as opposed to in a cron job, # for example), if tput is installed, and if tput knows some color codes, then # set the color values. if [ -t 1 ] && [ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]; then _clr="$(tput sgr0)" _blu="$(tput setaf 6)" _ylw="$(tput setaf 3)" _red="$(tput setaf 1)" fi log() { echo "$_blu[LOG]$_clr $@"; } wrn() { echo "$_ylw[WRN]$_clr $@" >&2; } err() { echo "$_red[ERR]$_clr $@" >&2; exit 1; } export LIXPREFIX="${LIXPREFIX:-${0%/bin/lix}}" export LIXROOT="$(dirname "$(readlink -f "$0")")" export HOWROOT="$(dirname "$(readlink -f "$(which how)")")" export SRCREPO="${SRCREPO:-$LIXPREFIX/var/src}" export SRCROOT="${SRCROOT:-${LIXROOT%/lix}/src}" export cmd="$1" export OP="$cmd" export FAKEROOT="" export CLEANUPFAKEROOT="" export SUCCESS="" # these are lowercase because they will be used in 'how' scripts. export name export version [ -d "$SRCROOT" ] || err "$SRCROOT is not a directory!" [ -d "$SRCREPO" ] || err "$SRCREPO is not a directory!" [ -d "$LIXROOT" ] || err "$LIXROOT is not a directory!" . "$LIXROOT/lib/pkg.sh" . "$LIXROOT/lib/built.sh" . "$LIXROOT/lib/dependencies.sh" . "$LIXROOT/lib/lowerlayers.sh" . "$LIXROOT/lib/guessver.sh" # process command options if [ "${cmd#--bootstrap}" != "$cmd" ]; then if [ "$cmd" = "--bootstrap" ]; then shift export BSLAYER="$1" else export BSLAYER="$(echo "$cmd" | cut -d'=' -f2)" fi [ -d "$BSLAYER" ] || err "$BSLAYER is not a directory!" shift cmd="$1" fi case "$cmd" in do) docmd="$2" shift ;; mt|mnt|mount|um|umt|umnt|umount) FAKEROOT="$2" shift ;; up) while [ "${2#-}" != "$2" ]; do upflags="$upflags $2" shift done ;; sh|shell) # maybe this should be its own utility. [ "$1" ] || err "missing 'layer name' argument!" [ -e "$2" ] || err "no such file as '$2'." [ "$1" = "${1#lix/}" ] \ || wrn "you are using the 'lix' namespace! this can be dangerous..." layers="$(lowerlayers "$(dependencies "$(cat "$2")")" "$BSLAYER")" lyr mk "$1" chin "$(lyr up "$layers" "$1")" "${3:-sh}" exit 0 ;; esac # get required positional arguments name="$2" [ -n "$3" ] \ && version="$3" \ || version="$(guessver "$name")" [ -n "$version" ] || err "could not determine version for '$name'." cleanup() { [ -z "$PKGHOW" ] || umount "$PKGHOW" || true [ -z "$FAKEROOT" ] || unmountpkg "$FAKEROOT" || true [ -z "$CLEANUPFAKEROOT" ] || rmdir "$FAKEROOT" || true [ -n "$SUCCESS" ] || err "$name $version '$OP' failed" } trap cleanup EXIT INT HUP beginmsg() { OP="$1" log "starting '$OP' for $name $version" } successmsg() { log "completed '$OP' for $name $version"; } expectsrc() { [ -d "$(lyr upperdir lix/$name/$version/src)" ] \ || err "'src' layer missing! did you run 'lix pull $name $version' first?" } pullcmd() { beginmsg "pull" # if `how` has specific instructions for this package but there is no # `src` package, then this must be a "bundle" package or something. # just create an empty source directory and call it a day. (but please # consider finding a more elegant way to handle bundles. there must # be one, but it will probably require a rewrite. design problems # usually arise out of fundamentally flawed models. with the right # model, a _clean_ solution becomes trivial.) if { how $name $version | grep -q ':' ; } \ && [ ! -d "$SRCROOT/pkg/$name" ] then wrn "no 'src' entry. assuming this is a 'sourceless' package..." mkdir -p "$SRCREPO/$name/$version" # ew... elif [ -e "$SRCREPO/$name/$version" ]; then wrn "$SRCREPO/$name/$version already exists. skipping remote pull." else src "$name" "$version"; fi if [ -d "$(lyr upperdir lix/$name/$version/src)" ]; then wrn "source code upper layer already exists! skipping patch.sh." else loadpkgdeps log "looking for a patch.sh from 'how' to run in $name's overlay." pkgdo ". ../how/env.sh; ../how/patch.sh" fi successmsg } confcmd() { beginmsg "configure" pkgdo ". ../how/env.sh; ../how/conf.sh" successmsg } makecmd() { beginmsg "make" pkgdo ". ../how/env.sh; ../how/make.sh" # compile "built-with" list mkdir -p -- "$LIXROOT/built-with/${name}" echo "$deps" > "$LIXROOT/built-with/${name}/$version" successmsg } instcmd() { beginmsg "install" upperdir="$(lyr upperdir lix/$name/$version)" # clean out previous installation and make backup if [ -d "$upperdir/fs" ]; then log "making backup of package's existing 'fs' layer..." fsbak="$upperdir/bak/$(basename "$(mktemp -u)")" mkdir -p "$fsbak" cp -a "$upperdir/fs/." "$fsbak/" fi # install. restore backup on failure. delete backup on success. if { pkgdo ". ../how/env.sh; ../how/inst.sh"; }; then log "removing backup of package's previous 'fs' layer..." rm -fr "$fsbak" rmdir "$(dirname "$fsbak")" 2> /dev/null || true else log "restoring backup of package's previous 'fs' layer..." rm -fr "$upperdir/fs" mv "$fsbak" "$upperdir/fs" rmdir "$(dirname "$fsbak")" 2> /dev/null || true exit 1 fi successmsg } # commands can be invoked with their full name, with a two-letter short form # composed of the first letter and the last consonant (e.g., 'mk' for 'make'), # and with an assortment of one-off abbreviations that just make sense for each # command. e.g., 'rm' for 'remove'. case "$cmd" in pl|pull) pullcmd ;; cf|cr|cg|conf|config|configure) expectsrc confcmd ;; mk|make) expectsrc makecmd ;; in|il|inst|install) expectsrc instcmd ;; ad|add) pullcmd expectsrc confcmd makecmd instcmd ;; cl|cn|clean) rm -fr "$(lyr upperdir lix/$name/$version)/src" 2> /dev/null || true rm -fr "$(lyr upperdir lix/$name/$version)/build" 2> /dev/null || true ;; rm|rv|remove) lyr rm "lix/$name/$version" ;; pg|purge) rm -fr $SRCREPO/$name/$version lyr rm "lix/$name/$version" ;; up) lmr -s $upflags "$(lyr upperdir lix/$name/$version/fs)" / ;; dn|down) lmr -s -u "$(lyr upperdir lix/$name/$version/fs)" / ;; do) expectsrc beginmsg "do" pkgdo ". ../how/env.sh; $docmd" successmsg ;; mt|mnt|mount) beginmsg "mount" [ -d "$mntpth" ] || err "no such directory: $mntpth" expectsrc mountpkg "$mntpth" >/dev/null \ || err "failed to mount $name $version overlay." successmsg ;; um|ut|umt|umnt|umount|unmount) unmountpkg "$mntpth" \ && log "unmounted $name $version overlay at $mntpth" \ || err "error unmounting $name $version overlay at $mntpth" ;; vr|vn|ver|version) echo "$version" ;; bl|built) built "$name" ;; dp|deps|dependencies) loadpkgdeps cols=0 cols="$(echo "$PKGDEPS" | while read line; do newcols="$(echo "$line" | awk '{ print $1 }' | wc -c)" [ "$newcols" -ge "$cols" ] || continue cols="$newcols" echo "$cols" done | tail -n1)" # get a list of dependencies with resolved version numbers. if no # version number could be resolved, the "version" column will be empty # and a warning will be printed. echo "$PKGDEPS" | while read line; do [ "$line" ] || continue; dep="$(echo "$line" | awk '{ print $1 }')" depver="$(echo "$line" | awk '{ print $2 }')" [ "$depver" ] || wrn "could not resolve dependency '$dep'!" # pad-space each dependency name so the versions align in a column. printf "%-${cols}s %s\n" "$dep" "$depver" done ;; *) err "unrecognized command '$cmd'";; esac SUCCESS="yes"