]> pd.if.org Git - zpackage/blobdiff - zpm-install
let newpackage set additional fields
[zpackage] / zpm-install
index 173ff1b85a3371b3f3650ce9461f469a21d09e9c..0a7cf3ed2a8335fe2d2ebede5c095ad264255fca 100755 (executable)
 #!/bin/sh
 
-# do one thing and do it well
-# this program installs packages from a package file
-# by default, it will install the latest version of each package
-# found in the file.
-
-# todo
-
-# if package specifiers are given as arguments after the package file
-# it will only install those packages.
-
-# package specifiers are of the form pkg[-ver[-rel]], i.e the
-# release can be omitted, and the version-release can be omitted.
-# examples:
-# zpm install -f foo-0.1-1.zpm
-# zpm install -f foo.zpm foo-0.1
-
-# todo: file tag handling
-
-# what we need to install a package:
-
-# recording repo: where we record what we've done
-# source: where we get the package and files from
-# install root: really just a prefix, but thought about differently,
-#    and we might need to do a chroot
-# package name to install, could be "all" or "all most recent"
-# but for now, assume only one package in a file?
-
-# zpm install [options] <package ...>
-
-pkgver=${ZPMPACKAGEVER:-1.0}
-pkgrel=${ZPMPACKAGEREL:-1}
-
-pkgroot=/
-
-# allocate an install id, perhaps hash package and timestamp
-# installid=$(echo $(date) $pkglist | zpm hash)
-
-# extract pre-scripts and run them
-# get list of paths to install
-# for each path, if directory, create and set mode
-# for each path, create leading directories
-# extract to something like /var/tmp/.hash, with low perms
-# only atomic if same filesystem, so use .installid.hash in the
-# install directory
-# set perms and such
-# move into place
-# after all the files, extract post scripts and run them
-
-# also need to mark package as installing so if it fails part way
-# through, it can be finished later
-# probably also want an option to "backup" any packages being upgraded
-# so it's trivial to downgrade or to revert if the install fails
-
-# option for "multipackage" just to let the system know that's what you meant
-# option to take filenames from stdin
-# parse package, version, release from file if not given
-# TODO what's the difference between prefix and pkgroot
-# need an option to not chown the files
-# option to install but not merge/track
-
-# options
-# -R install root, if installing as root, will chroot?
-# -C no chroot, even if root
-# -N no pre-scripts
-# -X no post-scripts
-# -f source repository file
-# -d local (recording) repository database
-# -D don't locally record
-# -t only files matching tags
-# -T exclude files matching tags
-
-chroot=1
-
-while getopts :R:CNXf:d:Dt:T:u:g: opt; do
+warn() {
+       echo $* 1>&2
+}
+
+die() {
+       echo $* 1>&2
+       zpm log -i -a 'aborting install' -t "$pkgid" "$*"
+       exit 1
+}
+
+changeall() {
+       for pkgid in $(zpm list -s $1); do
+               zpm pkg $pkgid status=$2
+       done
+}
+
+dryrun=0
+verbose=0
+runscripts=1
+runconfigure=1
+absorb=0
+overwrite=0
+syncopts=''
+installall=0
+mergefiles=0
+
+# zpm-install [-SCn] [ -d localdb ] [ -f pkgfile ] [ -R installroot ] pkgstr ...
+while getopts f:d:R:nSCvAOaF opt; do
        case $opt in
-               R) pkgroot="$OPTARG" ;;
-               C) chroot=0 ;;
                f) pkgfile="$OPTARG" ;;
-               u) user="$OPTARG" ;;
-               g) group="$OPTARG" ;;
-               d) ZPMDB="$OPTARG" ;;
+               F) mergefiles=1 ;;
+               d) localdb="$OPTARG" ;;
+               R) rootdir="$OPTARG" ;;
+               S) runscripts=0 ;;
+               C) runconfigure=0 ;;
+               A) absorb=1; syncopts="${syncopts} -A" ;;
+               a) installall=1; ;;
+               O) overwrite=1; syncopts="${syncopts} -O" ;;
+               n) dryrun=1 ;;
+               v) verbose=1 ;;
+               *) die "usage ..." ;;
        esac
 done
+shift $(( OPTIND - 1))
 
-shift $((OPTIND - 1))
+if [ -z "$1" ]; then
+       installall=1
+fi
 
-for cf in /etc/zpmrc ~/.zpmrc ./.zpmrc; do
-       test -r $cf && . $cf
-done
+if [ -z "$pkgfile" ]; then
+       pkgfile=$ZPM_PACKAGE_FILE
+fi
 
-: ${ZPMDB:=/var/lib/zpm/db.zpm}
+if [ $installall -eq 1 ]; then
+       pkglist="$(zpm list -f $pkgfile)"
+else
+       pkglist=$(zpm findpkg -f $pkgfile "$1")
+fi
 
-export ZPMDB
+if [ $verbose -gt 0 ]; then
+       echo $pkglist
+fi
 
-die() {
-       printf 'zpm-install:' 1>&2
-       printf ' %s' $* 1>&2
-       printf '\n' 1>&2
-       exit 1
-}
+if [ -z "$pkglist" ]; then
+       die "$0 no packages specified for install"
+fi
 
-if [ -z "$pkgfile" ]; then
-       # actually, if no pkgfile, get pkgfile from repo
-       # but need to loop over finding package files then
-       # so this program probably needs to be "install from pkgfile"
-       # and a separate one that will loop over a package
-       # spec list and find from repos
-       die "must specify package file" 
-       pkgfile="$package-$pkgver-$pkgrel.zpm"
+if [ "$idempotent" = 1 ]; then
+       idempotent='or ignore'
 fi
 
-set -e
-zpm test -v $pkgfile
+if [ -n "$rootdir" ]; then
+       : rootdir=${rootdir%%/}
+fi
 
-if [ $# -gt 0 ]; then
-       pkglist="$@"
-else
-       pkglist=$(zpm findpkg $pkgfile)
+if [ -z "$localdb" ]; then
+       localdb=${rootdir}/var/lib/zpm/local.db
 fi
 
-pathlist() {
-       zpm shell $pkgfile<<EOS
-select path from packagefiles
-       where package||'-'||version||'-'||release = '$pkg'
-       ;
-EOS
-}
+if [ ! -f "$localdb" ]; then
+       if [ -n "$rootdir" ] && [ ! -d $rootdir ]; then
+               mkdir $rootdir || die "can't create $rootdir: $!"
+       fi
+       for d in /var /var/lib /var/lib/zpm; do
+               test -d $rootdir/$d || mkdir $rootdir/$d || die "can't create $rootdir/$d/: $!"
+       done
+       zpm init "$localdb"
+       if [ $? -ne 0 ]; then
+               die "aborting install"
+       fi
+fi
 
-# find a repo file for a given package
-findrepofor() {
-       false
-}
+ZPMDB=$localdb
+export ZPMDB
 
-installpkg() (
-       package="$1"
-)
+if [ -z "$ZPMDB" ]; then
+       die "no local db"
+else
+       #echo "localdb = $ZPMDB"
+       true
+fi
 
-pkgname() {
-       # strip off a trailing release
-       nv=$(printf '%s' "$1" | sed -e 's/-[0-9]\+$//')
-       nv=$(printf '%s' "$nv" | sed -e 's/-[0-9][^-]*$//')
-       printf '%s' "$nv"
-}
+zpm test -v "$ZPMDB" || die "$ZPMDB is not a zpm database"
 
-# TODO see if we're already installed
-# if we are, then bail...
-
-
-# how to do an upgrade?
-# paths to add
-# paths to remove
-# paths to replace
-
-newfiles() {
-       #zpm merge $pkgfile $newver
-
-       # add...
-       zpm shell $ZPMDB<<-EOS
-       select NV.path
-       from packagefiles NV
-       where
-       printf('%s-%s-%s', NV.package, NV.version, NV.release) = '$1'
-       except
-       select OV.path
-       from packagefiles OV
-       where
-       printf('%s-%s-%s', OV.package, OV.version, OV.release) = '$2'
-       ;
-       EOS
-}
+# check if we're installing something already
+var=$(zpm list -f $localdb -s installing | wc -l)
+if [ $var -gt 0 ]; then
+       zpm list -v -f $localdb -s installing 
+       die "already ($localdb) installing $var package(s)"
+fi
+# check if we're removing something already
+var=$(zpm list -f $localdb -s removing | wc -l)
+if [ $var -gt 0 ]; then
+       zpm list -v -f $localdb -s removing 
+       die "already ($localdb) removing $var package(s)"
+fi
+var=$(zpm list -f $localdb -s updating | wc -l)
+if [ $var -gt 0 ]; then
+       zpm list -v -f $localdb -s updating 
+       die "already ($localdb) updating $var package(s)"
+fi
 
-removedfiles() {
-       #zpm merge $pkgfile $newver
-
-       zpm shell $ZPMDB<<-EOS
-       select OV.path
-       from packagefiles OV
-       where
-       printf('%s-%s-%s', OV.package, OV.version, OV.release) = '$2'
-       except
-       select NV.path
-       from packagefiles NV
-       where
-       printf('%s-%s-%s', NV.package, NV.version, NV.release) = '$1'
-       ;
-       EOS
-}
+if [ -n "$rootdir" ]; then
+       ZPM_ROOT_DIR="$rootdir"
+       export ZPM_ROOT_DIR
+fi
 
-changedfiles() {
-       # add...
-       zpm shell $ZPMDB<<-EOS
-       select NV.path
-       from packagefiles OV
-       inner join packagefiles NV
-       on OV.path = NV.path
-       where
-       printf('%s-%s-%s', NV.package, NV.version, NV.release) = '$1'
-       and
-       printf('%s-%s-%s', OV.package, OV.version, OV.release) = '$2'
-       and NV.hash != OV.hash
-       ;
-       EOS
-}
+for pkgid in $pkglist; do
+       curstatus=$(zpm pkg $pkgid status)
+       if [ "$curstatus" = 'installed' ]; then
+               die "$pkgid already installed"
+       fi
 
-do_upgrade() {
-       newver=$1
-       oldver=$2
+       package=$(zpm parse -n $pkgid)
+       current=$(zpm list -s installed "$package")
        
-       set -e
-       echo merging $newver
-       zpm merge $pkgfile $newver
-       zpm pkg $newver status installing
-
-       echo newfiles
-       newct=$(newfiles | wc -l)
-       if [ $newct -gt 0 ]; then
-               newfiles $newver $oldver | xargs zpm ipkgfile ${user+-u $user} ${group+-g $group} -R "$pkgroot" -f $pkgfile -- $nver
+       if [ $runscripts -gt 0 ]; then
+               # TODO run pre-upgrade script if needed
+               # zpm runscript -p pre-upgrade $current $pkgid
+               zpm script -f $pkgfile -p pre-install $pkgid $current
+               if [ $? -ne 0 ]; then
+                       die "pre-install script for $pkgid failed"
+               fi
+       else
+               if zpm script -f $pkgfile -Fql -p pre-install $pkgid; then
+                       zpm note -e -p $pkgid -m 'pre-install script not run'
+               fi
        fi
 
-       echo changed
-       ct=$(changedfiles | wc -l)
-       if [ $ct -gt 0 ]; then
-               changedfiles $newver $oldver | xargs zpm ipkgfile ${user+-u $user} ${group+-g $group} -R "$pkgroot" -f $pkgfile -- $pkg
+       # remove the package if it exists.  can't be in an installed
+       # state, would have bailed above.  So, if it exists, can only
+       # be 'upgraded'.  This should be fast, because we won't run
+       # a garbage collect, so any possible duplicate files between
+       # an upgraded or removed files, if they're there, won't need
+       # to be merged.
+
+       # only merge if localdb and pkgfile are different
+       if [ "$pkgfile" != "$ZPMDB" ]; then
+               zpm rmpackage $pkgid
+               if [ $verbose -gt 0 ]; then
+                       echo merging $pkgid
+               fi
+               if [ $mergefiles -eq 1 ]; then
+                       zpm merge -u -F -f $pkgfile -s installing $pkgid
+               else
+                       zpm merge -u -f $pkgfile -s installing $pkgid
+               fi
+               if [ $? -ne 0 ]; then
+                       die "merging $pkgid failed"
+               fi
+       else
+               zpm pkg $pkgid status=installing
        fi
 
-       echo removed
-       ct=$(removedfiles | wc -l)
-       if [ $ct -gt 0 ]; then
-               removedfiles $newver $oldver | xargs rm
-       fi
+       zpm shell "$ZPMDB" "update packages set status='updating' where status='installed' and package in (select package from packages where status = 'installing')"
+done
 
-       zpm pkg $newver status installed
-       zpm pkg $oldver status upgraded
+# do the sync
 
-       zpm shell $ZPMDB<<-EOS
-       delete from packages
-       where
-       printf('%s-%s-%s', package, version, release) = '$oldver';
-       EOS
-}
+#zpm shell $ZPMDB 'select * from install_status' 1>&2
+if [ $dryrun -gt 0 ]; then
+       syncopts="$syncopts -n"
+fi
 
-for pkg in $pkglist; do
-       pname=$(pkgname $pkg)
-       curver=$(zpm findpkg $ZPMDB $pname)
-       pkg=$(zpm findpkg $pkgfile $pkg)
-       upgrade='n'
+if [ $verbose -gt 0 ]; then
+       syncopts="$syncopts -v"
+fi
 
-       if [ -n "$curver" ]; then
-               set +e
-               upgrade=$(zpm vercmp $pkg $curver)
-       fi
+if [ "$pkgfile" != "$ZPMDB" ]; then
+       syncopts="$syncopts -f $pkgfile"
+fi
 
-       case $upgrade in
-               0) die 'already installed' $curver;;
-               1) do_upgrade $pkg $curver ; exit 0 ;;
-               -1) die 'would be downgrade' $curver '->' $pkg ;;
-               n) printf 'ok to install %s\n' $pkg ;;
-       esac
+#zpm shell $ZPMDB 'select * from syncinfo'
+#zpm list -v
+zpm syncfs $syncopts
 
-       zpm merge $pkgfile $pkg
-       # TODO find scripts marked as pre-install
-       #run_preinstall
+syncrv=$?
 
-       # TODO if this is an upgrade, run pre-upgrade
-       #if [ $upgrade != 'n' ]; then
-       #       run_preupgrade
-       #fi
+if [ $dryrun -gt 0 ]; then
+       for pkgid in $pkglist; do
+               zpm pkg $pkgid status=dryrun
+       done
+fi
 
-       # TODO get total size of install so we can do a progress bar
-       #tsize=totalsize
+if [ $syncrv -ne 0 ]; then
+       zpm pkg $pkgid status=failed
+       die 'zpm-syncfs failed';
+fi
 
-       # add package info to local package db
-       #zpm merge $pkgfile $pkg
+if [ $(id -u) -eq 0 ]; then
+       if [ ! -d $rootdir/etc ]; then
+               warn "no etc directory in $rootdir, skipping ldconfig"
+       elif [ -f $rootdir/sbin/ldconfig ]; then
+               $rootdir/sbin/ldconfig -r ${rootdir:-/}
+       elif [ -f /sbin/ldconfig ]; then
+               /sbin/ldconfig -r ${rootdir:-/}
+       else
+               true
+       fi
+fi
 
-       # check for conflicts
+for pkgid in $pkglist; do
+       package=$(zpm parse -n $pkgid)
+       current=$(zpm list -s updating "$package")
+       
+       if [ $runscripts -gt 0 ]; then
+               zpm script -p post-install $pkgid $current
+       else
+               if zpm script -Fql -p post-install $pkgid; then
+                       zpm note -e -p $pkgid -m 'post-install script not run'
+               fi
+       fi
 
-       # mark package in localdb as installing
-       # zpm setmark installing $pkg
-       # install all the files for a package
-       # TODO install directories first in order of path length
-       echo installing $pkglist
-       filecount=$(pathlist | wc -l)
-       echo $filecount files
-       #die 'aborting for test'
-       #pathlist
-       pathlist | xargs zpm ipkgfile ${user+-u $user} ${group+-g $group} -R "$pkgroot" -f $pkgfile -- $pkg
+       if [ -n "$current" ]; then
+               zpm pkg $pkgid status=installed :$current status=updated
+       else
+               zpm pkg $pkgid status=installed
+       fi
 
-       # TODO find scripts marked as post-install
-       # TODO if this is an upgrade, run post-upgrade
+       # TODO skip configure if not on a terminal, regardless of settings
+       # TODO will need force option
+       if [ $runconfigure -gt 0 ]; then
+               zpm script -p configure $pkgid
+       else
+               if zpm script -Fql -p configure $pkgid; then
+                       zpm note -e -p $pkgid -m 'configure script not run'
+               fi
+       fi
 
-       # mark as ready for install
-       #zpm setmark ready $pkg
 done
 
-#zpm setmark installed $pkglist
+changeall updating updated