--- /dev/null
+#!/bin/sh
+
+# merge
+# collects info from package file and copies it into another package file
+
+# merge [ -d ZPMDB ] [-f $pkgfile] pkg
+# -F include file content
+# -S don't include script content
+
+die() {
+ printf 'zpm-merge:' 1>&2
+ printf ' %s' "$@" 1>&2
+ printf '\n' 1>&2
+ exit 1
+}
+
+verbose=0
+mergefiles=0
+mergescripts=1
+target=/var/lib/zpm/local.db
+
+target=${ZPMDB:=/var/lib/zpm/local.db}
+
+# TODO option to merge all packages found in pkgfile
+while getopts :f:vd:FSs: opt; do
+ case $opt in
+ f) pkgfile="$OPTARG" ;;
+ v) verbose=1 ;;
+ d) target="$OPTARG" ;;
+ F) mergefiles=1 ;;
+ S) mergescripts=0 ;;
+ s) newstatus="$OPTARG" ;;
+ *) echo 'zpm-merge unknown option' $OPTARG; exit 1 ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+# TODO test target
+if [ ! -e "$target" ]; then
+ die "target file $target does not exist"
+fi
+
+zpm test -v "$target" || exit 1
+
+# TODO if pkgfile is specified, allow multiple packages as args
+pkgid=$1
+shift
+
+if [ -z "$pkgid" ]; then
+ die "must specify pkgid"
+fi
+
+eval "$(zpm parse -E $pkgid)"
+
+if [ -z "$pkgfile" ]; then
+ pkgfile=$ZPM_PACKAGE_FILE
+fi
+
+# calculate package id, pkgfile, etc
+# cases R = full package id, F = specified package file
+
+# immediate error
+# --- 000 error, must specify something
+if [ -z "$release" ] && [ -z "$pkgfile" ]; then
+ die must specify package file or complete package id
+fi
+
+# try to get from package file
+if [ -z "$release" ]; then
+ pkgid=$(zpm findpkg $pkgfile $pkgid)
+ if [ -z "$pkgid" ]; then
+ die cannot find package id
+ fi
+ eval "$(zpm parse -E $pkgid)"
+fi
+
+# --F 001 error, wouldn't know which pkgid to create, could derive from file?
+if [ -z "$release" ]; then
+ die must specify complete package id
+fi
+
+# set file from pkgid
+# -R- 010 set file from pkgid, create in file, error if no file
+if [ -z "$pkgfile" ]; then
+ pkgfile="$pkgid.zpm"
+fi
+
+if [ $verbose -gt 0 ]; then
+ echo merging $pkgfile $pkgid into $target
+fi
+
+zpm test -v "$pkgfile" || exit 1
+
+merged=$(zpm shell "$target" "select 1 from packages_pkgid where pkgid = '$pkgid'")
+if [ -n "$merged" ]; then
+ die "$pkgid already exists in $target";
+fi
+
+# TODO file tags and package tags
+{
+cat <<EOS
+.bail on
+attach '$pkgfile' as remote;
+
+begin;
+
+insert or rollback into packages
+select * from remote.packages P
+where
+printf('%s-%s-%s', P.package, P.version, P.release) = '$pkgid'
+;
+
+insert or rollback into packagefiles
+select * from remote.packagefiles PF
+where
+printf('%s-%s-%s', PF.package, PF.version, PF.release) = '$pkgid'
+;
+
+insert or rollback into scripts
+select * from remote.scripts PF
+where
+printf('%s-%s-%s', PF.package, PF.version, PF.release) = '$pkgid'
+;
+EOS
+
+# actual files
+if [ $mergefiles -eq 1 ]; then
+cat<<EOS
+insert into files
+select F.* from remote.files F
+inner join remote.packagefiles_pkgid PF
+on PF.hash = F.hash
+where
+PF.pkgid = '$pkgid'
+on conflict (hash) do nothing
+;
+EOS
+fi
+
+# scripts
+# actual files
+if [ $mergescripts -eq 1 ]; then
+cat<<EOS
+insert into files
+select F.* from remote.files F
+inner join remote.scripts_pkgid PF
+on PF.hash = F.hash
+where
+PF.pkgid = '$pkgid'
+on conflict (hash) do nothing
+;
+EOS
+fi
+
+if [ -n "$newstatus" ]; then
+ newstatus=$(zpm quote "$newstatus")
+ package=$(zpm quote "$name")
+ version=$(zpm quote "$version")
+cat <<EOS
+update packages set status = '$newstatus'
+where package = '$package' and version = '$version' and release = '$release'
+;
+EOS
+fi
+
+# elf info
+
+# TODO check for adding file contents
+echo 'commit;'
+} | zpm shell $target