#!/bin/sh
#	$Id$
#	$FreeBSD: head/ports-mgmt/pkg_jail/files/pkg_update 465528 2018-03-25 16:57:38Z dinoex $
#
# Copyright (c) 2001-2018 by Dirk Meyer. All rights reserved.
#   Im Grund 4, 34317 Habichtswald, Germany
#   Email: dirk.meyer@dinoex.sub.org
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of the author nor the names of any co-contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# -------------------------------------------------------------------------
#
#

quiet_mkdir() {
	for dir in "${@}"
	do
		if test ! -d "${dir}"
		then
			mkdir "${dir}"
		fi
	done
}
#
# clean all data that is listed in mtree
# Usage: cleanmtree prefix local-temp-directory mtree-file
cleanmtree() {
	prefix="${1}"
	tmplocal="${2}"
	mkdir "${tmplocal}"
	mtree -duqn -p "${tmplocal}" -f "${3}" >> /dev/null
	find -d "${tmplocal}" -type d |
	sed "s=${tmplocal}==" |
	while read name
	do
		rmdir "${tmplocal}/${name}"
		if test -d "${prefix}/${name}"
		then
			rmdir "${prefix}/${name}"
		fi
	done
}

# fiter stdin for dirs already in pkg-plist of a port
plist_dir() {
	while read dir
	do
		dirrm="@dirrm ${dir}"
		if test -f pkg-plist
		then
			if fgrep -q -x "${dirrm}" pkg-plist
			then
				continue
			fi
			if fgrep -q -x "%%PORTDOCS%%${dirrm}" pkg-plist
			then
				continue
			fi
		fi
		echo "${dirrm}"
	done
}

# generate sed command file to reverse PLIST_SUB
plist_sub() {
	subs="${1}"
	echo "s=$(make -V PREFIX)/==g" > "${subs}"
	make -V PLIST_SUB |
	awk -F = '
END {
	for (I=0; I<COUNT; I++) {
		MAXL = 0
		MAXJ = 0
		for (J in LVAL) {
			TEST = length( LVAL[J] )
			if ( TEST > MAXL ) {
				MAXL = TEST
				MAXJ = J
			}
		}
		print "s=" LVAL[ MAXJ ] "=%%" LKEY[ MAXJ ] "%%=g"
		LVAL[MAXJ] = ""
	}
}
{
	QT = "\""
	LINE = $0
	gsub( "[ \t]$", "", LINE )
	while ( LINE != "" ) {
		gsub( "^[ \t]*", "", LINE )
		gsub( ":=", "=", LINE )
		if ( ! match( LINE, "^[A-Z][0-9A-Z_]*=" ) ) {
			print "error:" LINE
			break
		}
		KEY = substr( LINE, RSTART, RLENGTH - 1 )
		LINE = substr( LINE, RSTART + RLENGTH )
		if ( substr( LINE, 1, 1 )  == QT ) {
			LINE = substr( LINE, 2 )
			I = index( LINE, "\"" )
			VAL = substr( LINE, 1, I - 1 )
			LINE = substr( LINE, I + 1 )
		} else {
			I = index( LINE, " " )
			VAL = substr( LINE, 1, I - 1 )
			LINE = substr( LINE, I )
		}
		if ( KEY == "LIB32DIR" )
			continue
		if ( KEY == "XAWVER" )
			continue
		if ( VAL == "" )
			continue
		if ( VAL == "@comment " )
			continue
		if ( VAL == "%D" )
			continue
		gsub( "[.]", "[.]", VAL )
		LVAL[ COUNT ] = VAL
		LKEY[ COUNT ] = KEY
		COUNT++
	}
}' >> "${subs}"
}

read_env_local() {
	local_env=""
	if test -f "${fulldir}/Env.local"
	then
		echo "=== Reading ${fulldir}/Env.local"
		local_env="$(tr '\n' ' ' < "${fulldir}/Env.local")"
	fi
}

get_mflavor() {
	if test "${1}" != ""
	then
		echo "FLAVOR=${1}"
	fi
}

get_flavor_dir() {
	case "${1}" in
	*@*)
		echo "${1##*@}"
		;;
	esac
}

add_flavor() {
	if test "${1}" != ""
	then
		echo "@${1}"
	fi
}

run_pkg_add() {
	env ${pkg_env} ${local_env} ${pkg} add "${pkgfile}"
	installed="$(${pkg} query -e "%o == ${dir}" '%o')"
	if test "${installed}" = "${dir}"
	then
		return 0
	fi
	return 1
}

run_pkg_installed() {
	# more then one Flavor can be installed
	installed="$(${pkg} query -e "%o == ${dir}" '%o' | head -1)"
	if test "${installed}" = "${dir}"
	then
		echo "#installed:	${pkgname} from ${dir}"
		return 0
	fi
	return 1
}

run_pkg_match() {
	required_by="$(${pkg} info --required-by "${origin%@*}" | wc -l)"
	if test "${required_by}" -gt 1
	then
#		echo "${origin} (dependency)"
		return 0
	fi
	echo "${origin}"
	return 0
}

get_pkgfile_wd() {
	pkgfile="$(make -V PKGFILE ${1} | sed 's|\\:|:|g')"
}

get_pkgfile_dir() {
	pkgfile="$(cd "${1}" && make -V PKGFILE ${2} | sed 's|\\:|:|g')"
}

get_pkgnew() {
	pnew="$(cd "${1}" && make -V PKGFILE ${2} | sed 's|\\:|:|g')"
}

run_pkg_add_missing() {
	pkgname="$(make -V PKGNAME)"
	get_pkgfile_wd
	dir="${fulldir##${portsdir}/}"
	dir="${dir##${localdir}/}"
	installed="$(${pkg} query -e "%o == ${dir}" '%o')"
	if test "${installed}" = "${dir}"
	then
		return 1
	fi
	if test ! -e "${pkgfile}"
	then
		return 0
	fi
	if run_pkg_add
	then
		return 1
	fi
	return 0
}

run_pkg_delete() {
	pkgname="$(make -V PKGNAME)"
	${pkg} delete "${pkgname}"
}

run_pkg_delete_all() {
	installed="$(${pkg} query -e '%p == /usr/local' '%o'; ${pkg} query -e '%p == /compat/linux' '%o'; ${pkg} query -e '%p ~ /usr/local/*' '%o';)"
	if test "${installed}" = ""
	then
		return
	fi
	${pkg} delete -y -f ${installed}
	return
}

run_pkg_info_installed() {
	${pkg} query -e "%o == ${1}" '%o'
}

run_pkg_info_origin_file() {
	porigin="$(${pkg} info -q -o -F "${1}")"
	pflavor="$(${pkg} info -q --annotations -F "${1}" | grep "^flavor")"
	pflavor="${pflavor##flavor*: }"
	if test "${pflavor}" = ""
	then
		echo "${porigin}"
	else
		echo "${porigin}@${pflavor}"
	fi
}

run_pkg_info_origin_name() {
	porigin="$(${pkg} info -q -o "${1}")"
	pflavor="$(${pkg} annotate -q -S "${1}" 'flavor')"
	if test "${pflavor}" = ""
	then
		echo "${porigin}"
	else
		echo "${porigin}@${pflavor}"
	fi
}

run_pkg_info_options() {
        ${pkg} query -F "${1}" "%Ok=%Ov" | sort
}

run_pkg_info_origin_all() {
	${pkg} query -e '%a = 0' "%o" |
	while read name
	do
		run_pkg_info_origin_name "${name}"
	done
}

run_pkg_info_dependecies() {
	${pkg} info -q --dependencies -F "${1}"
}

run_pkg_info_list() {
	${pkg} info
}

run_pkg_info_requiredby() {
	${pkg} info -q -r "${1}"
}

dependency_is_good() {
	if test ! -d "${fulldir}"
	then
		echo "Directory not found: ${fulldir}"
		echo "Directory not found: ${fulldir}" >> ${tmpupdated}
		return 1
	fi
	dir="${fulldir##${portsdir}/}"
	dir="${dir##${localdir}/}"
	if test "${dir}" = ""
	then
		echo "Directory bad: ${fulldir}"
		echo "Directory bad: ${fulldir}" >> ${tmpupdated}
		return 1
	fi
	pkgname="$(cd ${fulldir} && make -V PKGNAME ${2})"
	if run_pkg_installed
	then
		return 2
	fi
	get_pkgfile_dir "${fulldir}" "${2}"
	if test -e ${pkgfile}
	then
		return 0
	fi
	noinstall="$(cd "${fulldir}" && make -V NO_INSTALL ${2})"
	case "${noinstall}" in
	yes|YES)
		return 2
		;;
	esac
	echo "# missing package: ${pkgname} from ${dir}"
	echo "# missing package: ${pkgname} from ${dir}" >> ${tmpupdated}
	return 3
}

filter_depends() {
	if test -f "${depends}"
	then
		sed -f "${depends}"
	else
		cat
	fi
}

# check dependencies and decides if a ports needs to be rebuild
# Usage: port_uptodate show
# Usage: port_uptodate make
port_uptodate() {
	tmpupdated="/tmp/port-updated.$$"
	tmpfailed="/tmp/port-failed.$$"
	mflavor="$(get_mflavor "${2}")"
	add_flavor="$(add_flavor ${2})"
	case "${1}" in
	show)
		rm -f "${logdir}/"show*
		;;
	esac
	#
	case "${1}" in
	show*|make*)
		dir="$(make -V PKGORIGIN)"
		base="${portsdir}/${dir}"
		base1="$(pwd)"
		base2="$(cd "${base}" && pwd)"
		if test ! "${base1}" = "${base2}"
		then
			echo "# WARNING: PKGORIGIN=${base2} does not match ${base1}"
			echo "# WARNING: using ${base}"
		fi
		echo "## ${base}: port_uptodate ${1} ${2}"
		pkgname="$(make -V PKGNAME ${mflavor})"
		get_pkgfile_wd ${mflavor}
		mainpkg="${pkgname}"
		for=""
		found=""
		mainpkgfile=""
		rm -f "${tmpupdated}" "${tmpfailed}"
		if run_pkg_installed
		then
			found="1"
		else
			if test -e ${pkgfile}
			then
				echo "pkg_add ${pkgfile}"
				mainpkgfile="${pkgfile}"
				found="1"
			fi
		fi
		;;
	*)
		echo "port_uptodate: bad arguments" >&2
		return 64
		;;
	esac
	#
	# creates dependency
	env ${pkg_env} make checksum ${mflavor} >&2
	#
	if test ! -e "${depends}"
	then
		# create empy list
		touch "${depends}"
	fi
	#
	for depdir_flavors in $(
		env ${pkg_env} make build-depends-list run-depends-list ${mflavor} |
		filter_depends
	)
	do
		fulldir="${depdir_flavors%@*}"
		flavor="$(get_flavor_dir "${depdir_flavors}")"
		mflavor="$(get_mflavor "${flavor}")"
		add_flavor="$(add_flavor ${flavor})"
		dir=""
		pkgname=""
		pkgfile=""
		dependency_is_good "${1}" ${mflavor}
		err="${?}"
		case "${err}" in
		0) # exist
			echo "dependency_is_good"
			log="$(echo "${dir}${add_flavor}" | sed -e 's=/=,=g')"
			case "${1}" in
			xshow*)
				if test ! -f "${logdir}/show,${log}"
				then
					# check dependend package is ok!
					( cd ${fulldir} && port_uptodate ${1}+ ${flavor} )
					touch "${logdir}/show,${log}"
				fi
				;;
			xmake*)
				if test ! -f "${logdir}/check,${log}"
				then
					# check dependend package is ok!
					( cd ${fulldir} && port_uptodate ${1}+ ${flavor} )
					touch "${logdir}/check,${log}"
					if run_pkg_installed
					then
						continue
					fi
				fi
				;;
			esac

			if test "${mainpkgfile}" != ""
			then
				if test "${pkgfile}" -nt "${mainpkgfile}"
				then
					echo "# dependend package newer: ${pkgfile} ${mainpkgfile}"
					echo "# dependend package newer: ${pkgfile} ${mainpkgfile}" >> ${tmpupdated}
				fi
			fi
			echo "#existing package:	${pkgname} from ${dir}${for}"
			echo "pkg_add ${pkgfile}"
			case "${1}" in
			make*)
				if run_pkg_add
				then
					continue
				fi
				echo "pkg_add ${pkgfile} failed, no ${pkgname}!"
				echo "=== dependend package failed to add: ${pkgfile} ${pkgname}" >&2
				echo "=== dependend package failed to add: ${pkgfile} ${pkgname}" >> ${tmpfailed}
				echo "=== dependend package failed to add: ${pkgfile} ${pkgname}" >> ${logdir}/err,${log}
				break
				;;
			esac
			continue
			;;
		1) # abort
			break
			;;
		2) # installed
			continue
			;;
		3) # missing
			log="$(echo "${dir}${add_flavor}" | sed -e 's=/=,=g')"
			case "${1}" in
			make*)
				echo "cd ${fulldir} && port_uptodate ${1}+ ${flavor}"
				( cd ${fulldir} && port_uptodate ${1}+ ${flavor} )
				if run_pkg_installed
				then
					continue
				fi
				echo "=== package ${pkgname} error dependency" >&2
				echo "=== package ${pkgname} error dependency" >> ${tmpfailed}
				echo "=== package ${pkgname} error dependency" >> ${logdir}/err,${log}
				break
				;;
			esac
			;;
		esac
	done
	pkgname="${mainpkg}"
	mflavor="$(get_mflavor "${2}")"
	add_flavor="$(add_flavor ${2})"
	if test -e "${tmpfailed}"
	then
		fulldir="$(pwd)"
		dir="${fulldir##${portsdir}/}"
		dir="${dir##${localdir}/}"
		echo "=====================================" >&2
		echo "=== package ${pkgname} missing dependency" >&2
		cat ${tmpfailed} >&2
		echo "=====================================" >&2
		if test "${dir}" != ""
		then
			log="$(echo "${dir}${add_flavor}" | sed -e 's=/=,=g')"
			cat ${tmpfailed} >> ${logdir}/err,${log}
		fi
		rm -f "${tmpfailed}" "${tmpupdated}"
		return 1
	fi
	if test "${found}" = "" -o -e "${tmpupdated}"
	then
		rm -f "${tmpupdated}"
		dir="${base##${portsdir}/}"
		dir="${dir##${localdir}/}"
		log="$(echo "${dir}${add_flavor}" | sed -e 's=/=,=g')"
		local_env=""
		if test -f "${base}/Env.local"
		then
			echo "=== Reading ${base}/Env.local"
			local_env="$(tr '\n' ' ' < "${base}/Env.local")"
		fi
		prefix="/usr/local"
		if test ! -d "${prefix}"
		then
			mkdir -p "${prefix}"
		fi
		case "${1}" in
		make*)
			if test -e "${logdir}/err,${log}"
			then
				echo "=====================================" >&2
				echo "=== package ${pkgname} had failed build" >&2
				echo "=====================================" >&2
				echo "=== package ${pkgname} had failed build" \
					>> ${logdir}/err,${log}
				return 2
			fi
			echo "cd ${base} && env ${pkg_env} ${local_env} make package ${mflavor} >> ${logdir}/err,${log} 2>&1"
			( cd "${base}" && env ${pkg_env} ${local_env} make package ${mflavor} </dev/null >> "${logdir}/err,${log}" 2>&1 )
			get_pkgfile_dir "${base}" "${mflavor}"
			if test -e "${pkgfile}"
			then
				if test -f "${logdir}/build,${log}"
				then
					mv -f "${logdir}/build,${log}" "${logdir}/last,${log}"
				fi
				( cd ${base} && env ${pkg_env} make stage-qa check-orphans check-sanity ${mflavor} </dev/null >> "${logdir}/err,${log}" 2>&1 )
				mv -f "${logdir}/err,${log}" "${logdir}/build,${log}"
				( cd ${base} && env ${pkg_env} make clean NOCLEANDEPENDS=yes ${mflavor} )
				if run_pkg_installed
				then
					return 0
				fi
				noinstall="$(cd "${base}" && make -V NO_INSTALL ${mflavor})"
				case "${noinstall}" in
				yes|YES)
					return 0
					;;
				esac
				nostage="$(cd "${base}" && make -V NO_STAGE ${mflavor})"
				case "${nostage}" in
				yes|YES)
					echo "=====================================" >&2
					echo "=== package ${pkgname} was not installed" >&2
					echo "=====================================" >&2
					echo "=== package ${pkgname} was not installed" \
						>> ${logdir}/err,${log}
					return 2
					;;
				*)
					# install staged package
					get_pkgfile_dir "${base}" "${mflavor}"
					if run_pkg_add
					then
						return 0
					fi
					echo "=====================================" >&2
					echo "=== pkg_add ${pkgfile}, no ${pkgname}!" >&2
					echo "=====================================" >&2
					echo "=== package ${pkgname} can not be installed" \
						>> ${logdir}/err,${log}
					return 2
				esac
			fi
			get_pkgfile_dir "${base}" "${mflavor}"
			if test -e "${pkgfile}"
			then
				if test -f "${logdir}/build,${log}"
				then
					mv -f "${logdir}/build,${log}" "${logdir}/last,${log}"
				fi
				mv -f "${logdir}/err,${log}" "${logdir}/build,${log}"
				( cd ${base} && env ${pkg_env} make clean NOCLEANDEPENDS=yes ${mflavor} )
				return 0
			else
				echo "=====================================" >&2
				echo "=== package ${pkgname} was not build" >&2
				echo "=====================================" >&2
				echo "=== package ${pkgname} was not build" \
					>> ${logdir}/err,${log}
				return 2
			fi
			;;
		show*)
			echo "if test ! -e \"${pkg_dbdir}/${mainpkg}/+CONTENTS\""
			echo "then"
			echo "  echo \"=====================================\" >&2"
			echo "  echo \"=== package ${pkgname} was not build\" >&2"
			echo "  echo \"=====================================\" >&2"
			echo "  exit 2"
			echo "fi"
			echo "mv -f \"${logdir}/err,${log}\" \"${logdir}/build,${log}\""
			return 1
			;;
		esac
	else
		rm -f "${tmpupdated}"
		if test "${found}" = "1"
		then
			echo "#ok"
			return 0
		fi
		echo "#not made"
		return 1
	fi
}

# make all packages to build a port in a clean jail
# Usage: make_packages_in_dir directory
make_packages_in_dir() {
	tmpshow="/tmp/check-package.$$"
	dir="${1%@*}"
	main_flavor="$(get_flavor_dir "${1}")"
	if test "${dir}" = ""
	then
		return
	fi
	if test ! -d "${dir}"
	then
		dir="${portsdir}/${dir}"
	fi
	if test -d "${dir}"
	then
		(
		echo ""
		echo "# checking: ${dir} ${main_flavor}"
		cd "${dir}" || return 69

		add_flavor="$(add_flavor ${main_flavor})"
		odir="${dir##${portsdir}/}"
		odir="${odir##${localdir}/}"
		log="$(echo "${odir}${add_flavor}" | sed -e 's=/=,=g')"
		if test -e "${logdir}/err,${log}"
		then
			echo "# skipping: err,${log}"
			return 69
		fi

		wrkdir="$(make -V WRKDIRPREFIX)"
		prefix="/usr/local"
		if ! test "${wrkdir}" = ""
		then
			rm -rf "${wrkdir}"/*
			run_pkg_delete_all
			rm -rf "${prefix}"/* "${prefix}"/.pkgtemp*
		fi

		port_uptodate show ${main_flavor} > "${tmpshow}"
		err="${?}"

		case "${err}" in
		1)
			port_uptodate make ${main_flavor}
			err="${?}"
			if test "${err}" != "0"
			then
				echo "port_uptodate: aborted!"
				return
			fi

			env ${pkg_env} make deinstall ${main_flavor}
			run_pkg_delete_all
			if test -f ${localdir}/data/badfiles
			then
				grep -v "^#" ${localdir}/data/badfiles |
				while read bad
				do
					if test -f "${bad}"
					then
						rm -f "${bad}"
					fi
					if test -L "${bad}"
					then
						rm -f "${bad}"
					fi
				done
			fi
			if test -f ${localdir}/data/baddirs
			then
				grep -v "^#" ${localdir}/data/baddirs |
				while read bad
				do
					if test -d "${bad}"
					then
						rmdir "${bad}"
					fi
				done
			fi
			plistlog="${logdir}/plist,$(make -V PKGORIGIN | sed -e 's=/=,=')${add_flavor}"
			subs="${plistlog}.sed"
			plist_sub "${subs}"
			echo -n "" > "${plistlog}"
			if test -d /root/GNUstep
			then
				find -d /root/GNUstep -type f >> "${plistlog}"
				find -d /root/GNUstep -type d |
				sed -e 's=^=@dirrm =' >> "${plistlog}"
				rm -rf /root/GNUstep
			fi
			if test -d "${prefix}"
			then
				find -d "${prefix}" -type f -or -type l |
				sort |
				sed -f "${subs}" >> "${plistlog}"
				if test -f "${portsdir}/Templates/BSD.local.dist"
				then
					cleanmtree "${prefix}" /tmp/local \
						"${portsdir}/Templates/BSD.local.dist"
				else
					cleanmtree "${prefix}" /tmp/local \
						"/etc/mtree/BSD.local.dist"
				fi
				if test -d "${prefix}"
				then
					find -d "${prefix}" -type d |
					sort -r |
					sed -f "${subs}" |
					plist_dir >> "${plistlog}"
				fi
			fi
			rm -f "${subs}"
			if test ! -s "${plistlog}"
			then
				rm -f "${plistlog}"
			fi
			;;
		esac
		rm -f "${tmpshow}"
		)
	else
		case "${dir}" in
		'')
			;;
		*nonexistent)
			;;
		*)
			echo "## dir does not exist: ${dir}"
			echo "## dir does not exist: ${dir}" \
				>> ${localdir}/make-packages.errlog
			;;
		esac
	fi
}
#
# make all packages to build and install a port to a host
# Usage: add_packages_in_dir directory
add_packages_in_dir() {
	tmpshow="/tmp/check-package.$$"
	fulldir="${1%@*}"
	main_flavor="$(get_flavor_dir "${1}")"
	if test "${fulldir}" = ""
	then
		return
	fi
	case "${fulldir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${fulldir}"
	then
		xdir="${portsdir}/${dir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${fulldir}"
			return
		fi
		fulldir="${xdir}"
	fi

	(
	echo "# checking: ${fulldir}"
	cd "${fulldir}" || return 69

	port_uptodate show ${main_flavor} > "${tmpshow}"
	err="${?}"
	case "${err}" in
	0)
		if run_pkg_add_missing
		then
			exit 1
		fi
		;;
	1)
		port_uptodate make ${main_flavor}
		;;
	esac
	rm -f "${tmpshow}"
	)
}
#
# install the existing packages from a port to a host
# Usage: install_packages_in_dir directory
install_packages_in_dir() {
	fulldir="${1%@*}"
	main_flavor="$(get_flavor_dir "${1}")"
	if test "${fulldir}" = ""
	then
		return
	fi
	case "${fulldir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${fulldir}"
	then
		xdir="${portsdir}/${fulldir}"
		if test ! -d "${xdir}"
		then
			movedto="$(get_new_origin "${fulldir}")"
			if test "${movedto}" = "nonexistent"
			then
				echo "## port removed: ${fulldir}"
				return
			fi
			if test "${movedto}" = "${dir}"
			then
				echo "## dir does not exist: ${fulldir}"
				return
			fi
			echo "## dir moved: ${dir} -> ${movedto}"
			xdir="${portsdir}/${movedto}"
			if test ! -d "${xdir}"
			then
				echo "## dir does not exist: ${movedto}"
				return
			fi
		fi
		fulldir="${xdir}"
	fi

#	echo "# checking: ${dir}"
	(
	cd "${fulldir}" || return 69
	if run_pkg_add_missing
	then
		echo "## package does not exist: ${pkgfile}"
		echo "(cd ${fulldir} && make package ${main_flavor})"
	fi
	)
}
#
# show the existing packages from a port to a host
# Usage: show_packages_in_dir directory
show_packages_in_dir() {
	fulldir="${1%@*}"
	main_flavor="$(get_flavor_dir "${1}")"
	if test "${fulldir}" = ""
	then
		return
	fi
	case "${fulldir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${fulldir}"
	then
		xdir="${portsdir}/${dir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${fulldir}"
			return
		fi
		fulldir="${xdir}"
	fi

	(
#	echo "# checking: ${fulldir}"
	cd "${fulldir}" || return 69
	if run_pkg_add_missing
	then
		echo "## package does not exist: ${pkgfile}"
		echo "(cd ${dir} && make package ${main_flavor})"
	fi
	)
}
#
# delete the existing packages on this host
# Usage: deinstall_packages_in_dir directory
deinstall_packages_in_dir() {
	fulldir="${1%%@*}"
	if test "${fulldir}" = ""
	then
		return
	fi
	case "${fulldir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${fulldir}"
	then
		xdir="${portsdir}/${fulldir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${dir}"
			return
		fi
		fulldir="${xdir}"
	fi

	(
#	echo "# checking: ${fulldir}"
	cd "${fulldir}" || return 69
	run_pkg_delete "${pkgname}"
	)
}
#
#
# show the existing packages from a port to a host
# Usage: show_missing_packages_in_dir directory
show_missing_packages_in_dir() {
	dir="${1%%@*}"
	if test "${dir}" = ""
	then
		return
	fi
	case "${dir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${dir}"
	then
		xdir="${portsdir}/${dir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${dir}"
			return
		fi
		dir="${xdir}"
	fi

	(
#	echo "# checking: ${dir}"
	cd "${dir}" || return 69
	get_pkgfile_wd
	if test -f "${pkgfile}"
	then
		return
	fi
	echo "## package does not exist: ${pkgfile}"
	echo "(cd ${dir} && make package)"
	)
}
#
# fetch the distfiles for a port
# Usage: fetch_distfiles_in_dir directory
fetch_distfiles_in_dir() {
	dir="${1%@*}"
	if test "${dir}" = ""
	then
		return
	fi
	case "${dir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${dir}"
	then
		xdir="${portsdir}/${dir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${dir}"
			return
		fi
		dir="${xdir}"
	fi

	(
	echo "# checking: ${dir}"
	cd "${dir}" || return 69

	make fetch
	)
}
#
# fetch the distfiles for a port
# Usage: fetch_recursive_distfiles_in_dir directory
fetch_recursive_distfiles_in_dir() {
	dir="${1%@*}"
	if test "${dir}" = ""
	then
		return
	fi
	case "${dir}" in
	*nonexistent)
		return
		;;
	esac
	if test ! -d "${dir}"
	then
		xdir="${portsdir}/${dir}"
		if test ! -d "${xdir}"
		then
			echo "## dir does not exist: ${dir}"
			return
		fi
		dir="${xdir}"
	fi

	(
	echo "# checking: ${dir}"
	cd "${dir}" || return 69

	make fetch-recursive
	)
}
#
#
#
move_dependent_away() {
	local incache
	grep -l -r "^${1}"'$' "${pkginfo_cache}/" |
	while read incache
	do
		file="${incache#${pkginfo_cache}/}"
		move_away "${file}"
		if test -f "${incache}"
		then
			# obsolete cache file
			rm -f "${incache}"
		fi
	done
}
#
# move outdated package int seperate dir for cleanup
# usage: move_away package
move_away() {
	if test -d "${pkgold}" -a -f "${1}"
	then
		# move it if the "Old" directory exists.
		mv -f "${1}" "${pkgold}/${1}"
		# remove old symlink
		linked="${1%${ext}}.txz"
		if test -L "${linked}"
		then
			rm -f -v "${linked}"
		fi
		file="${1##*/}"
		saved="${pkginfo_cache}/${file}"
		if test -f "${saved}"
		then
			# obsolete cache file
			rm -f "${saved}"
		fi
		move_dependent_away "${file%${ext}}"
	fi
}
#
# cache pkg_info -r
# usage: pkg_info_dependecies  package
pkg_info_dependecies()
{
	file="${1##*/}"
	saved="${pkginfo_cache}/${file}"
	if test "${saved}" -nt "${1}"
	then
		cat "${saved}"
		return
	fi
	run_pkg_info_dependecies "${1}" |
	tee "${saved}"
}

#
# make new package depends list for port
port_dependencies() {
	cd "${depdir}" && env ${pkg_env} make ${1} ${mflavor} |
	filter_depends |
	while read dorigin_flavors
	do
		dorigin="${dorigin_flavors%@*}"
		dflavor="$(get_flavor_dir "${dorigin_flavors}")"
		mflavor="$(get_mflavor "${dflavor}")"
		cd "${dorigin}" && env ${pkg_env} make -V ${2} ${mflavor}
	done |
	sort
}

#
# make new package option list
port_options() {
	cd "${depdir}" && (
		env ${pkg_env} make -V SELECTED_OPTIONS ${mflavor} |
		tr ' ' '\n' |
		sed -e 's|$|=on|'
		env ${pkg_env} make -V DESELECTED_OPTIONS ${mflavor} |
		tr ' ' '\n' |
		sed -e 's|$|=off|'
	) |
	grep -v '^=' |
	sort
}

#
# show diffs
show_diffs() {
	sfile="${pkginfo_cache}/${ptarget##*/}.slist"
	dfile="${pkginfo_cache}/${ptarget##*/}.dlist"
	echo "${1}" > "${sfile}"
	echo "${2}" > "${dfile}"
	diff -u "${sfile}" "${dfile}" | grep '^[+-][^+-]'
	rm -f "${sfile}" "${dfile}"
}

#
# check all packages in ${PACKAGES}/All/
# Usage: clean_package_all
clean_package_all() {
	(
	cd ${pkgall} || exit 69
	rm -rf "${pkginfo_cache}"
	quiet_mkdir "${pkginfo_cache}"
	for i in *
	do
		# is the package already moved away?
		if test ! -f "${i}"
		then
			continue
		fi
		# skip all symlinks
		if test -L "${i}"
		then
			continue
		fi
		case "${i}" in
		digests.${ext}|meta.${ext}|packagesite.${ext})
			continue
			;;
		esac
		# ist this package up to date?
		origin_flavors="$(run_pkg_info_origin_file "${i}")"
                origin="${origin_flavors%@*}"
                flavor="$(get_flavor_dir "${origin_flavors}")"
                mflavor="$(get_mflavor "${flavor}")"
		if test "${origin}" = ""
		then
			echo "${i}: missing origin"
			move_away ${i}
			continue
		fi
		depdir="${portsdir}/${origin}"
		if test ! -d "${depdir}"
		then
			echo "${i}: missing ports dir => ${depdir}"
			move_away ${i}
			continue
		fi
		get_pkgfile_dir "${depdir}" "${2}"
		get_pkgnew "${depdir}" "${mflavor}"
		if test "${pnew}" != "${pkgall}/${i}"
		then
			if test "${pnew}" = ""
			then
				echo "${i}: missing or defunt Makefile in ${depdir}"
			else
				echo "${i}: is obsolete => ${pnew##*/}"
			fi
			move_away ${i}
			continue
		fi
		ptarget="${pnew}"
		# 
		# check that options are still the same
		soptions="$(run_pkg_info_options "${ptarget}")"
		doptions="$(port_options)"
		if test "${soptions}" != "${doptions}"
		then
			echo "${i}: options changed"
			show_diffs "${soptions}" "${doptions}"
			move_away ${i}
			continue
		fi
		# 
		# check that the dependencies are still the same
		slist="$(run_pkg_info_dependecies "${ptarget}")"
		dlist="$(port_dependencies "run-depends-list" PKGNAME)"
		if test "${slist}" != "${dlist}"
		then
			echo "${i}: dependecies changed"
			show_diffs "${slist}" "${dlist}"
			move_away ${i}
			continue
		fi
		# 
		# check the build dependencies
		sfile="${pkginfo_cache}/${ptarget##*/}"
		echo "${slist}" > "${sfile}"
		blist="$(port_dependencies "build-depends-list" PKGFILE)"
		echo "${blist}" |
		while read pnew
		do
			if test "${pnew}" == ""
			then
				continue
			fi
			pmade="${pnew##*/}"
			if test ! -f "${pnew}"
			then
				echo "${i}: build-depend package ${pmade} missing!"
				move_away ${i}
				break
			fi
			if test "${pnew}" -nt "${ptarget}"
			then
				echo "${i}: build-depend package ${pmade} newer"
				move_away ${i}
				break
			fi
			echo "${pmade%${ext}}" >> "${sfile}"
		done
		# is the package already moved away?
		if test ! -f "${i}"
		then
			continue
		fi
		#
		# check each run depended package
		echo "${slist}" |
		while read dep
		do
			if test "${dep}" == ""
			then
				continue
			fi
			pmade="${dep}${ext}"
			if test ! -f "${pkgall}/${pmade}"
			then
				echo "${i}: run-depends package ${pmade} missing!"
				move_away ${i}
				break
			fi
			#
			# find matching port directory (origin)
			origin_flavors="$(run_pkg_info_origin_file "${pkgall}/${pmade}")"
			origin="${origin_flavors%@*}"
			flavor="$(get_flavor_dir "${origin_flavors}")"
			mflavor="$(get_mflavor "${flavor}")"
			if test "${origin}" = ""
			then
				echo "${i}: missing origin for ${pmade}"
				move_away ${i}
				break
			fi
			depdir="${portsdir}/${origin}"
			if test ! -d "${depdir}"
			then
				echo "${i}: run-depends package ${pmade} missing ports dir => ${origin}"
				move_away ${i}
				break
			fi
			get_pkgnew "${depdir}" "${mflavor}"
			if test "${pnew}" != "${pkgall}/${pmade}"
			then
				echo "${i}: run-depends package ${pmade} is obsolete => ${pnew}"
				move_away ${i}
				break
			fi
			if test "${pmade}" -nt "${ptarget}"
			then
				echo "${i}: run-depends package ${pmade} newer"
				move_away ${i}
				break
			fi
			#
			# up to date
		done
	done
	)
}
#
# check all packages in ${PACKAGES}/All/ and move if port uses openssl
# Usage: clean_package_openssl
clean_package_openssl() {
	(
	cd ${pkgall} || exit 69
	for i in *
	do
		origin_flavors="$(run_pkg_info_origin_file "${i}")"
		origin="${origin_flavors%@*}"
		flavor="$(get_flavor_dir "${origin_flavors}")"
                mflavor="$(get_mflavor "${flavor}")"
		if test "${origin}" = ""
		then
			continue
		fi
		depdir="${portsdir}/${origin}"
		if test ! -d "${depdir}"
		then
			continue
		fi
		openssl="$(cd "${depdir}" && make -V USES ${mflavor})"
		case "${openssl}" in
		*ssl*)
			echo "${i}: depends on openssl!"
			move_away ${i}
			;;
		esac
	done
	)
}
#
# check all links in ${PACKAGES}/
# Usage: clean_package_links
clean_package_links() {
	#
	# find all links
	find ${packages} -type l |
	while read link
	do
		if test -s "${link}"
		then
			#
			# it results in a real file
			continue
		fi
		#
		# remove stale link
		rm -f "${link}"
	done
}
#
# check for obsolete distfiles
# Usage: clean_distfiles
clean_distfiles() {
	tmp1="/tmp/all-distinfo"
	tmp2="/tmp/all-distfiles"
	rm -f "${tmp2}"
	find "${tmp1}" -type f -mtime +6h -exec rm -f {} \;
	if ! test -f "${tmp1}"
	then
		echo "Processing ... distinfo"
		find ${portsdir}/ -type f -name "distinfo*" -exec \
		cut -d " " -f2 "{}" ";" |
		tr -d '()' |
		sort -u > "${tmp1}"
	fi
	if ! test -f "${tmp2}"
	then
		echo "Processing ... distfiles"
		find ${distdir}/ -name go -prune -o -type f |
		grep -v "${old}/" |
		sed -e "s=${distdir}/==" |
		sort -u > "${tmp2}"
	fi
	echo "Processing ... differences"
	comm -13 "${tmp1}" "${tmp2}" |
	while read name
	do
		dir="/${name}"
		dir="${dir%/*}"
		echo "${dir}" "${name}"
		if test ! -d "${old}${dir}"
		then
			echo \
			mkdir -p "${old}${dir}"
			mkdir -p "${old}${dir}"
		fi
		if test -d "${distdir}/${name}"
		then
			continue
		fi
		if test -f "${old}/${name}"
		then
			if ! diff -qs "${distdir}/${name}" "${old}/${name}"
			then
				for i in "$(jot 99)"
				do
					if test -f "${old}/${name}.${i}"
					then
						continue
					fi
					echo \
					mv -i "${distdir}/${name}" "${old}/${name}.${i}"
					mv -i "${distdir}/${name}" "${old}/${name}.${i}"
					break
				done
				if test -f "${distdir}/${name}"
				then
					echo "ignored: ${distdir}/${name}"
				fi
				continue
			fi
			echo \
			rm -f "${distdir}/${name}"
			rm -f "${distdir}/${name}"
			continue
		fi
		echo \
		mv -i "${distdir}/${name}" "${old}/${name}"
		mv -i "${distdir}/${name}" "${old}/${name}"
	done
}
#
# Sync distfiles with a mirror
# Usage: merge_distfiles
merge_distfiles() {
	if test ! -d "${mergedistdir}"
	then
		echo "${mergedistdir}: no such Directory" >&2
		return
	fi
	find "${distdir}" -type f |
	sort > /tmp/distfiles.1
	find "${mergedistdir}" -type f |
	sed -e "s=${mergedistdir}=${distdir}=" |
	sort > /tmp/distfiles.2
	#diff -u /tmp/distfiles.2 /tmp/distfiles.1
	comm -23 /tmp/distfiles.1 /tmp/distfiles.2 |
	while read name
	do
		dir="${name%/*}"
		xfile="${name##*/}"
		dir="${dir#${distdir}}"
		if test -f "${mergedistdir}/${dir}${xfile}"
		then
			continue
		fi
		case "${dir}" in
		/Old/*)
			echo "${mergedistdir}${dir#/Old}${xfile}"
			if test -f "${mergedistdir}${dir#/Old}${xfile}"
			then
				continue
			fi
			;;
		*)
			echo "${mergedistdir}/Old${dir}${xfile}"
			if test -f "${mergedistdir}/Old${dir}${xfile}"
			then
				continue
			fi
			;;
		esac
		if test ! -d "${mergedistdir}${dir}"
		then
			echo \
			mkdir -p "${mergedistdir}${dir}"
			mkdir -p "${mergedistdir}${dir}"
		fi
		echo \
		cp -pi "${name}" "${mergedistdir}${dir}/"
		cp -pi "${name}" "${mergedistdir}${dir}/"
	done
}
#
# update origin ins installed package when ports has been moved
# Usage: update_origin installed origin
update_origin() {
	installed="${1}"
	origin="${2}"
	echo "${installed} ${origin}"
	if ! fgrep -q "${origin}|" "${portsdir}/MOVED"
	then
		fgrep "${origin}" "${cache}"
		return
	fi
	movedto="$(fgrep "${origin}|" "${portsdir}/MOVED" |
		tail -1 |
		cut -d "|" -f2)"
	if test "${origin}" = "${movedto}"
	then
		return
	fi
	echo "Updating: ${origin} -> ${movedto}"
	${pkg} set -o "${origin}:${movedto}"
}
#
# write new package state
make_version_list() {
	if test ! -s "${cache}"
	then
		echo "pkg_version -v -L ="
		${pkg} version -v -L = | grep -v bsdpan- > "${cache}"
	fi
}
#
# update origin ins installed package when ports has been moved
# Usage: fix_moved_ports
fix_moved_ports() {
	make_version_list
	if grep -q "orphaned" "${cache}"
	then
		grep "orphaned" "${cache}" |
		while read installed flag status origin
		do
			update_origin "${installed}" "${origin}"
		done
	fi
	if egrep -q "Comparison failed" "${cache}"
	then
		egrep "Comparison failed" "${cache}" |
		while read installed flag status failed
		do
			origin="$(run_pkg_info_origin_name "${installed}")"
			if test "${origin}" = ""
			then
				continue
			fi
			update_origin "${installed}" "${origin}"
		done
	fi
}
#
# check recursive for deinstall
delete_dependent_package() {
	local installed
	installed="${1}"
	run_pkg_info_requiredby "${installed}" |
	while read requiredby
	do
		delete_dependent_package "${requiredby}"
	done
	seenflag="${seen}/${installed}"
	if test -e "${seenflag}"
	then
		return
	fi
	origin="$(run_pkg_info_origin_name "${installed}")"
	echo "pkg delete ${installed}"
	add_to_file "${todolist}" "${origin}" quiet
	touch "${seenflag}"
}
#
# generate orderd list to deinstall all old packages on a host
make_deinstall_list() {
	quiet_mkdir "${seen}"
	rm -f "${seen}/"*
	(
		echo "#!/bin/sh"
		cat "${cache}" |
		while read installed flag status origin
		do
			case "${flag}" in
			'<')
				delete_dependent_package "${installed}"
				;;
			esac
		done
	) > "${deinstall}"
	rm -f "${seen}/"*
}
#
# remove_from_file file line quiet
remove_from_file( ) {
	edit="${1}"
	pattern="${2}"
	if test ! -e "${edit}"
	then
		return
	fi
	if test "$(fgrep -x "${pattern}" "${edit}" | wc -l)" -ge 1
	then
		if test "${quiet}" = ""
		then
			echo "remove: ${pattern} from ${edit}"
		fi
		cp -p "${edit}" "${edit}.bak"
		fgrep -v -x "${pattern}" "${edit}.bak" > "${edit}"
		rm -f "${edit}.bak"
	fi
}
#
# add_to_file file line quiet
add_to_file( ) {
	edit="${1}"
	pattern="${2}"
	if test -e "${edit}"
	then
		if test "$(fgrep -x "${pattern}" "${edit}" | wc -l)" -gt 1
		then
			remove_from_file "${edit}" "${pattern}"
		fi
	else
		touch "${edit}"
	fi
	if ! fgrep -q -x "${pattern}" "${edit}"
	then
		if test "${quiet}" = ""
		then
			echo "register: ${pattern} in ${edit}"
		fi
		echo "${pattern}" >> "${edit}"
	fi
}
#
# get_moved_origin origin
get_new_origin() {
	local origin
	origin="${1}"
	if test -d "${portsdir}/${origin}"
	then
		echo "${origin}"
		return
	fi
	movedto="$(fgrep "${origin}|" "${portsdir}/MOVED" |
		tail -1 |
		cut -d "|" -f2)"
	if test "${movedto}" = ""
	then
		echo "nonexistent"
		return
	fi
	echo "${movedto}"
}
#
# parse_default $#
#	global: defaultdata
#	global: target
parse_default() {
	if test "${1}" -lt 1
	then
		if test ! -f "${defaultdata}"
		then
			usage
		fi
		exec /bin/sh "${0}" "${target}" "${defaultdata}"
		echo "error in path: ${0}" >&2
		exit 64
	fi
}
#
next_target() {
	if test "${#}" -lt 2
	then
		return
	fi
	shift
	exec /bin/sh "${0}" "${@}"
}
#
# update pkg tools
update_pkg() {
	if test -f "${pkg}"
	then
		${pkg} delete -y -a -f
		env "PKG_DBDIR=/var/db/pkgng" ${pkg} delete -y -a -f
	fi
	/etc/rc.d/ldconfig start
	( cd "${portsdir}/ports-mgmt/pkg" && env "FORCE_PKG_REGISTER=yes" "PKG_DBDIR=/var/db/pkgng" make clean deinstall PREFIX=/usr/pkgng PKGNAMESUFFIX=-pkgng package install )
	if test ! -L /usr/sbin/pkg
	then
		mv -f /usr/sbin/pkg /usr/sbin/pkg.orig
		ln -s "${pkg}" /usr/sbin/pkg
	fi
	( cd "${portsdir}/ports-mgmt/pkg" && env "FORCE_PKG_REGISTER=yes" make clean package install )
	${pkg} delete -y -f pkg
}
#
#
# update if pkg tools have changed
check_update_pkg() {
	defaultdata="${localdir}/data/make-packages.${hostname}"
	if test ! -f "${defaultdata}"
	then
		return
	fi
	if test -f "${pkg}"
	then
		old="$(env "PKG_DBDIR=/var/db/pkgng" ${pkg} query -e '%p == /usr/pkgng' %n-%v)"
		pkgname="$(cd "${portsdir}/ports-mgmt/pkg" && make PKGNAMESUFFIX=-pkgng -V PKGNAME)"
		if test "${old}" = "${pkgname}"
		then
			if test ! -L /usr/sbin/pkg
			then
				mv -f /usr/sbin/pkg /usr/sbin/pkg.orig
				ln -s "${pkg}" /usr/sbin/pkg
			fi
			return
		fi
		ext="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V PKG_SUFX)"
		pkgfile="${portsdir}/All/${pkgname}${ext}"
		if test -f "${pkgfile}"
		then
			env "PKG_DBDIR=/var/db/pkgng" ${pkg} add "${pkgfile}"
			if test ! -L /usr/sbin/pkg
			then
				mv -f /usr/sbin/pkg /usr/sbin/pkg.orig
				ln -s "${pkg}" /usr/sbin/pkg
			fi
			return
		fi
		pkgfile="${portsdir}/Old/${pkgname}${ext}"
		if test -f "${pkgfile}"
		then
			env "PKG_DBDIR=/var/db/pkgng" ${pkg} add "${pkgfile}"
			if test ! -L /usr/sbin/pkg
			then
				mv -f /usr/sbin/pkg /usr/sbin/pkg.orig
				ln -s "${pkg}" /usr/sbin/pkg
			fi
			return
		fi
	fi
	update_pkg
}
#
# check if we run in build jail
check_buildjail() {
	defaultdata="${localdir}/data/make-packages.${hostname}"
	if test ! -f "${defaultdata}"
	then
		echo "${defaultdata}: no such file, aborted." >&2
		echo "!!WARNNING!! Such a file should only exist for your build jail" >&2
		echo "!!WARNNING!! This will uninstall all packages." >&2
		echo "!!WARNNING!! This will delete your config in /usr/local." >&2
		exit 64
	fi
}
#
# gitup.conf needs to fixed
gitup_conf() {
	sed -i '' -e 's|"ignores"          : \[\],|"ignores"          : \[ "/distfiles", "/packages", "/local", "/current", \],|' '/usr/local/etc/gitup.conf'
}
#
# check that gitup is installed when needed
check_gitup() {
	if test ! -e "${portsdir}/.gituprevision"
	then
		# not needed
		return
	fi
	if test -e /usr/local/bin/gitup
	then
		# installed
		gitup_conf
		return
	fi
	get_pkgfile_dir "${portsdir}/net/gitup"
	git_pkgfile="${pkgfile}"
	if ! test -e "${pkgfile}"
	then
		make_packages_in_dir "net/gitup"
	fi
	if test -e "${git_pkgfile}"
	then
		# try up to date package
		env ${pkg_env} ${local_env} ${pkg} add "${git_pkgfile}"
		gitup_conf
		return
	fi
	echo "Failed to install gitup" >&2
}
#
# check that git is installed when needed
check_git() {
	if test ! -e "${portsdir}/.git"
	then
		# not needed
		return
	fi
	if test -e /usr/local/bin/git
	then
		# installed
		return
	fi
	get_pkgfile_dir "${portsdir}/devel/git" "FLAVOR=tiny"
	git_pkgfile="${pkgfile}"
	if ! test -e "${pkgfile}"
	then
		make_packages_in_dir "devel/git@tiny"
	fi
	if test -e "${git_pkgfile}"
	then
		# try up to date package
		env ${pkg_env} ${local_env} ${pkg} add "${git_pkgfile}"
		return
	fi
	echo "Failed to install git" >&2
}
#
# check that portsnap is installed when needed
check_portsnap() {
	if test ! -e "${portsdir}/.portsnap.INDEX"
	then
		# not needed
		return
	fi
	if test -e /usr/sbin/portsnap
	then
		# present in base
		return
	fi
	get_pkgfile_dir "${portsdir}/ports-mgmt/portsnap"
	if ! test -e "${pkgfile}"
	then
		make_packages_in_dir "ports-mgmt/portsnap"
	fi
	if test -e "${pkgfile}"
	then
		# try up to date package
		env ${pkg_env} ${local_env} ${pkg} add "${pkgfile}"
		return
	fi
	echo "Failed to install portsnap" >&2
	return
}
#
# inform usage
usage() {
	echo "Usage:" >&2
	echo "    ${0##*/} update-pkg" >&2
	echo "    ${0##*/} repo" >&2
	echo "    ${0##*/} make-packages [port] [...]" >&2
	echo "    ${0##*/} add-packages [port] [...]" >&2
	echo "    ${0##*/} install-packages [port] [...]" >&2
	echo "    ${0##*/} show-packages [port] [...]" >&2
	echo "    ${0##*/} show-missing-packages [port] [...]" >&2
	echo "    ${0##*/} clean-packages ..." >&2
	echo "    ${0##*/} clean-openssl-packages ..." >&2
	echo "    ${0##*/} clean-distfiles ..." >&2
	echo "    ${0##*/} merge-distfiles ..." >&2
	echo "    ${0##*/} fetch-distfiles [port] [...]" >&2
	echo "    ${0##*/} fetch-recursive-distfiles [port] [...]" >&2
	echo "    ${0##*/} fix-moved-ports ..." >&2
	echo "    ${0##*/} list-installed-ports" >&2
	echo "    ${0##*/} make-version-list ..." >&2
	echo "    ${0##*/} show-version-list ..." >&2
	echo "    ${0##*/} make-deinstall-list ..." >&2
	echo "    ${0##*/} show-missing-reinstall" >&2
	echo "    ${0##*/} show-missing-installed" >&2
	echo "    ${0##*/} check-reinstall" >&2
	echo "    ${0##*/} reinstall" >&2
	echo "    ${0##*/} clean-reinstall" >&2
	echo "    ${0##*/} clean ..." >&2
	echo "    ${0##*/} check-installed-ports [port]" >&2
	echo "    ${0##*/} update-ports ..." >&2
	echo "    ${0##*/} update-jail ..." >&2
	echo "    ${0##*/} full-update-jail [retry] ..." >&2
	echo "    ${0##*/} check-update ..." >&2
	exit 64
}
#
# check empty call
if test $# -lt 1
then
	usage
fi
#
USE_PACKAGE_DEPENDS="yes"
DEPENDS_SHOW_FLAVOR="yes"
DEPENDS_TARGET="package install"
export USE_PACKAGE_DEPENDS
export DEPENDS_SHOW_FLAVOR
export DEPENDS_TARGET
hostnames="$(hostname -s)"
localdir="${PKG_UPDATE_DIR:-/usr/ports/local/update}"
logdir="${PKG_UPDATE_LOGDIR:-${localdir}/log-${hostnames}}"
hostname="$(hostname)"
depends="${localdir}/data/depends.${hostname}"
cache="${localdir}/version-list.${hostname}"
deinstall="${localdir}/deinstall.${hostname}"
todolist="${localdir}/data/todo.${hostname}"
seen="/tmp/deinstall-seen"
required="/tmp/required-seen"
inrequired="/tmp/inrequired-seen"
pkginfo_cache="/var/tmp/pkginfo_cache"
#
#	get all path information from /etc/make.conf
nowarn="COMMENT=0 CATEGORIES=0 PORTVERSION=0"
portsdir="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V PORTSDIR)"
pkg_dbdir="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V PKG_DBDIR)"
packages="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V PACKAGES | sed 's|\\:|:|g')"
defaultdata="${localdir}/data/make-packages.${hostname}"
if test -f "${defaultdata}"
then
	pkg_prefix="/usr/pkgng"
else
	pkg_prefix="/usr/local"
fi
pkg="${pkg_prefix}/sbin/pkg-static"
pkg_env="PKG_DEPENDS= PKG_PREFIX=${pkg_prefix} PKG_BIN=${pkg} PKG_TRIGGERS_DIR=/usr/local/share/pkg/triggers"
#
target="${1}"
case "${target}" in
update-pkg)
	check_buildjail
	update_pkg
	;;
repo)
	mv "${packages}/Old" "${packages}-Old"
	# cleanup leftover repo files
	rm -fv "${packages}/packagesite.yaml" "${packages}/digests"
	packages2=$(realpath "${packages}")
	${pkg} repo "${packages2}"
	mv "${packages}-Old" "${packages}/Old"
	next_target "${@}"
	;;
status)
	if test -s ${localdir}/make-packages.errlog
	then
		tail -10 ${localdir}/make-packages.errlog
	fi
	if test -d "${logdir}"
	then
		ls -tlr "${logdir}/"err,* | tail -20
	fi
	next_target "${@}"
	;;
make-packages)
	shift
	check_buildjail
	check_update_pkg
	parse_default "${#}"
	quiet_mkdir "${localdir}/data" "${logdir}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				make_packages_in_dir "${dir}"
			done
		else
			make_packages_in_dir "${i}"
		fi
	done
	/bin/sh "${0}" repo status
	;;
add-packages)
	shift
	defaultdata="${localdir}/data/install-packages.${hostname}"
	parse_default "${#}"
	quiet_mkdir "${localdir}/data" "${logdir}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				add_packages_in_dir "${dir}"
			done
		else
			add_packages_in_dir "${i}"
		fi
	done
	;;
install-packages)
	shift
	defaultdata="${localdir}/data/install-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				install_packages_in_dir "${dir}"
			done
		else
			install_packages_in_dir "${i}"
		fi
	done
	;;
show-packages)
	shift
	defaultdata="${localdir}/data/install-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				show_packages_in_dir "${dir}"
			done
		else
			show_packages_in_dir "${i}"
		fi
	done
	;;
deinstall-packages)
	shift
	defaultdata="${localdir}/data/install-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				deinstall_packages_in_dir "${dir}"
			done
		else
			deinstall_packages_in_dir "${i}"
		fi
	done
	;;
show-missing-packages)
	shift
	defaultdata="${localdir}/data/install-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				show_missing_packages_in_dir "${dir}"
			done
		else
			show_missing_packages_in_dir "${i}"
		fi
	done
	;;
fetch-distfiles)
	shift
	defaultdata="${localdir}/data/make-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				fetch_distfiles_in_dir "${dir}"
			done
		else
			fetch_distfiles_in_dir "${i}"
		fi
	done
	;;
fetch-recursive-distfiles)
	shift
	defaultdata="${localdir}/data/make-packages.${hostname}"
	parse_default "${#}"
	for i in "${@}"
	do
		if test -f "${i}"
		then
			for dir in $(grep -v "^#" "${i}")
			do
				fetch_recursive_distfiles_in_dir "${dir}"
			done
		else
			fetch_recursive_distfiles_in_dir "${i}"
		fi
	done
	;;
clean-packages)
	ext="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V PKG_SUFX)"
	pkgall="${packages}/All"
	pkgold="${packages}/Old"
	quiet_mkdir "${pkgold}"
	check_update_pkg
	#
	# save pwd
	(
		clean_package_all
		clean_package_links
	)
	/bin/sh "${0}" repo
	next_target "${@}"
	;;
clean-openssl-packages)
	pkgall="${packages}/All"
	pkgold="${packages}/Old"
	quiet_mkdir "${pkgold}"
	check_update_pkg
	#
	# save pwd
	(
		clean_package_openssl
		clean_package_links
	)
	/bin/sh "${0}" repo
	next_target "${@}"
	;;
clean-distfiles)
	distdir="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V DISTDIR)"
	old="${distdir}/Old"
	quiet_mkdir "${old}"
	#
	clean_distfiles
	next_target "${@}"
	;;
merge-distfiles)
	distdir="$(make -f /usr/share/mk/bsd.port.mk ${nowarn} -V DISTDIR)"
	mergedistdir="${MERGEDISTDIR-/media/distfiles}"
	old="${distdir}/Old"
	#
	merge_distfiles
	next_target "${@}"
	;;
fix-moved-ports)
	fix_moved_ports
	next_target "${@}"
	;;
list-installed-ports)
	run_pkg_info_origin_all
	next_target "${@}"
	;;
show-version-list)
	make_version_list
	cat "${cache}"
	next_target "${@}"
	;;
make-version-list)
	rm -f "${cache}"
	make_version_list
	next_target "${@}"
	;;
make-deinstall-list)
	make_version_list
	quiet="1"
	make_deinstall_list
	next_target "${@}"
	;;
show-missing-reinstall)
	grep -v '^#' "${todolist}" |
	while read origin dummy
	do
		movedto="$(get_new_origin "${origin}")"
		if test ! -d "${portsdir}/${movedto}"
		then
			echo "error   ${package} has lost portsdir ${movedto}"
			continue
		fi
		get_pkgfile_dir "${portsdir}/${movedto}"
		if test ! -f "${pkgfile}"
		then
			echo "	${movedto} no new package"
			continue
		fi
		pkgname="$(cd "${portsdir}/${movedto}" && make -V PKGNAME)"
		if test -d "${pkg_dbdir}/${pkgname}"
		then
			echo "new     ${pkgname} installed"
			continue
		fi
		installed="$(run_pkg_info_installed "${origin}")"
		if test "${installed}" != ""
		then
			echo "old     ${origin} installed"
			continue
		fi
		installed="$(run_pkg_info_installed "${movedto}")"
		if test "${installed}" != ""
		then
			echo "old     ${movedto} installed"
			continue
		fi
		echo "	${movedto} package not installed"
	done
	;;
check-reinstall)
	grep -v '^#' "${todolist}" |
	while read origin dummy
	do
		movedto="$(get_new_origin "${origin}")"
		if test ! -d "${portsdir}/${movedto}"
		then
			echo "error   ${package} has lost portsdir ${movedto}"
			continue
		fi
		get_pkgfile_dir "${portsdir}/${movedto}"
		if test ! -f "${pkgfile}"
		then
			echo "	${movedto} no new package"
			continue
		fi
	done
	;;
clean-reinstall)
	quiet="1"
	grep -v '^#' "${todolist}" |
	while read origin dummy
	do
		movedto="$(get_new_origin "${origin}")"
		if test ! -d "${portsdir}/${movedto}"
		then
			echo "error   ${origin} has lost portsdir ${movedto}"
			continue
		fi
		pkgname="$(cd "${portsdir}/${movedto}" && make -V PKGNAME)"
		if test -d "${pkg_dbdir}/${pkgname}"
		then
			remove_from_file "${todolist}" "${origin}"
			continue
		fi
		installed="$(run_pkg_info_installed "${origin}")"
		if test "${installed}" != ""
		then
			remove_from_file "${todolist}" "${origin}"
			continue
		fi
		get_pkgfile_dir "${portsdir}/${movedto}"
		if test ! -f "${pkgfile}"
		then
			echo "	${movedto} no new package"
			continue
		fi
		echo "	${origin} package not installed"
	done
	;;
show-missing-installed)
	env ${pkg_env} ${local_env} pkg version -qo -Rl '?'
	;;
reinstall)
	exec /bin/sh "${0}" install-packages "${todolist}"
	echo "error in path: ${0}" >&2
	exit 64
	;;
clean)
	rm -f "${cache}" "${deinstall}"
	next_target "${@}"
	;;
check-installed-ports)
	shift
	tmp1="/tmp/check-listed.$$"
	tmp2="/tmp/check-installed.$$"
	quiet_mkdir "${localdir}/data"
	defaultdata="${localdir}/data/install-packages.${hostname}"
	if test ! -f "${defaultdata}"
	then
		/bin/sh "${0}" "list-installed-ports" | sort > "${defaultdata}"
	fi
	parse_default "${#}"
	(
		for i in "${@}"
		do
			if test -f "${i}"
			then
				grep -v "^#" "${i}"
			else
				echo "${i}"
			fi
		done
	) |
	sed -e 's=^/usr/ports/==' |
	sort -u > "${tmp1}"
	run_pkg_info_origin_all |
	sort -u > "${tmp2}"
	obsolete="$(comm -23 "${tmp1}" "${tmp2}")"
	if test "${obsolete}" != ""
	then
		echo "#    not installed, but listed:"
		echo "${obsolete}" |
		while read origin
		do
			origindir="${portsdir}/${origin%@*}"
			if test ! -d "${origindir}"
			then
				echo "${origin} (no origin)"
				continue
			fi
			echo "${origin}"
		done
		echo ""
	fi
	obsolete="$(comm -13 "${tmp1}" "${tmp2}")"
	if test "${obsolete}" != ""
	then
		echo "#    installed, but not listed:"
		echo "${obsolete}" |
		while read origin
		do
			origindir="${portsdir}/${origin%@*}"
			if test ! -d "${origindir}"
			then
				echo "${origin} (no origin)"
				continue
			fi
			flavor="$(get_flavor_dir "${origin}")"
			mflavor="$(get_mflavor "${flavor}")"
			pkgname="$(cd "${origindir}" && make -V PKGNAME ${mflavor} 2>/dev/null)"
			run_pkg_match
		done
		echo ""
	fi
	rm -f "${tmp1}" "${tmp2}"
	;;
check-gitup)
	check_gitup
	;;
update-ports)
	check_gitup
	check_git
	check_portsnap
	if test -e "${portsdir}/.gituprevision"
	then
		gitup ports
	else
		(cd ${portsdir} && make update)
	fi
	next_target "${@}"
	;;
update-jail)
	cd ${localdir} || exit 69
	defaultdata="${localdir}/data/make-packages.${hostname}"
	#
	/bin/sh "${0}" clean-packages
	rm -f "${logdir}/"err,*
	/bin/sh "${0}" make-packages
	next_target "${@}"
	;;
full-update-jail)
	cd ${localdir} || exit 69
	defaultdata="${localdir}/data/make-packages.${hostname}"
	#
	case "${2}" in
	retry)
		shift
		;;
	*)
		/bin/sh "${0}" update-ports
		;;
	esac
	/bin/sh "${0}" clean-distfiles
	/bin/sh "${0}" clean-packages
	rm -f "${logdir}/"err,*
	/bin/sh "${0}" make-packages
	next_target "${@}"
	;;
check-update)
	/bin/sh "${0}" check-installed-ports
	/bin/sh "${0}" show-missing-packages
	/bin/sh "${0}" show-missing-installed
	next_target "${@}"
	;;
*)
	usage
esac
#
exit 0
#
# eof
