#!/bin/sh -e
# ==================================================================================
# portsreinstall main script
# Copyright (C) 2010-2013 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
# This software is distributed under the 2-Clause BSD License.
# ==================================================================================

# ==================================================
# ================== ENVIRONMENT ===================
# ==================================================

# ============ Set up of environment =============
APPNAME=`basename "$0"`

MYVERSION=3.0.2
COMPATIBLE_VERSIONS='^(3\.0\.[0-9]+)$'
# Template for development versions
# MYVERSION=3.0.2+toward_3.0.3_20130710063939
# COMPATIBLE_VERSIONS='^(3\.0\.[0-9]+\+toward_3\.0\.1_[0-9]+|3\.0\.[0-9]+)$'
MYPREFIX=`dirname "\`dirname \"$0\"\`" | sed 's|/bin$||'`
MYPREFIX=${MYPREFIX:-/usr/local}
LIBDIR=${MYPREFIX}/lib/${APPNAME}

. ${LIBDIR}/libtemp.sh
. ${LIBDIR}/libstr.sh
. ${LIBDIR}/liboptions.sh
. ${LIBDIR}/libusage.sh
. ${LIBDIR}/libmessage.sh
. ${LIBDIR}/libpkgsys.sh
. ${LIBDIR}/libmisc.sh
. ${LIBDIR}/libfileedit.sh
. ${LIBDIR}/libconf.sh
. ${LIBDIR}/libdatabase_build.sh
. ${LIBDIR}/libdatabase_query.sh
. ${LIBDIR}/libdatabase_record.sh
. ${LIBDIR}/libcommand.sh
. ${LIBDIR}/libprogram.sh
. ${LIBDIR}/libreinstall.sh
. ${LIBDIR}/libdeinstall.sh

misc_init_vardefs
temp_trap_init
conf_setup_envs
DBDIR=/var/tmp/${APPNAME}.db
CONFFILE=${MYPREFIX}/etc/${APPNAME}.conf
PKGTOOLSCONF=${MYPREFIX}/etc/pkgtools.conf


# ==================================================
# ========= PARSING OPTIONS AND ARGUMENTS ==========
# ==================================================

# ============= Save arguments for upgraded restart =============
options_dump_args "$@" > ${TMPDIR}/restart_command.sh

# ============= Option check =============
options_set_default

options_getopts "$@" || :
if [ $OPTIONS_ERRNO -eq 2 ]
then
	message_echo "INTERNAL ERROR: In parsing options" >&2
	exit 1
fi
shift "${OPTIONS_SHIFT}"

# ============= Argument check for no-command options =============
if [ $opt_help_mode -ne 0 -o $opt_show_version = yes ]
then
	if [ $# -gt 0 ]
	then
		OPTIONS_ERRNO=1
	fi
fi

# ============= Output usage if the case of a help mode or option/argument errors =============
if [ $OPTIONS_ERRNO -ne 0 ]
then
	exit $OPTIONS_ERRNO
elif [ $opt_help_mode -eq 1 ]
then
	usage_short
	exit
elif [ $opt_help_mode -eq 2 ]
then
	usage_long | less
	exit
fi

# ============= Output version number =============
if [ $opt_show_version = yes ]
then
	message_version
	exit
fi

# ============= Execute command operations before getting the temporary database ready =============
command_exec_before_db_creation "$@"

# ============= Creation of temporary database directory =============
database_build_create

# ============= Argument check for conventional runs =============
command_parse_args "$@"
shift "${COMMAND_SHIFT}"


# ==================================================
# ================== TOOLS SET UP ==================
# ==================================================

# ============= Opening title =============

message_credit
[ $COMMAND_MODE = do -o $COMMAND_MODE = redo -o $COMMAND_MODE = forget ] && \
	message_opening_notice
message_echo

# ============= Execute command operations which do not need package tools =============

command_exec_without_pkgtools "$@"
misc_is_superuser_privilege && touch "${DBDIR}/in_use"

# ============= Definition of environment dependent functions =============

pkgsys_def_pkgtools

# ============= Option settings =============

# Execute command operations which are not affected by saved option settings
command_exec_irrespective_of_saved_options "$@"

# Load, renew and save option values
optcomb_err=0
options_chk_invalid_optvals_renewal non_renewable || optcomb_err=$?
if [ \( $opt_reload_conf = yes -o $opt_reset_targets = yes \) -a "x$COMMAND_MODE" != xredo ]
then
	message_echo "ERROR: Option -N is available only in the initial run of redo command." >&2
	message_echo >&2
	optcomb_err=1
fi
if [ $opt_batch_ports_only = yes -a $opt_interactive_ports_only = yes ]
then
	message_echo "ERROR: Options -A and -I conflict with each other." >&2
	message_echo >&2
	optcomb_err=1
fi
if [ -e "${DBDIR}/saved_options.sh" ]
then
	{
		options_renewed_optvals M renewable_anytime || optcomb_err=$?
		options_renewed_optvals N renewable_in_redo_on_target || optcomb_err=$?
		options_renewed_optvals L renewable_in_redo_on_conf || optcomb_err=$?
	} > ${TMPDIR}/renewed_optvals.sh
	[ $optcomb_err -eq 0 ] || exit $optcomb_err
	. "${DBDIR}/saved_options.sh"
	. "${TMPDIR}/renewed_optvals.sh"
fi
misc_is_superuser_privilege && misc_get_all_vardefs | options_filter saved > ${DBDIR}/saved_options.sh

# Show option values
if [ -e "${DBDIR}/saved_options.sh" -a $opt_batch_mode = no \
	-a \( $COMMAND_MODE = do -o $COMMAND_MODE = redo \) ]
then
	message_echo "INFO: List of option values:"
	message_echo "-----------------------------------------"
	message_cat "${DBDIR}/saved_options.sh"
	message_echo "-----------------------------------------"
	message_echo
fi

# ============= Termination messages during construction of the temporary database =============

# Set termination messages
temp_terminate_process_common ()
{
	local msg_where
	[ $opt_batch_mode = yes ] && return
	msg_where=`temp_get_msg_current_stage`
	[ -n "$msg_where" ] && msg_where=" during $msg_where"
	echo
	if [ $errno -eq 130 ]
	then
		echo "INFO: Terminated at `message_timestamp`$msg_where."
		echo
		echo " You can restart this process from the terminated point by"
	else
		echo "INFO: Aborted at `message_timestamp`$msg_where."
		echo
		echo " You may restart this process from the aborted point by"
	fi
	echo "executing without options or arguments as:"
	if [ -n "$COMMAND_RESTART" ]
	then
		echo "  ${APPNAME} $COMMAND_RESTART"
	else
		echo "  ${APPNAME}"
	fi
}

temp_terminate_process ()
{
	[ $errno -eq 0 -o $opt_batch_mode = yes ] && return
	temp_terminate_process_common
	[ -n "$COMMAND_RESTART" ] || message_cat 3<< eof
 Instead, if you only want to construct the temporary database so as to stop before the actual reinstallation, execute as:
  ${APPNAME} prepare
eof
}

# ============= Configurations =============

# Save the previous configuration if exists
PROGRAM_DEPENDS=''
_program_exec_and_record_completion__operation ()
{
	rm -rf "${DBDIR}/conf.prev"
	[ -d "${DBDIR}/conf" ] && \
		cp -Rp "${DBDIR}/conf" "${DBDIR}/conf.prev"
	:
}
program_exec_and_record_completion SAVE_PREV_CONF

# Get complete configuration variable definitions by importing pkgtools.conf(5) if available
PROGRAM_DEPENDS='SAVE_PREV_CONF'
_program_exec_and_record_completion__operation ()
{
	local need_msg
	need_msg=no
	rm -rf "${DBDIR}/conf"
	mkdir -p "${DBDIR}/conf"
	[ "x`options_get_effective_opt_load_pkgtoolsconf`" != xno -a $opt_batch_mode = no ] \
		&& need_msg=yes
	[ $need_msg = yes ] && \
		message_section_title "Parsing pkgtools.conf (by using installed portupgrade)"
	conf_get_complete_var_defs > ${DBDIR}/conf/complete_setup.sh
	[ $need_msg = yes ] &&  { message_echo "===> ok"; message_echo; }
	:
}
program_exec_and_record_completion GET_COMPLETE_CONF_VAR_DEF

# Parse the configuration
PROGRAM_DEPENDS='GET_COMPLETE_CONF_VAR_DEF'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Parsing the configuration"
	conf_manipulate_available_var_defs
	. "${DBDIR}/conf/manipulated_defs.sh"
	# ALT_MOVED_*
	conf_build_effective_MOVED
	# Environmental variables
	conf_setup_effective_env > ${DBDIR}/conf/setenv.sh
	. "${DBDIR}/conf/setenv.sh"
	# HOLD_*
	conf_parse_vars_for_each_port_glob HOLD
	str_escape_regexp_filter < ${DBDIR}/conf/HOLD:PORTS.parsed \
		| sed 's/^/^/;s/$/$/' > ${DBDIR}/conf/HOLD_PORTS.grep_pattern
	# TABOO_*
	conf_parse_vars_for_each_port_glob TABOO
	fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" \
		> ${DBDIR}/taboo.all.list
	# NOPKG_*
	conf_parse_vars_for_each_port_glob NOPKG
	# REPLACE_*
	conf_build_replacement_patterns_from_REPLACE
	# MARG_*
	conf_parse_vars_for_each_port_glob_with_bound_val MARG TARGET DEF
	# MENV_*
	conf_parse_vars_for_each_port_glob_with_bound_val MENV TARGET DEF
	# BEFOREBUILD_*
	conf_parse_vars_for_each_port_glob_with_bound_val BEFOREBUILD TARGET COMMAND
	# BEFOREDEINSTALL_*
	conf_parse_vars_for_each_port_glob_with_bound_val BEFOREDEINSTALL TARGET COMMAND
	# AFTERINSTALL_*
	conf_parse_vars_for_each_port_glob_with_bound_val AFTERINSTALL TARGET COMMAND
	message_echo
}
program_exec_and_record_completion PARSE_CONF

. "${DBDIR}/conf/setenv.sh"

# ============= Upgrade of tools =============

# Execute command operations which should be done without upgrade of tools
command_exec_before_tools_upgrade "$@"

# Check whether the temporary database is newer than the ports tree and refresh if so
database_build_refresh_if_obsolete

# Get the port origin for this utility if installed by port
MYPORTORIGIN=`pkgsys_get_my_origin 2> /dev/null` || :

# Collect all installed packages
PROGRAM_DEPENDS=''
_program_exec_and_record_completion__operation ()
{
	message_section_title "Collecting all installed packages"
	pkg_info_qoa > ${DBDIR}/installed_ports
	pkg_info_gen_pkg_origin_table
	str_escape_regexp_filter < "${DBDIR}/installed_ports" \
		| sed 's/^/^/; s/$/$/' > ${DBDIR}/installed_ports.grep_pattern
	message_echo
}
program_exec_and_record_completion COLLECT_ALL_INSTALLED_PACKAGES

# Preliminary inspection of tools which have to be up-to-date
# (No need depend on PARSE_CONF because INSPECT_ALL_DEPENDENCIES will take the task.)
PROGRAM_DEPENDS=
_program_exec_restartable_loop_operation__routine ()
{
	local origin
	origin=$1
	database_build_inspect_dependencies "$origin"
}
_program_exec_and_record_completion__operation ()
{
	local DEPTH_INDEX
	message_section_title "Preliminary inspection of tools which have to be up-to-date"
	{
		[ "$PKGSYS_USE_PKGNG" = yes ] && echo 'ports-mgmt/pkg'
		pkgsys_is_dialog4ports_used && echo 'ports-mgmt/dialog4ports'
		[ -n "$MYPORTORIGIN" ] && echo "$MYPORTORIGIN"
	} 2> /dev/null > ${DBDIR}/stage.loop_list/tools_to_inspect
	DEPTH_INDEX='--'
	program_exec_restartable_loop_operation tools_to_inspect
	database_build_post_inspect_dependencies
	message_echo
}
program_exec_and_record_completion PRELIMINARY_INSPECTION_OF_TOOLS

# Upgrade of ports-mgmt/pkg if new
# (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
	-a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no \
	-a "$PKGSYS_USE_PKGNG" = yes ]
then
	PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
	_program_exec_and_record_completion__operation ()
	{
		local _MSG_CURRENT_STAGE_general
		_MSG_CURRENT_STAGE_general="pkgng upgrade"
		temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
		message_section_title "Upgrade of ports-mgmt/pkg if new"
		touch "${DBDIR}/target_all"
		reinstall_exec ports-mgmt/pkg
		reinstall_restore_conflicts
		rm -f "${DBDIR}/target_all"
		message_echo
	}
	program_exec_and_record_completion UPGRADE_PKGNG
fi

# Upgrade of ports-mgmt/dialog4ports if new
# (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
	-a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no ] \
	&& pkgsys_is_dialog4ports_used
then
	PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
	_program_exec_and_record_completion__operation ()
	{
		local _MSG_CURRENT_STAGE_general
		_MSG_CURRENT_STAGE_general="pkgng dialog4ports"
		temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
		message_section_title "Upgrade of dialog4ports if new"
		touch "${DBDIR}/target_all"
		reinstall_exec ports-mgmt/dialog4ports
		reinstall_restore_conflicts
		rm -f "${DBDIR}/target_all"
		message_echo
	}
	program_exec_and_record_completion UPGRADE_DIALOG4PORTS
fi

# Upgrade of this utility if new
# (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
	-a $opt_dry_run = no -a $opt_suppress_self_upadte = no \
	-a -n "$MYPORTORIGIN" ]
then
	PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
	_program_exec_and_record_completion__operation ()
	{
		local _MSG_CURRENT_STAGE_general
		_MSG_CURRENT_STAGE_general="pkgng upgrade"
		temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
		message_section_title "Upgrade of this utility if new"
		touch "${DBDIR}/target_all"
		reinstall_exec "$MYPORTORIGIN"
		reinstall_restore_conflicts
		rm -f "${DBDIR}/target_all"
		message_echo
	}
	program_exec_and_record_completion UPGRADE_SELF
fi

if [ "x`${APPNAME} -aV 2> /dev/null`" != "x$MYVERSION" ]
then
	message_echo "INFO: ${APPNAME} is upgraded and the temporary database needs refresh."
	database_build_clean_for_self_upgrade || :
	message_echo "INFO: Restarting with the new version."
	message_echo
	temp_trap_for_invoking_new_version
	. "${TMPDIR}"/restart_command.sh
	exit
fi


# ==================================================
# ================== PREPARATION ===================
# ==================================================

# ============= Correspondence to configuration changes =============

# Patch to the temporary database by reflecting changes in configuration
PROGRAM_DEPENDS='PARSE_CONF'
_program_exec_and_record_completion__operation ()
{
	local tmpfile_diff tmpfile_old tmpfile_new key
	[ -d "${DBDIR}/conf.prev" ] || return 0
	message_section_title "Patch to the temporary database by reflecting changes in configuration"
	tmpfile_old=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::old
	tmpfile_new=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::new
	tmpfile_updated_ports=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::updated_ports
	if fileedit_manipulate_old_new_lines \
		"${DBDIR}/conf.prev/setenv.sh" "${DBDIR}/conf/setenv.sh" "$tmpfile_old" "$tmpfile_new"
	then
		if grep -q -e ^LOCALBASE= -e ^LINUXBASE= -e ^PORTSDIR= "$tmpfile_old" "$tmpfile_new"
		then
			message_echo "ERROR: Migration of the temporary database is unavailable because LOCALBASE, LINUXBASE or PORTSDIR was changed." >&2
			message_echo "        ${APPNAME} clean" >&2
			message_echo "must be executed in advance." >&2
			exit 1
		fi
	fi
	cut -s -d '|' -f 1,2 "${DBDIR}/conf.prev/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.old
	cut -s -d '|' -f 1,2 "${DBDIR}/conf/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.new
	if fileedit_manipulate_old_new_lines \
		"${TMPDIR}/MOVED_ALT.old" "${TMPDIR}/MOVED_ALT.new" "$tmpfile_old" "$tmpfile_new"
	then
		cat "$tmpfile_old" "$tmpfile_new" | while read from to
		do
			echo "$from"
			[ -n "$to" ] && echo "$to"
		done
	fi > $tmpfile_updated_ports
	if fileedit_manipulate_old_new_lines \
		"${DBDIR}/conf.prev/REPLACE.csv" "${DBDIR}/conf/REPLACE.csv" "$tmpfile_old" "$tmpfile_new"
	then
		cat "$tmpfile_old" "$tmpfile_new" | while read from to
		do
			echo "$from"
			[ -n "$to" ] && echo "$to"
		done
	fi >> $tmpfile_updated_ports
	[ `wc -l < $tmpfile_updated_ports` -gt 0 ] && rm -f "${DBDIR}/REPLACE.complete_sed_pattern"
	[ -d "${DBDIR}/conf/each_port" ] && find "${DBDIR}/conf/each_port" -depth 2 \
		| while read dbpath
	do
		origin=`str_dirpath_to_origin "$dbpath"`
		dbpath_prev=${DBDIR}/conf.prev/each_port/$origin
		diff -r "$dbpath_prev" "$dbpath" > /dev/null 2>&1 && continue
		echo "$origin"
	done >> $tmpfile_updated_ports
	[ -d "${DBDIR}/conf.prev/each_port" ] && find "${DBDIR}/conf.prev/each_port" -depth 2 \
		| while read dbpath_prev
	do
		origin=`str_dirpath_to_origin "$dbpath_prev"`
		dbpath=${DBDIR}/conf/each_port/$origin
		[ -d "$dbpath" ] && continue
		echo "$origin"
	done >> $tmpfile_updated_ports
	if [ `wc -l < $tmpfile_updated_ports` -gt 0 ]
	then
		sort -u "$tmpfile_updated_ports" | while read origin
		do
			database_build_patch_reconf "$origin"
		done
		program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
	fi
	message_echo
}
program_exec_and_record_completion PATCH_TO_TMPDB_REFLECT_CONF_CHANGES

# ============= Database construction =============

# Execute command operations which must be done before building the temporary database
command_exec_before_building_tempdb "$@"

# Meta process for redo
PROGRAM_DEPENDS=''
_program_exec_and_record_completion__operation ()
{
	rm -f "${DBDIR}/new_success_in_current_run"
	[ "x$COMMAND_MODE" = xredo ] || return 0
	message_echo "[REDO mode]"
	message_echo
}
program_exec_and_record_completion REDO_INIT

# Determine specified targets
PROGRAM_DEPENDS=''
_program_exec_and_record_completion__operation ()
{
	local tag level dbsuffix
	message_section_title "Determining specified targets"
	cat "${DBDIR}/stage.loop_list/target_itself.specified" \
		"${DBDIR}/stage.loop_list/target_dependents.specified" \
		"${DBDIR}/stage.loop_list/target_requirements.specified" \
		"${DBDIR}/need.list" \
		"${DBDIR}/targets_specified_so_far" 2> /dev/null \
		| sort -u > ${DBDIR}/targets_specified_so_far.tmp
	mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
	rm -f "${DBDIR}/stage.loop_list/target_itself.specified" \
		"${DBDIR}/stage.loop_list/target_dependents.specified" \
		"${DBDIR}/stage.loop_list/target_requirements.specified"
	if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
	then
		options_select_new_ports_if_duplicated O \
			"${DBDIR}/stage.loop_list/target_itself.specified" "$opt_target_itself"
		options_select_new_ports_if_duplicated t \
			"${DBDIR}/stage.loop_list/target_dependents.specified" "$opt_target_dependents"
		options_select_new_ports_if_duplicated T \
			"${DBDIR}/stage.loop_list/target_requirements.specified" "$opt_target_requirements"
		if [ `cat "${DBDIR}/stage.loop_list/target_itself.specified" \
			"${DBDIR}/stage.loop_list/target_dependents.specified" \
			"${DBDIR}/stage.loop_list/target_requirements.specified" | wc -l` -eq 0 ]
		then
			message_echo "ERROR: No matching port for target globs." >&2
			message_echo >&2
			exit 1
		fi
		cat "${DBDIR}/stage.loop_list/target_itself.specified" \
			"${DBDIR}/stage.loop_list/target_dependents.specified" \
			"${DBDIR}/stage.loop_list/target_requirements.specified" \
			| sort -u > ${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset
		cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset" "${DBDIR}/need.list" 2> /dev/null \
			| sort -u > ${DBDIR}/need.list.tmp
		mv "${DBDIR}/need.list.tmp" "${DBDIR}/need.list"
		sort -u "${DBDIR}/need.list" "${DBDIR}/targets_specified_so_far" \
			> ${DBDIR}/targets_specified_so_far.tmp
		mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
		for tag in all run build none
		do
			for level in direct full
			do
				dbsuffix=$tag.$level
				{
					cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset"
					cat "${DBDIR}/stage.loop_list/target_dependents.specified" | while read origin
					do
						nodedir=${DBDIR}/requires/$origin
						cat "$nodedir/dependents.$dbsuffix" 2> /dev/null
					done
					cat "${DBDIR}/stage.loop_list/target_requirements.specified" | while read origin
					do
						nodedir=${DBDIR}/requires/$origin
						cat "$nodedir/requirements.$dbsuffix" 2> /dev/null
					done
				} | sort -u | while read origin
				do
					fileedit_rm_a_line "$origin" "${DBDIR}/success.$dbsuffix.list"
					fileedit_rm_a_line "$origin" "${DBDIR}/todo_after_requirements_succeed.$dbsuffix.list"
					rm -f "${DBDIR}/requires/$origin/succeeded_once"
				done
			done
		done
	fi
	message_echo
}
program_exec_and_record_completion DETERMINE_SPECIFIED_TARGETS

# Show specified targets
if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" -a $opt_batch_mode = no ]
then
	message_echo "INFO: (Re/de-)installation will be carried out only for the targets:"
	echo
	if [ `wc -l < ${DBDIR}/stage.loop_list/target_itself.specified` -gt 0 ]
	then
		message_echo "[Targets only]"
		echo "----------------------------------------"
		cat "${DBDIR}/stage.loop_list/target_itself.specified"
		echo "----------------------------------------"
		echo
	fi
	if [ `wc -l < ${DBDIR}/stage.loop_list/target_dependents.specified` -gt 0 ]
	then
		message_echo "[Targets with their `options_get_dependency_msgterm` dependents]"
		echo "----------------------------------------"
		cat "${DBDIR}/stage.loop_list/target_dependents.specified"
		echo "----------------------------------------"
		echo
	fi
	if [ `wc -l < ${DBDIR}/stage.loop_list/target_requirements.specified` -gt 0 ]
	then
		message_echo "[Targets with their `options_get_dependency_msgterm` requirements]"
		echo "----------------------------------------"
		cat "${DBDIR}/stage.loop_list/target_requirements.specified"
		echo "----------------------------------------"
		echo
	fi
fi

# Determine all target ports
PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS COLLECT_ALL_INSTALLED_PACKAGES'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Determining all target ports"
	{
		if [ $opt_only_target_scope = no ]
		then
			cat "${DBDIR}/installed_ports" 2> /dev/null || :
		fi
		cat "${DBDIR}/stage.loop_list/target_itself.specified" || :
		cat "${DBDIR}/stage.loop_list/target_dependents.specified" || :
		cat "${DBDIR}/stage.loop_list/target_requirements.specified" || :
		cat "${DBDIR}/targets_specified_so_far" || :
	}  2> /dev/null | sort -u > "${DBDIR}/stage.loop_list/ports_to_inspect"
	message_echo
}
program_exec_and_record_completion DETERMINE_ALL_TARGET_PORTS

# Inspection of all dependencies
PROGRAM_DEPENDS='PARSE_CONF DETERMINE_ALL_TARGET_PORTS'
_program_exec_restartable_loop_operation__routine ()
{
	local origin
	origin=$1
	database_build_inspect_dependencies "$origin"
}
_program_exec_and_record_completion__operation ()
{
	local DEPTH_INDEX 
	message_section_title "Inspecting dependencies of the all installed packages"
	[ $opt_only_target_scope = no -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ] && \
		message_echo "INFO: Ports which seem irrelevant to the targets are also inspected in order to get complete information."
	DEPTH_INDEX='--'
	program_exec_restartable_loop_operation ports_to_inspect
	database_build_post_inspect_dependencies
	message_echo
}
program_exec_and_record_completion INSPECT_ALL_DEPENDENCIES

# Convert dependency-lists to actual ones
PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES'
_program_exec_restartable_loop_operation__routine ()
{
	local origin table dbtag level tag target
	origin=$1
	for table in dependents requirements
	do
		for dbtag in requires obsolete
		do
			for level in direct full
			do
				for tag in all run build
				do
					target=${DBDIR}/$dbtag/$origin/${table}.${tag}.${level}
					if [ -e "$target.src" ]
					then
						sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "$target.src" \
							| grep -v '^$' | sort -u > $target.tmp
						[ -e "$target" ] && ! diff "$target.tmp" "$target" > /dev/null \
							&& echo "$origin" >> ${DBDIR}/update_dependencies
						mv "$target.tmp" "$target"
					else
						[ -e "$target" ] && echo "$origin" >> ${DBDIR}/update_dependencies
						rm -f "$target"
					fi
				done
			done
		done
	done
}
_program_exec_and_record_completion__operation ()
{
	message_section_title "Conversion of dependency-lists to actual ones"
	program_exec_restartable_loop_operation convert_dependency_lists
	sort -u "${DBDIR}/update_dependencies" > ${DBDIR}/update_dependencies.tmp
	mv "${DBDIR}/update_dependencies.tmp" "${DBDIR}/update_dependencies"
	str_escape_regexp_filter < ${DBDIR}/update_dependencies \
		| sed 's/^/^/; s/$/$/' > ${DBDIR}/update_dependencies.grep_pattern
	for tag in all run build
	do
		( cd "${DBDIR}/requires" && \
			find . -depth 3 -type f -name requirements.${tag}.full | sed 's|^./||;s|/[^/]*$||' ) \
			| grep -v -E -f "${DBDIR}/update_dependencies.grep_pattern" \
			| str_escape_regexp_filter | sed 's/^/^/; s/$/$/' \
			> ${TMPDIR}/convert_requirements_list:full_complete.grep_pattern || :
		( cd "${DBDIR}/requires" && \
			find . -depth 3 -type f -name requirements.${tag}.direct | sed 's|^./||;s|/[^/]*$||' ) \
			| grep -v -E -f "${TMPDIR}/convert_requirements_list:full_complete.grep_pattern" \
			> ${DBDIR}/stage.loop_list/complete_${tag}time_reqlists || :
	done
	for inspected_level_tmp in direct node
	do
		cat "${DBDIR}/ports.inspected.${inspected_level_tmp}.list" || :
	done 2> /dev/null | sort -u > ${DBDIR}/stage.loop_list/trim_dependency_lists_rm_uninspected_ports
	find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/stage.loop_list/inspect_dependent
	[ -e "${DBDIR}/dependents_files" ] && \
		mv "${DBDIR}/dependents_files" "${DBDIR}/dependents_files.prev"
	rm -f "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" "${DBDIR}/dependents_files.tmp"
	message_echo
}
program_exec_and_record_completion CONVERT_REQUIREMENTS_LIST

# Completion of recursive requirement lists
for _REQUIREMENT_LISTS_tag in all run build
do
	PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
	_program_exec_restartable_loop_operation__routine ()
	{
		local tag dbpath origin
		tag=${_REQUIREMENT_LISTS_tag}
		dbpath=$1
		origin=`str_dirpath_to_origin "$dbpath"`
		database_build_get_complete_recursive_dependency requirements.${tag} "$origin" > /dev/null
	}
	_program_exec_and_record_completion__operation ()
	{
		local tag
		tag=${_REQUIREMENT_LISTS_tag}
		message_section_title "Completion of ${tag}-time requirement lists"
		program_exec_restartable_loop_operation complete_${tag}time_reqlists
		message_echo
	}
	program_exec_and_record_completion REQUIREMENT_LISTS:${_REQUIREMENT_LISTS_tag}
done

# Trim dependency lists by removing uninspected ports
if [ $opt_only_target_scope = yes ]
then
	PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST'
	_program_exec_restartable_loop_operation__routine ()
	{
		local dbpath tag level srcdb
		dbpath=$1
		for tag in all run build
		do
			for level in direct full
			do
				srcdb=requirements.${tag}.${level}
				[ -e "$dbpath/$srcdb" ] || continue
				grep -E -f "${DBDIR}/inspected_ports.grep_pattern" "$dbpath/$srcdb" \
					> $dbpath/$srcdb.tmp || :
				mv "$dbpath/$srcdb.tmp" "$dbpath/$srcdb"
			done
		done
	}
	_program_exec_and_record_completion__operation ()
	{
		message_section_title "Trimming dependency lists by removing uninspected ports"
		program_exec_restartable_loop_operation trim_dependency_lists_rm_uninspected_ports
		message_echo
	}
	program_exec_and_record_completion TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS
fi

# Inspection of dependents
PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS'
_program_exec_restartable_loop_operation__routine ()
{
	local dbpath origin tag level srcdb dstdb
	dbpath=$1
	origin=`str_dirpath_to_origin "$dbpath"`
	for tag in all run build
	do
		for level in direct full
		do
			srcdb=requirements.${tag}.${level}
			dstdb=dependents.${tag}.${level}
			[ -e "$dbpath/$srcdb" ] || continue
			while read origin_requirement
			do
				dstpath=${DBDIR}/requires/$origin_requirement
				echo "$dstpath/$dstdb" >> ${DBDIR}/dependents_files.tmp
				[ "$dstpath/$dstdb" -nt "$dbpath/$srcdb" ] && continue
				[ -d "$dstpath" ] || mkdir -p "$dstpath"
				echo "$origin" >> $dstpath/$dstdb.raw
				echo "$dstpath/$dstdb" >> ${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp
			done < $dbpath/$srcdb
		done
	done
}
_program_exec_and_record_completion__operation ()
{
	local dbrequires_valesc
	message_section_title "Inspection of dependents"
	dbrequires_valesc=`str_escape_replaceval "${DBDIR}/requires/"`
	program_exec_restartable_loop_operation inspect_dependent
	sort -u "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" 2> /dev/null \
		> ${DBDIR}/stage.loop_list/make_dependents_lists_unique || :
	sort -u "${DBDIR}/dependents_files.tmp" 2> /dev/null > ${DBDIR}/dependents_files || :
	[ -e "${DBDIR}/make_dependents_lists_unique.prev" ] && \
		fileedit_manipulate_old_lines "${DBDIR}/dependents_files.prev" "${DBDIR}/dependents_files" \
		| xargs rm -f
	message_echo
}
program_exec_and_record_completion INSPECT_DEPENDENTS

# Remove duplicated lines in dependents lists
PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST INSPECT_DEPENDENTS'
_program_exec_restartable_loop_operation__routine ()
{
	local dbpath tag level dstdb
	dstdb=$1
	cat "$dstdb" "$dstdb.raw" 2> /dev/null | sort -u > $dstdb.tmp
	mv "$dstdb.tmp" "$dstdb"
	rm -f "$dstdb.raw"
}
_program_exec_and_record_completion__operation ()
{
	local dbrequires_valesc
	message_section_title "Removing duplicated items in dependents lists"
	program_exec_restartable_loop_operation make_dependents_lists_unique
	message_echo
}
program_exec_and_record_completion MAKE_DEPENDENTS_LISTS_UNIQUE

# Preparation of target attribute information
for _TARGET_ATTR_INFO_table in requirements dependents itself
do
	[ `cat "${DBDIR}/stage.loop_list/target_${_TARGET_ATTR_INFO_table}.replaced.specified" 2> /dev/null \
		| wc -l` -gt 0 ] || continue
	PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS CONVERT_REQUIREMENTS_LIST'
	_program_exec_restartable_loop_operation__routine ()
	{
		local origin dbtargets_valesc table
		origin=$1
		dbtargets_valesc=`str_escape_replaceval "${DBDIR}/targets/"`
		table=${_TARGET_ATTR_INFO_table}
		for database in requires initial
		do
			dbpath=${DBDIR}/$database/$origin
			dstpath=${DBDIR}/targets/$origin
			[ -d "$dstpath" ] || mkdir -p "$dstpath"
			touch "$dstpath/target_itself"
			echo "$origin" >> ${DBDIR}/all_targets.lst
			[ $table = itself ] && continue
			for tag in all run build
			do
				for level in direct full
				do
					srcdb=${table}.${tag}.${level}
					dstdb=target_${database}_${table}.${tag}.${level}
					[ -e "$dbpath/$srcdb" ] || continue
					cat "$dbpath/$srcdb" >> ${DBDIR}/all_targets.lst
					sed -E "s/^/$dbtargets_valesc/; s|$|/$dstdb|" "$dbpath/$srcdb" \
						| fileedit_add_a_line_to_files_if_new "$origin"
				done
			done
		done
	}
	_program_exec_and_record_completion__operation ()
	{
		local table
		table=${_TARGET_ATTR_INFO_table}
		message_section_title "Preparation of target attribute information for dependency [$table]"
		program_exec_restartable_loop_operation target_$table.replaced.specified
		message_echo
	}
	program_exec_and_record_completion TARGET_ATTR_INFO:${_TARGET_ATTR_INFO_table}
done

# Post-process after the preparation of target attribute information
PROGRAM_DEPENDS='MAKE_DEPENDENTS_LISTS_UNIQUE TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Post-process after the preparation of target attribute information"
	sort -u "${DBDIR}/all_targets.lst" 2> /dev/null \
		| grep -E -f "${DBDIR}/inspected_ports.grep_pattern" \
		| sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" \
		> ${DBDIR}/all_targets.lst.tmp || :
	mv "${DBDIR}/all_targets.lst.tmp" "${DBDIR}/all_targets.lst"
	find "${DBDIR}/targets" -depth 2 -type d > ${DBDIR}/stage.loop_list/build_complement_to_new_dependents_for_targets 2> /dev/null || :
	{
		cat "${DBDIR}/all_targets.lst" "${DBDIR}/need.with_replaced.list" 2> /dev/null || :
		find "${DBDIR}/requires" -depth 3 -type f -name installed_version \
			| sed -E 's|.*/([^/]+/[^/]+)/[^/]*$|\1|'
	} | sort -u > ${DBDIR}/stage.loop_list/inspect_necessity
	cp /dev/null "${DBDIR}/stage.loop_list/parse_target_attr_info"
	find -E "${DBDIR}/requires" -depth 3 -type f -regex '.*/necessary_port\.(direct|full)$' -delete
	message_echo
}
program_exec_and_record_completion TARGET_ATTR_INFO_POSTPROCESS

# Build of data on complement to new dependents for target attribute information
PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents CONVERT_REQUIREMENTS_LIST'
_program_exec_restartable_loop_operation__routine ()
{
	local dbpath origin
	dbpath=$1
	origin=`str_dirpath_to_origin "$dbpath"`
	database_build_complement_to_new_dependents_for_targets "$origin"
}
_program_exec_and_record_completion__operation ()
{
	message_section_title "Build of data on complement to new dependents for target attribute information"
	program_exec_restartable_loop_operation build_complement_to_new_dependents_for_targets
	sort -u "${DBDIR}/stage.loop_list/parse_target_attr_info" > ${DBDIR}/stage.loop_list/parse_target_attr_info.tmp
	mv "${DBDIR}/stage.loop_list/parse_target_attr_info.tmp" "${DBDIR}/stage.loop_list/parse_target_attr_info"
	message_echo
}
program_exec_and_record_completion COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO

# Parse target attribute information
PROGRAM_DEPENDS='COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO'
_program_exec_restartable_loop_operation__routine ()
{
	local dbpath origin
	dbpath=$1
	origin=`str_dirpath_to_origin "$dbpath"`
	database_build_target_attributes "$origin"
}
_program_exec_and_record_completion__operation ()
{
	message_section_title "Parsing target attribute information"
	program_exec_restartable_loop_operation parse_target_attr_info
	message_echo
}
program_exec_and_record_completion PARSE_TARGET_ATTR_INFO

# Inspection of necessity
PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS REQUIREMENT_LISTS:run-time REQUIREMENT_LISTS:build-time INSPECT_ALL_DEPENDENCIES'
_program_exec_restartable_loop_operation__routine ()
{
	local origin
	origin=$1
	for level in direct full
	do
		database_build_inspect_necessity_for_only_new_upgrade "$origin" "$level"
	done
}
_program_exec_and_record_completion__operation ()
{
	message_section_title "Inspection of necessity"
	program_exec_restartable_loop_operation inspect_necessity
	for level in direct full
	do
		find "${DBDIR}/requires" -depth 3 -type f -name "necessary_port.${level}" \
			> ${DBDIR}/stage.loop_list/necessary_ports.${level}
	done
	message_echo
}
program_exec_and_record_completion INSPECT_NECESSITY

# Inspection of necessary upgrades
for _NECESSARY_UPDATES_level in direct full
do
	PROGRAM_DEPENDS='INSPECT_NECESSITY INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE'
	_program_exec_restartable_loop_operation__routine ()
	{
		local markerpath level dbpath origin tag
		markerpath=$1
		level=${_NECESSARY_UPDATES_level}
		dbpath=`dirname "$markerpath"`
		origin=`str_dirpath_to_origin "$dbpath"`
		database_query_does_a_port_need_update "$origin" || return 0
		for tag in all run build none
		do
			touch "$dbpath/necessary_upgrade.$tag.${level}"
			[ -e "$dbpath/dependents.$tag.${level}" ] || continue
			while read origin_dependent
			do
				touch "${DBDIR}/requires/$origin_dependent/necessary_upgrade.$tag.${level}"
			done < $dbpath/dependents.$tag.${level}
		done
	}
	_program_exec_and_record_completion__operation ()
	{
		local level
		level=${_NECESSARY_UPDATES_level}
		message_section_title "Inspection of necessary upgrades at the $level level"
		program_exec_restartable_loop_operation necessary_ports.${level}
		message_echo
	}
	program_exec_and_record_completion NECESSARY_UPDATES:${_NECESSARY_UPDATES_level}
done

# Preparation for inspection of new leaf ports
if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
then
	PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PARSE_CONF'
	_program_exec_and_record_completion__operation ()
	{
		message_section_title "Preparation for inspection of new leaf ports"
		find "${DBDIR}/requires" -depth 3 -type f -name dependents.all.full \
			| sed -E 's|.*/([^/]+/[^/]+)/[^/]+$|\1|' \
			| sort -u > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports
		sort -u "${DBDIR}/inspected_ports" > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports
		fileedit_manipulate_new_lines \
			"${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports" \
			"${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports" \
			| grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" \
			> ${DBDIR}/stage.loop_list/leaf_ports_primary_candidates || :
		cp /dev/null "${DBDIR}/grep.leaf_ports.pattern"
		cp /dev/null "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
		message_echo
	}
	program_exec_and_record_completion PREPARE_INSPECT_LEAF_PORTS
fi

# Inspection of new primary leaf ports
if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
then
	PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PREPARE_INSPECT_LEAF_PORTS PARSE_CONF'
	_program_exec_restartable_loop_operation__routine ()
	{
		local origin origin_ini origin_esc dbpath origin_req
		origin=$1
		pkgsys_is_pkgtool "$origin" && return
		dbpath=${DBDIR}/requires/$origin
		origin_esc=`str_escape_regexp "$origin"`
		grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
		if ! grep -q -E "^$origin_esc$" "${DBDIR}/noneed.list" 2> /dev/null
		then
			if [ -e "$dbpath/initial_orig" ]
			then
				origin_ini=`cat "$dbpath/initial_orig"`
				[ -e "${DBDIR}/initial/$origin_ini/installed_version" \
					-a `cat "${DBDIR}/initial/$origin_ini/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
					&& return
			fi
			[ -e "${DBDIR}/initial/$origin/installed_version" \
				-a `cat "${DBDIR}/initial/$origin/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
				&& return
		fi
		if [ -e "$dbpath/requirements.all.full" ]
		then
			grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" "$dbpath/requirements.all.full" | \
				fileedit_add_lines_if_new "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
		fi
		fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
	}
	_program_exec_and_record_completion__operation ()
	{
		local num_leaves num_leaves_prev
		message_section_title "Inspection of new primary leaf ports"
		program_exec_restartable_loop_operation leaf_ports_primary_candidates
		wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' ' > ${DBDIR}/num_leaves
		cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
		message_echo "  `cat "${DBDIR}/num_leaves"` primary leaf port(s) is/are found."
		message_echo
	}
	program_exec_and_record_completion INSPECT_PRIMARY_LEAF_PORTS
fi

# Inspection of requirements of new leaf ports
if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
then
	PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE INSPECT_PRIMARY_LEAF_PORTS PARSE_CONF'
	_program_exec_and_record_completion__operation ()
	{
		local num_leaves num_leaves_prev num_inspect num_leaves_new
		message_section_title "Inspection of requirements of new leaf ports"
		message_echo "INFO: The inspection proceeds by iterative method."
		while :
		do
			_program_exec_restartable_loop_operation__routine ()
			{
				local origin origin_esc dbpath
				origin=$1
				pkgsys_is_pkgtool "$origin" && return
				dbpath=${DBDIR}/requires/$origin
				origin_esc=`str_escape_regexp "$origin"`
				grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
				grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
					"$dbpath/dependents.all.full" > /dev/null 2>&1 && return
				cat "$dbpath/requirements.all.full" 2> /dev/null \
					>> ${DBDIR}/leaf_ports_secondary_candidates.new_requirements || :
				fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
			}
			program_exec_restartable_loop_operation leaf_ports_secondary_candidates
			num_leaves_prev=`cat "${DBDIR}/num_leaves"`
			num_leaves=`wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' '`
			num_leaves_new=`echo $(($num_leaves-$num_leaves_prev)) | tr -d ' '`
			if [ $num_leaves_new -eq 0 ]
			then
				message_echo "  No more leaf port is found."
				message_echo "  $num_leaves leaf port(s) is/are found in total."
				break
			fi
			{
				grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
					"${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
				cat "${DBDIR}/leaf_ports_secondary_candidates.new_requirements" || :
			} | grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" | sort -u \
				> ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp || :
			program_reset_loop_for_stage INSPECT_REQUIREMENTS_OF_LEAF_PORTS
			mv "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp" \
				"${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
			cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
			echo "$num_leaves" > ${DBDIR}/num_leaves
			num_inspect=`wc -l < ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates | tr -d ' '`
			message_echo "  $num_leaves_new leaf port(s) is/are newly found; continue for $num_inspect candidate(s)."
		done
		grep -E -f "${DBDIR}/grep.leaf_ports.pattern" "${DBDIR}/inspected_ports" | sort -u > ${DBDIR}/leaf_ports || :
		message_echo
	}
	program_exec_and_record_completion INSPECT_REQUIREMENTS_OF_LEAF_PORTS
fi

# Order the ports considering dependencies
PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Ordering dependencies"
	if ! database_build_order_ports_considering_dependencies
	then
		message_echo "ERROR: Unsatisfied dependencies are remained:" >&2
		message_cat "${DBDIR}/unsatisfied.list"
		message_echo "*** Aborted by ${APPNAME}"
		message_echo "The ports tree seems broken. You might have caught an incomplete version."
		message_echo "You are encouraged to update the ports tree by portsnap(8)."
		message_echo "Then execute"
		message_echo " ${APPNAME} clean"
		message_echo "before restart."
		temp_terminate_process () { :; }
		exit 1
	fi
	message_echo
}
program_exec_and_record_completion ORDER_ALL_DEPENDENCIES

# Selection of removing leaf ports
PROGRAM_DEPENDS='INSPECT_REQUIREMENTS_OF_LEAF_PORTS'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Selection of removing leaf ports"
	deinstall_select_leaf_ports_to_delete
	message_echo
}
program_exec_and_record_completion SELECT_LEAF_PORTS

# Selection of removing obsolete ports
PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES PARSE_CONF'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Selection of removing obsolete ports"
	deinstall_select_obsolete_ports_to_delete
	message_echo
}
program_exec_and_record_completion SELECT_OBSOLETE_PORTS

# Collection of leaf ports to delete
if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
then
	PROGRAM_DEPENDS='SELECT_LEAF_PORTS'
	_program_exec_and_record_completion__operation ()
	{
		local src src_unselected reqptn_file src_with_initial_origins
		message_section_title "Collecting leaf ports to delete"
		src=${DBDIR}/leaf_ports
		src_unselected=${DBDIR}/leaf_ports_to_delete.unselected
		src_with_initial_origins=${DBDIR}/leaf_ports.with_ini
		reqptn_file=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
		cat "$src_unselected" 2> /dev/null | while read origin
		do
			cat "${DBDIR}/requires/$origin/requirements.all.full" || :
		done | sort -u | str_escape_regexp_filter \
			| sed 's/^/^/;s/$/$/' > $reqptn_file
		database_query_add_initial_origins < $src > $src_with_initial_origins
		message_echo
	}
	program_exec_and_record_completion COLLECT_LEAF_PORTS_TO_DELETE
fi

# Collection of obsolete ports to delete
PROGRAM_DEPENDS='SELECT_OBSOLETE_PORTS'
_program_exec_and_record_completion__operation ()
{
	local src src_selected src_unselected dst_selected reqptn_file
	message_section_title "Collecting obsolete ports to delete"
	src=${DBDIR}/obsolete_ports.can_be_deleted
	src_selected=${DBDIR}/obsolete_ports_to_delete.selected
	src_unselected=${DBDIR}/obsolete_ports_to_delete.unselected
	dst_selected=${DBDIR}/obsolete_ports_to_delete
	reqptn_file=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
	cat "$src_unselected" 2> /dev/null | while read origin
	do
		cat "${DBDIR}/initial/$origin/requirements.run.full" || :
		cat "${DBDIR}/obsolete/$origin/requirements.run.full" || :
	done | sort -u | str_escape_regexp_filter \
		| sed 's/^/^/;s/$/$/' > $reqptn_file
	grep -v -E -f "$reqptn_file" "$src_selected" > $dst_selected 2> /dev/null || :
	message_echo
}
program_exec_and_record_completion COLLECT_OBSOLETE_PORTS_TO_DELETE

# Set up the list of ports to reinstall
PROGRAM_DEPENDS='ORDER_ALL_DEPENDENCIES'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Setting up the list of ports to reinstall"
	cp -p "${DBDIR}/reinst_order.list" "${DBDIR}/stage.loop_list/reinst_todo"
	message_echo
}
program_exec_and_record_completion SETUP_REINST_TODO

# Composition of a list for deinstallation of obsolete and leaf packages
PROGRAM_DEPENDS='COLLECT_LEAF_PORTS_TO_DELETE COLLECT_OBSOLETE_PORTS_TO_DELETE'
_program_exec_and_record_completion__operation ()
{
	local reqptn_leaf reqptn_obs leaf_selected leaf_selected_src obs_selected obs_selected_src grepptn preserved
	message_section_title "Composing a list for deinstallation of obsolete and leaf packages"
	reqptn_leaf=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
	reqptn_obs=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
	leaf_selected_src=${DBDIR}/leaf_ports_to_delete.selected
	leaf_selected=${DBDIR}/leaf_ports_to_delete
	obs_selected_src=${DBDIR}/obsolete_ports_to_delete.selected
	obs_selected=${DBDIR}/obsolete_ports_to_delete
	grepptn=${DBDIR}/ports_to_delete.grep_pattern
	grepptn_col1=${DBDIR}/ports_to_delete.grep_pattern_col1
	preserved=${TMPDIR}/LIST_DEINST_PKGS::preserved
	if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
	then
		cat "$reqptn_leaf" "$reqptn_obs" 2> /dev/null | sort -u > $grepptn
		grep -v -E -f "$grepptn" "$leaf_selected_src" 2> /dev/null \
			| database_query_add_initial_origins > $leaf_selected || :
		cat "$obs_selected" "$leaf_selected" 2> /dev/null || :
	else
		rm -f "$leaf_selected"
		cat "$obs_selected" 2> /dev/null
	fi | sort -u > ${DBDIR}/stage.loop_list/ports_to_delete
	str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
		| sed 's/^/^/;s/$/$/' > $grepptn
	str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
		| sed 's/^/^/;s/$/[[:space:]]/' > $grepptn_col1
	cat "${DBDIR}/leaf_ports.with_ini" "${DBDIR}/obsolete_ports" 2> /dev/null \
		| grep -E -v -f "$grepptn" > ${DBDIR}/stage.loop_list/ports_to_restore || :
	if [ $opt_batch_mode = no ]
	then
		if [ ! -e "${DBDIR}/inspected_ports_only_partially" ] && \
			grep -v -E -f "$grepptn" "$leaf_selected_src" > $preserved 2> /dev/null
		then
			message_echo "INFO: Following leaf ports are preserved because required by other preserved leaf/obsolete ports."
			message_echo "----------------"
			while read origin
			do
				pkgtag=`cat "${DBDIR}/required/$origin/pkgtag" 2> /dev/null` || :
				if [ -n "$pkgtag" ]
				then
					echo "$origin" "($pkgtag)"
				else
					echo "$origin"
				fi
			done < $preserved
			message_echo "----------------"
		fi
		if grep -v -E -f "$grepptn" "$obs_selected_src" > $preserved 2> /dev/null
		then
			message_echo "INFO: Following obsolete ports are preserved because required by other obsolete ports."
			message_echo "----------------"
			while read origin
			do
				pkgtag=`cat "${DBDIR}/initial/$origin/installed_version" 2> /dev/null` || :
				if [ -n "$pkgtag" ]
				then
					echo "$origin" "($pkgtag)"
				else
					echo "$origin"
				fi
			done < $preserved
			message_echo "----------------"
		fi
	fi
	message_echo
}
program_exec_and_record_completion LIST_DEINST_PKGS

# Collect entire distfiles list
if [ $opt_suppress_inspect_entire_distinfo = yes ]
then
	PROGRAM_DEPENDS=''
	_program_exec_and_record_completion__operation ()
	{
		message_section_title "Collecting entire distfiles list"
		find "${PORTSDIR}" -depth 3 -name distinfo -exec cat {} \; \
			| grep '^SHA256 ' | sed -E 's/^SHA256 \(([^)]*)\).*/\1/' \
			| sort -u > ${DBDIR}/distfiles.entire.tmp
		mv "${DBDIR}/distfiles.entire.tmp" "${DBDIR}/distfiles.entire"
		message_echo
	}
	program_exec_and_record_completion COLLECT_ALL_DISTFILES_LIST
fi

# Inspection of all required distfiles
PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES COLLECT_ALL_DISTFILES_LIST'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Summarizing distfiles list"
	cat "${DBDIR}/distfiles.entire" "${DBDIR}/distfiles.inspected" 2> /dev/null \
		| sort -u | str_escape_regexp_filter \
		| sed 's|^|^\\.\\/|; s|$|$|' > ${DBDIR}/distfiles.grep.pattern || :
	message_echo
}
program_exec_and_record_completion DISTFILES_LIST

# Clean up of reinstallation status for preparation
PROGRAM_DEPENDS='REDO_INIT INSPECT_ALL_DEPENDENCIES'
_program_exec_and_record_completion__operation ()
{
	message_section_title "Cleaning up of reinstallation status for preparation"
	rm -rf "${DBDIR}/status.ports"
	message_echo
}
program_exec_and_record_completion CLEANUP_REINST_STATUS

# Completion of building the temporary database
PROGRAM_DEPENDS='REDO_INIT SETUP_REINST_TODO CLEANUP_REINST_STATUS PARSE_CONF INSPECT_ALL_DEPENDENCIES NECESSARY_UPDATES:direct NECESSARY_UPDATES:full PARSE_TARGET_ATTR_INFO MAKE_DEPENDENTS_LISTS_UNIQUE COLLECT_LEAF_PORTS_TO_DELETE'
_program_exec_and_record_completion__operation ()
{
	message_section_title "The temporary database is completely built up"
	message_echo
}
program_exec_and_record_completion PREPARATION


# ==================================================
# ====================== MAIN ======================
# ==================================================

# Execute command operations which must be done before actual (re/de)installation processes
command_exec_before_actual_re_de_installation "$@"

# Set termination messages
temp_terminate_process ()
{
	temp_terminate_process_common
}

# Reinstallation of remained ports
PROGRAM_DEPENDS='PREPARATION'
_program_exec_restartable_loop_operation__routine ()
{
	reinstall_exec "$@"
}
_program_exec_and_record_completion__operation ()
{
	local _MSG_CURRENT_STAGE_general
	_MSG_CURRENT_STAGE_general="reinstallation"
	temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
	message_section_title "Reinstallation"
	program_exec_restartable_loop_operation reinst_todo
	reinstall_restore_conflicts
	message_echo
}
program_exec_and_record_completion REINSTALLATION

# Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again 
PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
_program_exec_restartable_loop_operation__routine ()
{
	deinstall_restore "$@"
}
_program_exec_and_record_completion__operation ()
{
	local _MSG_CURRENT_STAGE_general
	_MSG_CURRENT_STAGE_general="restoration of unselected obsolete/leaf packages"
	temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
	message_section_title "Restoration of unselected obsolete/leaf packages"
	program_exec_restartable_loop_operation ports_to_restore
	temp_set_msg_current_stage
	message_echo
}
program_exec_and_record_completion RESTORE_ONCE_DEINST_PKGS

# Deinstallation of unused obsolete and leaf packages
PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
_program_exec_restartable_loop_operation__routine ()
{
	deinstall_exec "$@"
}
_program_exec_and_record_completion__operation ()
{
	local _MSG_CURRENT_STAGE_general
	_MSG_CURRENT_STAGE_general="deinstallation of obsolete/leaf packages"
	temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
	message_section_title "Deinstallation of unused obsolete/leaf packages"
	program_exec_restartable_loop_operation ports_to_delete
	temp_set_msg_current_stage
	message_echo
}
program_exec_and_record_completion DEINST_UNUSED_PKGS

# Clean up obsolete or unused distfiles
if [ $opt_only_target_scope = no -a $opt_keep_distfiles = no ]
then
	PROGRAM_DEPENDS='REINSTALLATION DISTFILES_LIST'
	_program_exec_and_record_completion__operation ()
	{
		local tmp_distfiles_exists
		message_section_title "Cleaning up obsolete or unused distfiles"
		tmp_distfiles_exists=${TMPDIR}/CLEANUP_OBSLETE_DISTFILES::distfiles_exists
		[ $opt_dry_run = yes ] && message_echo "INFO: The operations are not actually carried out."
		( set -e; cd "${DISTDIR}" && find . -type f ) \
			| sed 's|^\./||' | sort -u > $tmp_distfiles_exists
		fileedit_manipulate_old_lines "$tmp_distfiles_exists" "${DBDIR}/distfiles.entire" \
			| while read distfile
		do
			if [ $opt_batch_mode = no ]
			then
				echo "  $distfile"
			fi
			[ $opt_dry_run = yes ] && continue
			rm -f "${DISTDIR}/$distfile"
		done
		message_echo
	}
	program_exec_and_record_completion CLEANUP_OBSLETE_DISTFILES
fi

# Rebuild of package database
PROGRAM_DEPENDS='REINSTALLATION RESTORE_ONCE_DEINST_PKGS DEINST_UNUSED_PKGS'
_program_exec_and_record_completion__operation ()
{
	which -s pkgdb || return 0
	message_section_title "Rebuilding package database for portupgrade"
	pkgdb -fu
	message_echo
}
program_exec_and_record_completion REBUILD_PKGDB


# ==================================================
# ================ ENDING MESSAGES =================
# ==================================================

# Notice of failures
exists_unresolved_ports=
message_summary_dependents_of_failed_reinstallation failure || exists_unresolved_ports=y
message_summary_dependents_of_failed_reinstallation redo || exists_unresolved_ports=y
message_summary_dependents_of_failed_reinstallation conflict || exists_unresolved_ports=y
[ -n "$exists_unresolved_ports" ] && message_summary_advice_on_manual_solution

# End
temp_terminate_process () { :; }

if [ -z "$exists_unresolved_ports" ]
then
	message_section_title "COMPLETELY DONE"
	message_echo "- E N D -"
else
	message_warn_no_achieved_progress || :
	message_section_title "Done with some unresolved problems"
	message_echo "- To be continued -"
fi
