OSDN Git Service

Version 3.0.5+toward_3.1.0_20140717111527
[portsreinstall/current.git] / bin / portsreinstall
1 #!/bin/sh -e
2 # ==================================================================================
3 # portsreinstall main script
4 # Copyright (C) 2010-2014 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
5 # This software is distributed under the 2-Clause BSD License.
6 # ==================================================================================
7
8 # ==================================================
9 # ================== ENVIRONMENT ===================
10 # ==================================================
11
12 # ============ Set up of environment =============
13 APPNAME=`basename "$0"`
14
15 # MYVERSION=3.1.0
16 # COMPATIBLE_VERSIONS='^(3\.1\.[0-9]+)$'
17 # Template for development versions
18 MYVERSION=3.0.5+toward_3.1.0_20140717111527
19 COMPATIBLE_VERSIONS='^(3\.0\.[0-9]+\+toward_3\.1\.[0-9]+_[0-9]+|3\.0\.[0-9]+\+toward_3\.0\.[0-9]+_[0-9]+|3\.1\.[0-9]+)$'
20 MYPREFIX=`dirname "\`dirname \"$0\"\`" | sed 's|/bin$||'`
21 MYPREFIX=${MYPREFIX:-/usr/local}
22 LIBDIR=${MYPREFIX}/lib/${APPNAME}
23
24 . ${LIBDIR}/libtemp.sh
25 . ${LIBDIR}/libstr.sh
26 . ${LIBDIR}/liboptions.sh
27 . ${LIBDIR}/libusage.sh
28 . ${LIBDIR}/libmessage.sh
29 . ${LIBDIR}/libpkgsys.sh
30 . ${LIBDIR}/libmisc.sh
31 . ${LIBDIR}/libfileedit.sh
32 . ${LIBDIR}/libconf.sh
33 . ${LIBDIR}/libdatabase_build.sh
34 . ${LIBDIR}/libdatabase_query.sh
35 . ${LIBDIR}/libdatabase_record.sh
36 . ${LIBDIR}/libcommand.sh
37 . ${LIBDIR}/libprogram.sh
38 . ${LIBDIR}/libreinstall.sh
39 . ${LIBDIR}/libdeinstall.sh
40
41 misc_init_vardefs
42 temp_trap_init
43 DBDIR=/var/tmp/${APPNAME}.db
44 CONFFILE=${MYPREFIX}/etc/${APPNAME}.conf
45 PKGTOOLSCONF=${MYPREFIX}/etc/pkgtools.conf
46
47 # ==================================================
48 # ========= PARSING OPTIONS AND ARGUMENTS ==========
49 # ==================================================
50
51 # ============= Save arguments for upgraded restart =============
52 options_dump_args "$@" > ${TMPDIR}/restart_command.sh
53
54 # ============= Option check =============
55 options_set_default
56
57 options_getopts "$@" || :
58 if [ $OPTIONS_ERRNO -eq 2 ]
59 then
60         message_echo "INTERNAL ERROR: In parsing options" >&2
61         exit 1
62 fi
63 shift "${OPTIONS_SHIFT}"
64
65 # ============= Argument check for no-command options =============
66 if [ $opt_help_mode -ne 0 -o $opt_show_version = yes ]
67 then
68         if [ $# -gt 0 ]
69         then
70                 OPTIONS_ERRNO=1
71         fi
72 fi
73
74 # ============= Output usage if the case of a help mode or option/argument errors =============
75 if [ $OPTIONS_ERRNO -ne 0 ]
76 then
77         exit $OPTIONS_ERRNO
78 elif [ $opt_help_mode -eq 1 ]
79 then
80         usage_short
81         exit
82 elif [ $opt_help_mode -eq 2 ]
83 then
84         usage_long | less -r
85         exit
86 fi
87
88 # ============= Output version number =============
89 if [ $opt_show_version = yes ]
90 then
91         message_version
92         exit
93 fi
94
95 # ============= Set up variables for environment of ports and packages =============
96 conf_setup_ports_envs
97 conf_setup_packages_envs
98
99 # ============= Execute command operations before getting the temporary database ready =============
100 command_exec_before_db_creation "$@"
101
102 # ============= Creation of temporary database directory =============
103 database_build_create
104
105 # ============= Argument check for conventional runs =============
106 command_parse_args "$@"
107 shift "${COMMAND_SHIFT}"
108
109
110 # ==================================================
111 # ================== TOOLS SET UP ==================
112 # ==================================================
113
114 # ============= Termination messages during construction of the temporary database =============
115
116 # Set termination messages
117 temp_terminate_process_common ()
118 {
119         local msg_where
120         [ $opt_batch_mode = yes ] && return
121         msg_where=`temp_get_msg_current_stage`
122         [ -n "$msg_where" ] && msg_where=" during $msg_where"
123         echo
124         if [ $errno -eq 130 ]
125         then
126                 echo "INFO: Terminated at `message_timestamp`$msg_where."
127                 echo
128                 echo " You can restart this process from the terminated point by"
129         else
130                 echo "INFO: Aborted at `message_timestamp`$msg_where."
131                 echo
132                 echo " You may restart this process from the aborted point by"
133         fi
134         echo "executing without options or arguments as:"
135         if [ -n "$COMMAND_RESTART" ]
136         then
137                 echo "  ${APPNAME} $COMMAND_RESTART"
138         else
139                 echo "  ${APPNAME}"
140         fi
141 }
142
143 temp_terminate_process ()
144 {
145         local tmp_msg
146         tmp_msg=${TMPDIR}/temp_terminate_process:msg
147         [ $errno -eq 0 -o $opt_batch_mode = yes ] && return
148         temp_terminate_process_common
149         [ -n "$COMMAND_RESTART" ] && return
150         cat > $tmp_msg << eof
151  Instead, if you only want to construct the temporary database so as to stop before the actual reinstallation, execute as:
152   ${APPNAME} prepare
153 eof
154         message_cat "$tmp_msg"
155 }
156
157 # ============= Opening title =============
158
159 message_credit
160 [ $COMMAND_MODE = do -o $COMMAND_MODE = redo -o $COMMAND_MODE = forget ] && \
161         message_opening_notice
162 message_echo
163
164 # ============= Execute command operations which do not need package tools =============
165
166 command_exec_without_pkgtools "$@"
167 misc_is_superuser_privilege && touch "${DBDIR}/in_use"
168
169 # ============= Definition of environment dependent functions =============
170
171 pkgsys_def_pkgtools
172
173 # ============= Option settings =============
174
175 # Execute command operations which are not affected by saved option settings
176 command_exec_irrespective_of_saved_options "$@"
177
178 # Load, renew and save option values
179 optcomb_err=0
180 options_chk_invalid_optvals_renewal non_renewable || optcomb_err=$?
181 if [ \( $opt_reload_conf = yes -o $opt_reset_targets = yes \) -a "x$COMMAND_MODE" != xredo ]
182 then
183         message_echo "ERROR: Options -L and -N are available only in the initial run of redo command." >&2
184         message_echo >&2
185         optcomb_err=1
186 fi
187 if [ $opt_batch_ports_only = yes -a $opt_interactive_ports_only = yes ]
188 then
189         message_echo "ERROR: Options -A and -I conflict with each other." >&2
190         message_echo >&2
191         optcomb_err=1
192 fi
193 if [ -e "${DBDIR}/saved_options.sh" ]
194 then
195         {
196                 options_renewed_optvals M renewable_anytime || optcomb_err=$?
197                 options_renewed_optvals N renewable_in_redo_on_target || optcomb_err=$?
198                 options_renewed_optvals L renewable_in_redo_on_conf || optcomb_err=$?
199         } > ${TMPDIR}/renewed_optvals.sh
200         [ $optcomb_err -eq 0 ] || exit $optcomb_err
201         . "${DBDIR}/saved_options.sh"
202         . "${TMPDIR}/renewed_optvals.sh"
203 fi
204 misc_is_superuser_privilege && misc_get_all_vardefs | options_filter saved > ${DBDIR}/saved_options.sh
205
206 # Show option values
207 if [ -e "${DBDIR}/saved_options.sh" -a $opt_batch_mode = no \
208         -a \( $COMMAND_MODE = do -o $COMMAND_MODE = redo \) ]
209 then
210         message_echo "INFO: List of option values:"
211         message_echo "-----------------------------------------"
212         message_cat "${DBDIR}/saved_options.sh"
213         message_echo "-----------------------------------------"
214         message_echo
215 fi
216
217 # ============= Configurations =============
218
219 # Save the previous configuration if exists
220 PROGRAM_DEPENDS=''
221 _program_exec_and_record_completion__operation ()
222 {
223         rm -rf "${DBDIR}/conf.prev"
224         [ -d "${DBDIR}/conf" ] && \
225                 cp -Rp "${DBDIR}/conf" "${DBDIR}/conf.prev"
226         :
227 }
228 program_exec_and_record_completion SAVE_PREV_CONF
229
230 # Get complete configuration variable definitions by importing pkgtools.conf(5) if available
231 PROGRAM_DEPENDS='SAVE_PREV_CONF'
232 _program_exec_and_record_completion__operation ()
233 {
234         local need_msg
235         need_msg=no
236         rm -rf "${DBDIR}/conf"
237         mkdir -p "${DBDIR}/conf"
238         [ "x`options_get_effective_opt_load_pkgtoolsconf 2> /dev/null`" != xno -a $opt_batch_mode = no ] \
239                 && need_msg=yes
240         [ $need_msg = yes ] && \
241                 message_section_title "Parsing pkgtools.conf (by using installed portupgrade)"
242         conf_get_complete_var_defs > ${DBDIR}/conf/complete_setup.sh
243         [ $need_msg = yes ] &&  { message_echo "===> ok"; message_echo; }
244         :
245 }
246 program_exec_and_record_completion GET_COMPLETE_CONF_VAR_DEF
247
248 # Parse the configuration
249 PROGRAM_DEPENDS='GET_COMPLETE_CONF_VAR_DEF'
250 _program_exec_and_record_completion__operation ()
251 {
252         message_section_title "Parsing the configuration"
253         conf_manipulate_available_var_defs
254         . "${DBDIR}/conf/manipulated_defs.sh"
255         # ALT_MOVED_*
256         conf_build_effective_MOVED
257         # Environmental variables
258         conf_setup_effective_env > ${DBDIR}/conf/setenv.sh
259         . "${DBDIR}/conf/setenv.sh"
260         # HOLD_*
261         conf_parse_vars_for_each_port_glob HOLD
262         str_escape_regexp_filter < ${DBDIR}/conf/HOLD:PORTS.parsed \
263                 | sed 's/^/^/;s/$/$/' > ${DBDIR}/conf/HOLD_PORTS.grep_pattern
264         # TABOO_*
265         conf_parse_vars_for_each_port_glob TABOO
266         fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" \
267                 > ${DBDIR}/taboo.all.list
268         # NOPKG_*
269         conf_parse_vars_for_each_port_glob NOPKG
270         # REPLACE_*
271         conf_build_replacement_patterns_from_REPLACE
272         # MARG_*
273         conf_parse_vars_for_each_port_glob_with_bound_val MARG TARGET DEF
274         # MENV_*
275         conf_parse_vars_for_each_port_glob_with_bound_val MENV TARGET DEF
276         # BEFOREBUILD_*
277         conf_parse_vars_for_each_port_glob_with_bound_val BEFOREBUILD TARGET COMMAND
278         # BEFOREDEINSTALL_*
279         conf_parse_vars_for_each_port_glob_with_bound_val BEFOREDEINSTALL TARGET COMMAND
280         # AFTERINSTALL_*
281         conf_parse_vars_for_each_port_glob_with_bound_val AFTERINSTALL TARGET COMMAND
282         message_echo
283 }
284 program_exec_and_record_completion PARSE_CONF
285
286 . "${DBDIR}/conf/setenv.sh"
287
288 # ============= Upgrade of tools =============
289
290 # Execute command operations which should be done without upgrade of tools
291 command_exec_before_tools_upgrade "$@"
292
293 # Check whether the temporary database is newer than the ports tree and refresh if so
294 database_build_refresh_if_obsolete
295
296 # Get the port origin for this utility if installed by port
297 MYPORTORIGIN=`pkgsys_get_my_origin 2> /dev/null` || :
298
299 # Collect all installed packages
300 PROGRAM_DEPENDS=''
301 _program_exec_and_record_completion__operation ()
302 {
303         local tmp_installed_ports tmp_installed_pkgs
304         message_section_title "Collecting all installed packages"
305         if [ -e "${DBDIR}/installed_ports.inspected" ]
306         then
307                 if ! [ "${DBDIR}/installed_ports" -ot "${DBDIR}/initial" -a "${DBDIR}/installed_ports:pkg_vs_origin.tbl" -ot "${DBDIR}/initial" ]
308                 then
309                         find "${DBDIR}/initial" -depth 2 -type d \
310                                 | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/installed_ports || :
311                         while read origin
312                         do
313                                 pkg=`cat "${DBDIR}/initial/$origin/installed_version" 2>/dev/null` || continue
314                                 printf '%s\t%s\n' "$origin" "$pkg"
315                         done < ${DBDIR}/installed_ports > ${DBDIR}/installed_ports:pkg_vs_origin.tbl
316                 fi
317         else
318                 pkg_info_qoa > ${DBDIR}/installed_ports
319                 pkg_info_gen_pkg_origin_table
320         fi
321         str_escape_regexp_filter < "${DBDIR}/installed_ports" \
322                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/installed_ports.grep_pattern
323         message_echo
324 }
325 program_exec_and_record_completion COLLECT_ALL_INSTALLED_PACKAGES
326
327 # Preliminary inspection of tools which have to be up-to-date
328 # (No need depend on PARSE_CONF because INSPECT_ALL_DEPENDENCIES will take the task.)
329 PROGRAM_DEPENDS=
330 _program_exec_restartable_loop_operation__routine ()
331 {
332         local origin
333         origin=$1
334         database_build_inspect_dependencies "$origin"
335 }
336 _program_exec_and_record_completion__operation ()
337 {
338         local DEPTH_INDEX
339         message_section_title "Preliminary inspection of tools which have to be up-to-date"
340         {
341                 [ "$PKGSYS_USE_PKGNG" = yes ] && echo 'ports-mgmt/pkg'
342                 pkgsys_is_dialog4ports_used && echo 'ports-mgmt/dialog4ports'
343                 [ -n "$MYPORTORIGIN" ] && echo "$MYPORTORIGIN"
344         } 2> /dev/null > ${DBDIR}/stage.loop_list/tools_to_inspect
345         DEPTH_INDEX='--'
346         program_exec_restartable_loop_operation tools_to_inspect
347         database_build_post_inspect_dependencies
348         message_echo
349 }
350 program_exec_and_record_completion PRELIMINARY_INSPECTION_OF_TOOLS
351
352 # Upgrade of ports-mgmt/pkg if new
353 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
354 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
355         -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no \
356         -a "$PKGSYS_USE_PKGNG" = yes ]
357 then
358         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
359         _program_exec_and_record_completion__operation ()
360         {
361                 local _MSG_CURRENT_STAGE_general
362                 _MSG_CURRENT_STAGE_general="pkgng upgrade"
363                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
364                 message_section_title "Upgrade of ports-mgmt/pkg if new"
365                 touch "${DBDIR}/target_all"
366                 reinstall_exec ports-mgmt/pkg
367                 reinstall_restore_conflicts
368                 rm -f "${DBDIR}/target_all"
369                 temp_set_msg_current_stage
370                 message_echo
371         }
372         program_exec_and_record_completion UPGRADE_PKGNG
373 fi
374
375 # Upgrade of ports-mgmt/dialog4ports if new
376 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
377 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
378         -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no ] \
379         && pkgsys_is_dialog4ports_used
380 then
381         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
382         _program_exec_and_record_completion__operation ()
383         {
384                 local _MSG_CURRENT_STAGE_general
385                 _MSG_CURRENT_STAGE_general="pkgng dialog4ports"
386                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
387                 message_section_title "Upgrade of dialog4ports if new"
388                 touch "${DBDIR}/target_all"
389                 reinstall_exec ports-mgmt/dialog4ports
390                 reinstall_restore_conflicts
391                 rm -f "${DBDIR}/target_all"
392                 temp_set_msg_current_stage
393                 message_echo
394         }
395         program_exec_and_record_completion UPGRADE_DIALOG4PORTS
396 fi
397
398 # Upgrade of this utility if new
399 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
400 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
401         -a $opt_dry_run = no -a $opt_suppress_self_upadte = no \
402         -a -n "$MYPORTORIGIN" ]
403 then
404         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
405         _program_exec_and_record_completion__operation ()
406         {
407                 local _MSG_CURRENT_STAGE_general
408                 _MSG_CURRENT_STAGE_general="pkgng upgrade"
409                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
410                 message_section_title "Upgrade of this utility if new"
411                 touch "${DBDIR}/target_all"
412                 reinstall_exec "$MYPORTORIGIN"
413                 reinstall_restore_conflicts
414                 rm -f "${DBDIR}/target_all"
415                 temp_set_msg_current_stage
416                 message_echo
417         }
418         program_exec_and_record_completion UPGRADE_SELF
419 fi
420
421 if [ "x`${APPNAME} -aV 2> /dev/null`" != "x$MYVERSION" ]
422 then
423         message_echo "INFO: ${APPNAME} is upgraded and the temporary database needs refresh."
424         database_build_clean_for_self_upgrade || :
425         message_echo "INFO: Restarting with the new version."
426         message_echo
427         temp_trap_for_invoking_new_version
428         . "${TMPDIR}"/restart_command.sh
429         exit
430 fi
431
432
433 # ==================================================
434 # ================== PREPARATION ===================
435 # ==================================================
436
437 # ============= Correspondence to configuration changes =============
438
439 # Patch to the temporary database by reflecting changes in configuration
440 PROGRAM_DEPENDS='PARSE_CONF'
441 _program_exec_and_record_completion__operation ()
442 {
443         local tmpfile_diff tmpfile_old tmpfile_new key
444         [ -d "${DBDIR}/conf.prev" ] || return 0
445         message_section_title "Patch to the temporary database by reflecting changes in configuration"
446         tmpfile_old=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::old
447         tmpfile_new=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::new
448         tmpfile_updated_ports=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::updated_ports
449         if fileedit_manipulate_old_new_lines \
450                 "${DBDIR}/conf.prev/setenv.sh" "${DBDIR}/conf/setenv.sh" "$tmpfile_old" "$tmpfile_new"
451         then
452                 if grep -q -e ^LOCALBASE= -e ^LINUXBASE= -e ^PORTSDIR= "$tmpfile_old" "$tmpfile_new"
453                 then
454                         message_echo "ERROR: Migration of the temporary database is unavailable because LOCALBASE, LINUXBASE or PORTSDIR was changed." >&2
455                         message_echo "        ${APPNAME} clean" >&2
456                         message_echo "must be executed in advance." >&2
457                         exit 1
458                 fi
459         fi
460         cut -s -d '|' -f 1,2 "${DBDIR}/conf.prev/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.old
461         cut -s -d '|' -f 1,2 "${DBDIR}/conf/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.new
462         if fileedit_manipulate_old_new_lines \
463                 "${TMPDIR}/MOVED_ALT.old" "${TMPDIR}/MOVED_ALT.new" "$tmpfile_old" "$tmpfile_new"
464         then
465                 cat "$tmpfile_old" "$tmpfile_new" | while read from to
466                 do
467                         echo "$from"
468                         [ -n "$to" ] && echo "$to"
469                 done
470         fi > $tmpfile_updated_ports
471         if fileedit_manipulate_old_new_lines \
472                 "${DBDIR}/conf.prev/REPLACE.csv" "${DBDIR}/conf/REPLACE.csv" "$tmpfile_old" "$tmpfile_new"
473         then
474                 cat "$tmpfile_old" "$tmpfile_new" | while read from to
475                 do
476                         echo "$from"
477                         [ -n "$to" ] && echo "$to"
478                 done
479         fi >> $tmpfile_updated_ports
480         [ `wc -l < $tmpfile_updated_ports` -gt 0 ] && rm -f "${DBDIR}/REPLACE.complete_sed_pattern"
481         [ -d "${DBDIR}/conf/each_port" ] && find "${DBDIR}/conf/each_port" -depth 2 \
482                 | while read dbpath
483         do
484                 origin=`str_dirpath_to_origin "$dbpath"`
485                 dbpath_prev=${DBDIR}/conf.prev/each_port/$origin
486                 diff -r "$dbpath_prev" "$dbpath" > /dev/null 2>&1 && continue
487                 echo "$origin"
488         done >> $tmpfile_updated_ports
489         [ -d "${DBDIR}/conf.prev/each_port" ] && find "${DBDIR}/conf.prev/each_port" -depth 2 \
490                 | while read dbpath_prev
491         do
492                 origin=`str_dirpath_to_origin "$dbpath_prev"`
493                 dbpath=${DBDIR}/conf/each_port/$origin
494                 [ -d "$dbpath" ] && continue
495                 echo "$origin"
496         done >> $tmpfile_updated_ports
497         if [ `wc -l < $tmpfile_updated_ports` -gt 0 ]
498         then
499                 sort -u "$tmpfile_updated_ports" | while read origin
500                 do
501                         database_build_patch_reconf "$origin"
502                 done
503                 program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
504         fi
505         message_echo
506 }
507 program_exec_and_record_completion PATCH_TO_TMPDB_REFLECT_CONF_CHANGES
508
509 # ============= Database construction =============
510
511 # Execute command operations which must be done before building the temporary database
512 command_exec_before_building_tempdb "$@"
513
514 # Meta process for redo
515 PROGRAM_DEPENDS=''
516 _program_exec_and_record_completion__operation ()
517 {
518         rm -f "${DBDIR}/new_success_in_current_run"
519         [ "x$COMMAND_MODE" = xredo ] || return 0
520         message_echo "[REDO mode]"
521         message_echo
522 }
523 program_exec_and_record_completion REDO_INIT
524
525 # Determine specified targets
526 PROGRAM_DEPENDS=''
527 _program_exec_and_record_completion__operation ()
528 {
529         local tag level dbsuffix
530         message_section_title "Determining specified targets"
531         cat "${DBDIR}/stage.loop_list/target_itself.specified" \
532                 "${DBDIR}/stage.loop_list/target_dependents.specified" \
533                 "${DBDIR}/stage.loop_list/target_requirements.specified" \
534                 "${DBDIR}/need.list" \
535                 "${DBDIR}/targets_specified_so_far" 2> /dev/null \
536                 | sort -u > ${DBDIR}/targets_specified_so_far.tmp
537         mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
538         rm -f "${DBDIR}/stage.loop_list/target_itself.specified" \
539                 "${DBDIR}/stage.loop_list/target_dependents.specified" \
540                 "${DBDIR}/stage.loop_list/target_requirements.specified"
541         if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
542         then
543                 options_select_new_ports_if_duplicated O \
544                         "${DBDIR}/stage.loop_list/target_itself.specified" "$opt_target_itself"
545                 options_select_new_ports_if_duplicated t \
546                         "${DBDIR}/stage.loop_list/target_dependents.specified" "$opt_target_dependents"
547                 options_select_new_ports_if_duplicated T \
548                         "${DBDIR}/stage.loop_list/target_requirements.specified" "$opt_target_requirements"
549                 if [ `cat "${DBDIR}/stage.loop_list/target_itself.specified" \
550                         "${DBDIR}/stage.loop_list/target_dependents.specified" \
551                         "${DBDIR}/stage.loop_list/target_requirements.specified" | wc -l` -eq 0 ]
552                 then
553                         message_echo "ERROR: No matching port for target globs." >&2
554                         message_echo >&2
555                         exit 1
556                 fi
557                 cat "${DBDIR}/stage.loop_list/target_itself.specified" \
558                         "${DBDIR}/stage.loop_list/target_dependents.specified" \
559                         "${DBDIR}/stage.loop_list/target_requirements.specified" \
560                         | sort -u > ${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset
561                 cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset" "${DBDIR}/need.list" 2> /dev/null \
562                         | sort -u > ${DBDIR}/need.list.tmp
563                 mv "${DBDIR}/need.list.tmp" "${DBDIR}/need.list"
564                 sort -u "${DBDIR}/need.list" "${DBDIR}/targets_specified_so_far" \
565                         > ${DBDIR}/targets_specified_so_far.tmp
566                 mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
567                 for tag in all run build none
568                 do
569                         for level in direct full
570                         do
571                                 dbsuffix=$tag.$level
572                                 {
573                                         cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset"
574                                         cat "${DBDIR}/stage.loop_list/target_dependents.specified" | while read origin
575                                         do
576                                                 nodedir=${DBDIR}/requires/$origin
577                                                 cat "$nodedir/dependents.$dbsuffix" 2> /dev/null
578                                         done
579                                         cat "${DBDIR}/stage.loop_list/target_requirements.specified" | while read origin
580                                         do
581                                                 nodedir=${DBDIR}/requires/$origin
582                                                 cat "$nodedir/requirements.$dbsuffix" 2> /dev/null
583                                         done
584                                 } | sort -u | while read origin
585                                 do
586                                         fileedit_rm_a_line "$origin" "${DBDIR}/success.$dbsuffix.list"
587                                         fileedit_rm_a_line "$origin" "${DBDIR}/todo_after_requirements_succeed.$dbsuffix.list"
588                                         rm -f "${DBDIR}/requires/$origin/succeeded_once"
589                                 done
590                         done
591                 done
592         fi
593         message_echo
594 }
595 program_exec_and_record_completion DETERMINE_SPECIFIED_TARGETS
596
597 # Show specified targets
598 if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" -a $opt_batch_mode = no ]
599 then
600         message_echo "INFO: (Re/de-)installation will be carried out only for the targets:"
601         echo
602         if [ `wc -l < ${DBDIR}/stage.loop_list/target_itself.specified` -gt 0 ]
603         then
604                 message_echo "[Targets only]"
605                 echo "----------------------------------------"
606                 cat "${DBDIR}/stage.loop_list/target_itself.specified"
607                 echo "----------------------------------------"
608                 echo
609         fi
610         if [ `wc -l < ${DBDIR}/stage.loop_list/target_dependents.specified` -gt 0 ]
611         then
612                 message_echo "[Targets with their `options_get_dependency_msgterm` dependents]"
613                 echo "----------------------------------------"
614                 cat "${DBDIR}/stage.loop_list/target_dependents.specified"
615                 echo "----------------------------------------"
616                 echo
617         fi
618         if [ `wc -l < ${DBDIR}/stage.loop_list/target_requirements.specified` -gt 0 ]
619         then
620                 message_echo "[Targets with their `options_get_dependency_msgterm` requirements]"
621                 echo "----------------------------------------"
622                 cat "${DBDIR}/stage.loop_list/target_requirements.specified"
623                 echo "----------------------------------------"
624                 echo
625         fi
626 fi
627
628 # Determine all target ports
629 PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS COLLECT_ALL_INSTALLED_PACKAGES'
630 _program_exec_and_record_completion__operation ()
631 {
632         message_section_title "Determining all target ports"
633         {
634                 if [ $opt_only_target_scope = no ]
635                 then
636                         cat "${DBDIR}/installed_ports" 2> /dev/null || :
637                 fi
638                 cat "${DBDIR}/stage.loop_list/target_itself.specified" || :
639                 cat "${DBDIR}/stage.loop_list/target_dependents.specified" || :
640                 cat "${DBDIR}/stage.loop_list/target_requirements.specified" || :
641                 cat "${DBDIR}/targets_specified_so_far" || :
642         }  2> /dev/null | sort -u > "${DBDIR}/stage.loop_list/ports_to_inspect"
643         message_echo
644 }
645 program_exec_and_record_completion DETERMINE_ALL_TARGET_PORTS
646
647 # Inspection of all dependencies
648 PROGRAM_DEPENDS='PARSE_CONF DETERMINE_ALL_TARGET_PORTS'
649 _program_exec_restartable_loop_operation__routine ()
650 {
651         local origin
652         origin=$1
653         database_build_inspect_dependencies "$origin"
654 }
655 _program_exec_and_record_completion__operation ()
656 {
657         local DEPTH_INDEX 
658         message_section_title "Inspecting dependencies of the all installed packages"
659         [ $opt_only_target_scope = no -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ] && \
660                 message_echo "INFO: Ports which seem irrelevant to the targets are also inspected in order to get complete information."
661         DEPTH_INDEX='--'
662         program_exec_restartable_loop_operation ports_to_inspect
663         database_build_post_inspect_dependencies
664         message_echo
665 }
666 program_exec_and_record_completion INSPECT_ALL_DEPENDENCIES
667
668 # Convert dependency-lists to actual ones
669 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES'
670 _program_exec_restartable_loop_operation__routine ()
671 {
672         local origin table dbtag level tag target
673         origin=$1
674         for table in dependents requirements
675         do
676                 for dbtag in requires obsolete
677                 do
678                         for level in direct full
679                         do
680                                 for tag in all run build
681                                 do
682                                         target=${DBDIR}/$dbtag/$origin/${table}.${tag}.${level}
683                                         if [ -e "$target.src" ]
684                                         then
685                                                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "$target.src" \
686                                                         | grep -v '^$' | sort -u > $target.tmp
687                                                 [ -e "$target" ] && ! diff "$target.tmp" "$target" > /dev/null \
688                                                         && echo "$origin" >> ${DBDIR}/update_dependencies
689                                                 mv "$target.tmp" "$target"
690                                         else
691                                                 [ -e "$target" ] && echo "$origin" >> ${DBDIR}/update_dependencies
692                                                 rm -f "$target"
693                                         fi
694                                 done
695                         done
696                 done
697         done
698 }
699 _program_exec_and_record_completion__operation ()
700 {
701         message_section_title "Conversion of dependency-lists to actual ones"
702         program_exec_restartable_loop_operation convert_dependency_lists
703         sort -u "${DBDIR}/update_dependencies" > ${DBDIR}/update_dependencies.tmp
704         mv "${DBDIR}/update_dependencies.tmp" "${DBDIR}/update_dependencies"
705         str_escape_regexp_filter < ${DBDIR}/update_dependencies \
706                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/update_dependencies.grep_pattern
707         for tag in all run build
708         do
709                 ( cd "${DBDIR}/requires" && \
710                         find . -depth 3 -type f -name requirements.${tag}.full -or -name requirements.${tag}.full.orig ) \
711                         | sort -u \
712                         | sed 's|^./||;s|/[^/]*$||' \
713                         | grep -v -E -f "${DBDIR}/update_dependencies.grep_pattern" \
714                         | str_escape_regexp_filter | sed 's/^/^/; s/$/$/' \
715                         > ${TMPDIR}/convert_requirements_list:full_complete.grep_pattern || :
716                 ( cd "${DBDIR}/requires" && \
717                         find . -depth 3 -type f -name requirements.${tag}.direct -or -name requirements.${tag}.direct.orig ) \
718                         | sort -u \
719                         | sed 's|^./||;s|/[^/]*$||' \
720                         | grep -v -E -f "${TMPDIR}/convert_requirements_list:full_complete.grep_pattern" \
721                         > ${DBDIR}/stage.loop_list/complete_recursive_${tag}time_reqlists || :
722         done
723         for inspected_level_tmp in direct node
724         do
725                 cat "${DBDIR}/ports.inspected.${inspected_level_tmp}.list" || :
726         done 2> /dev/null | sort -u > ${DBDIR}/stage.loop_list/trim_dependency_lists_rm_uninspected_ports
727         find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/stage.loop_list/inspect_dependent
728         [ -e "${DBDIR}/dependents_files" ] && \
729                 mv "${DBDIR}/dependents_files" "${DBDIR}/dependents_files.prev"
730         rm -f "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" "${DBDIR}/dependents_files.tmp"
731         message_echo
732 }
733 program_exec_and_record_completion CONVERT_REQUIREMENTS_LIST
734
735 # Completion of recursive requirement lists
736 for _REQUIREMENT_LISTS_tag in all run build
737 do
738         PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
739         _program_exec_restartable_loop_operation__routine ()
740         {
741                 local tag dbpath origin suffix
742                 tag=${_REQUIREMENT_LISTS_tag}
743                 dbpath=$1
744                 origin=`str_dirpath_to_origin "$dbpath"`
745                 for suffix in '' .orig
746                 do
747                         database_build_get_complete_recursive_dependency requirements.${tag} "$origin" "$suffix" > /dev/null
748                 done
749         }
750         _program_exec_and_record_completion__operation ()
751         {
752                 local tag
753                 tag=${_REQUIREMENT_LISTS_tag}
754                 message_section_title "Completion of ${tag}-time requirement lists"
755                 program_exec_restartable_loop_operation complete_recursive_${tag}time_reqlists
756                 message_echo
757         }
758         program_exec_and_record_completion RECURSIVE_REQUIREMENT_LISTS:${_REQUIREMENT_LISTS_tag}
759 done
760
761 # Trim dependency lists by removing uninspected ports
762 if [ $opt_only_target_scope = yes ]
763 then
764         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST'
765         _program_exec_restartable_loop_operation__routine ()
766         {
767                 local dbpath tag level srcdb
768                 dbpath=$1
769                 for tag in all run build
770                 do
771                         for level in direct full
772                         do
773                                 srcdb=requirements.${tag}.${level}
774                                 [ -e "$dbpath/$srcdb" ] || continue
775                                 grep -E -f "${DBDIR}/inspected_ports.grep_pattern" "$dbpath/$srcdb" \
776                                         > $dbpath/$srcdb.tmp || :
777                                 mv "$dbpath/$srcdb.tmp" "$dbpath/$srcdb"
778                         done
779                 done
780         }
781         _program_exec_and_record_completion__operation ()
782         {
783                 message_section_title "Trimming dependency lists by removing uninspected ports"
784                 program_exec_restartable_loop_operation trim_dependency_lists_rm_uninspected_ports
785                 message_echo
786         }
787         program_exec_and_record_completion TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS
788 fi
789
790 # Inspection of dependents
791 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS'
792 _program_exec_restartable_loop_operation__routine ()
793 {
794         local dbpath origin tag level suffix srcdb dstdb
795         dbpath=$1
796         origin=`str_dirpath_to_origin "$dbpath"`
797         for tag in all run build
798         do
799                 for level in direct full
800                 do
801                         for suffix in '' .orig
802                         do
803                                 srcdb=requirements.${tag}.${level}${suffix}
804                                 dstdb=dependents.${tag}.${level}${suffix}
805                                 [ -e "$dbpath/$srcdb" ] || continue
806                                 while read origin_requirement
807                                 do
808                                         dstpath=${DBDIR}/requires/$origin_requirement
809                                         echo "$dstpath/$dstdb" >> ${DBDIR}/dependents_files.tmp
810                                         [ "$dstpath/$dstdb" -nt "$dbpath/$srcdb" ] && continue
811                                         [ -d "$dstpath" ] || mkdir -p "$dstpath"
812                                         echo "$origin" >> $dstpath/$dstdb.raw
813                                         echo "$dstpath/$dstdb" >> ${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp
814                                 done < $dbpath/$srcdb
815                         done
816                 done
817         done
818 }
819 _program_exec_and_record_completion__operation ()
820 {
821         local dbrequires_valesc
822         message_section_title "Inspection of dependents"
823         dbrequires_valesc=`str_escape_replaceval "${DBDIR}/requires/"`
824         program_exec_restartable_loop_operation inspect_dependent
825         sort -u "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" 2> /dev/null \
826                 > ${DBDIR}/stage.loop_list/make_dependents_lists_unique || :
827         sort -u "${DBDIR}/dependents_files.tmp" 2> /dev/null > ${DBDIR}/dependents_files || :
828         [ -e "${DBDIR}/make_dependents_lists_unique.prev" ] && \
829                 fileedit_manipulate_old_lines "${DBDIR}/dependents_files.prev" "${DBDIR}/dependents_files" \
830                 | xargs rm -f
831         message_echo
832 }
833 program_exec_and_record_completion INSPECT_DEPENDENTS
834
835 # Remove duplicated lines in dependents lists
836 PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST INSPECT_DEPENDENTS'
837 _program_exec_restartable_loop_operation__routine ()
838 {
839         local dbpath tag level dstdb
840         dstdb=$1
841         cat "$dstdb" "$dstdb.raw" 2> /dev/null | sort -u > $dstdb.tmp
842         mv "$dstdb.tmp" "$dstdb"
843         rm -f "$dstdb.raw"
844 }
845 _program_exec_and_record_completion__operation ()
846 {
847         local dbrequires_valesc
848         message_section_title "Removing duplicated items in dependents lists"
849         program_exec_restartable_loop_operation make_dependents_lists_unique
850         message_echo
851 }
852 program_exec_and_record_completion MAKE_DEPENDENTS_LISTS_UNIQUE
853
854 # Preparation of target attribute information
855 for _TARGET_ATTR_INFO_table in requirements dependents itself
856 do
857         [ `cat "${DBDIR}/stage.loop_list/target_${_TARGET_ATTR_INFO_table}.replaced.specified" 2> /dev/null \
858                 | wc -l` -gt 0 ] || continue
859         PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS CONVERT_REQUIREMENTS_LIST'
860         _program_exec_restartable_loop_operation__routine ()
861         {
862                 local origin dbtargets_valesc table
863                 origin=$1
864                 dbtargets_valesc=`str_escape_replaceval "${DBDIR}/targets/"`
865                 table=${_TARGET_ATTR_INFO_table}
866                 for database in requires initial
867                 do
868                         dbpath=${DBDIR}/$database/$origin
869                         dstpath=${DBDIR}/targets/$origin
870                         [ -d "$dstpath" ] || mkdir -p "$dstpath"
871                         touch "$dstpath/target_itself"
872                         echo "$origin" >> ${DBDIR}/all_targets.lst
873                         [ $table = itself ] && continue
874                         for tag in all run build
875                         do
876                                 for level in direct full
877                                 do
878                                         srcdb=${table}.${tag}.${level}
879                                         dstdb=target_${database}_${table}.${tag}.${level}
880                                         [ -e "$dbpath/$srcdb" ] || continue
881                                         cat "$dbpath/$srcdb" >> ${DBDIR}/all_targets.lst
882                                         sed -E "s/^/$dbtargets_valesc/; s|$|/$dstdb|" "$dbpath/$srcdb" \
883                                                 | fileedit_add_a_line_to_files_if_new "$origin"
884                                 done
885                         done
886                 done
887         }
888         _program_exec_and_record_completion__operation ()
889         {
890                 local table
891                 table=${_TARGET_ATTR_INFO_table}
892                 message_section_title "Preparation of target attribute information for dependency [$table]"
893                 program_exec_restartable_loop_operation target_$table.replaced.specified
894                 message_echo
895         }
896         program_exec_and_record_completion TARGET_ATTR_INFO:${_TARGET_ATTR_INFO_table}
897 done
898
899 # Post-process after the preparation of target attribute information
900 PROGRAM_DEPENDS='MAKE_DEPENDENTS_LISTS_UNIQUE TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents'
901 _program_exec_and_record_completion__operation ()
902 {
903         message_section_title "Post-process after the preparation of target attribute information"
904         sort -u "${DBDIR}/all_targets.lst" 2> /dev/null \
905                 | grep -E -f "${DBDIR}/inspected_ports.grep_pattern" \
906                 | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" \
907                 > ${DBDIR}/all_targets.lst.tmp || :
908         mv "${DBDIR}/all_targets.lst.tmp" "${DBDIR}/all_targets.lst"
909         find "${DBDIR}/targets" -depth 2 -type d > ${DBDIR}/stage.loop_list/build_complement_to_new_dependents_for_targets 2> /dev/null || :
910         {
911                 cat "${DBDIR}/all_targets.lst" "${DBDIR}/need.with_replaced.list" 2> /dev/null || :
912                 find "${DBDIR}/requires" -depth 3 -type f -name installed_version \
913                         | sed -E 's|.*/([^/]+/[^/]+)/[^/]*$|\1|'
914         } | sort -u > ${DBDIR}/stage.loop_list/inspect_necessity
915         cp /dev/null "${DBDIR}/stage.loop_list/parse_target_attr_info"
916         find -E "${DBDIR}/requires" -depth 3 -type f -regex '.*/necessary_port\.(direct|full)$' -delete
917         message_echo
918 }
919 program_exec_and_record_completion TARGET_ATTR_INFO_POSTPROCESS
920
921 # Build of data on complement to new dependents for target attribute information
922 PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents CONVERT_REQUIREMENTS_LIST'
923 _program_exec_restartable_loop_operation__routine ()
924 {
925         local dbpath origin
926         dbpath=$1
927         origin=`str_dirpath_to_origin "$dbpath"`
928         database_build_complement_to_new_dependents_for_targets "$origin"
929 }
930 _program_exec_and_record_completion__operation ()
931 {
932         message_section_title "Build of data on complement to new dependents for target attribute information"
933         program_exec_restartable_loop_operation build_complement_to_new_dependents_for_targets
934         sort -u "${DBDIR}/stage.loop_list/parse_target_attr_info" > ${DBDIR}/stage.loop_list/parse_target_attr_info.tmp
935         mv "${DBDIR}/stage.loop_list/parse_target_attr_info.tmp" "${DBDIR}/stage.loop_list/parse_target_attr_info"
936         message_echo
937 }
938 program_exec_and_record_completion COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO
939
940 # Parse target attribute information
941 PROGRAM_DEPENDS='COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO'
942 _program_exec_restartable_loop_operation__routine ()
943 {
944         local dbpath origin
945         dbpath=$1
946         origin=`str_dirpath_to_origin "$dbpath"`
947         database_build_target_attributes "$origin"
948 }
949 _program_exec_and_record_completion__operation ()
950 {
951         message_section_title "Parsing target attribute information"
952         program_exec_restartable_loop_operation parse_target_attr_info
953         message_echo
954 }
955 program_exec_and_record_completion PARSE_TARGET_ATTR_INFO
956
957 # Inspection of necessity
958 PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS RECURSIVE_REQUIREMENT_LISTS:run RECURSIVE_REQUIREMENT_LISTS:build INSPECT_ALL_DEPENDENCIES'
959 _program_exec_restartable_loop_operation__routine ()
960 {
961         local origin
962         origin=$1
963         for level in direct full
964         do
965                 database_build_inspect_necessity_for_only_new_upgrade "$origin" "$level"
966         done
967 }
968 _program_exec_and_record_completion__operation ()
969 {
970         message_section_title "Inspection of necessity"
971         program_exec_restartable_loop_operation inspect_necessity
972         for level in direct full
973         do
974                 find "${DBDIR}/requires" -depth 3 -type f -name "necessary_port.${level}" \
975                         > ${DBDIR}/stage.loop_list/necessary_ports.${level}
976         done
977         message_echo
978 }
979 program_exec_and_record_completion INSPECT_NECESSITY
980
981 # Inspection of necessary upgrades
982 for _NECESSARY_UPDATES_level in direct full
983 do
984         PROGRAM_DEPENDS='INSPECT_NECESSITY INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE'
985         _program_exec_restartable_loop_operation__routine ()
986         {
987                 local markerpath level dbpath origin tag
988                 markerpath=$1
989                 level=${_NECESSARY_UPDATES_level}
990                 dbpath=`dirname "$markerpath"`
991                 origin=`str_dirpath_to_origin "$dbpath"`
992                 database_query_does_a_port_need_update "$origin" || return 0
993                 for tag in all run build none
994                 do
995                         touch "$dbpath/necessary_upgrade.$tag.${level}"
996                         [ -e "$dbpath/dependents.$tag.${level}" ] || continue
997                         while read origin_dependent
998                         do
999                                 touch "${DBDIR}/requires/$origin_dependent/necessary_upgrade.$tag.${level}"
1000                         done < $dbpath/dependents.$tag.${level}
1001                 done
1002         }
1003         _program_exec_and_record_completion__operation ()
1004         {
1005                 local level
1006                 level=${_NECESSARY_UPDATES_level}
1007                 message_section_title "Inspection of necessary upgrades at the $level level"
1008                 program_exec_restartable_loop_operation necessary_ports.${level}
1009                 message_echo
1010         }
1011         program_exec_and_record_completion NECESSARY_UPDATES:${_NECESSARY_UPDATES_level}
1012 done
1013
1014 # Preparation for inspection of new leaf ports
1015 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1016 then
1017         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PARSE_CONF'
1018         _program_exec_and_record_completion__operation ()
1019         {
1020                 message_section_title "Preparation for inspection of new leaf ports"
1021                 find "${DBDIR}/requires" -depth 3 -type f -name dependents.all.full \
1022                         | sed -E 's|.*/([^/]+/[^/]+)/[^/]+$|\1|' \
1023                         | sort -u > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports
1024                 sort -u "${DBDIR}/inspected_ports" > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports
1025                 fileedit_manipulate_new_lines \
1026                         "${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports" \
1027                         "${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports" \
1028                         | grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" \
1029                         > ${DBDIR}/stage.loop_list/leaf_ports_primary_candidates || :
1030                 cp /dev/null "${DBDIR}/grep.leaf_ports.pattern"
1031                 cp /dev/null "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
1032                 message_echo
1033         }
1034         program_exec_and_record_completion PREPARE_INSPECT_LEAF_PORTS
1035 fi
1036
1037 # Inspection of new primary leaf ports
1038 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1039 then
1040         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PREPARE_INSPECT_LEAF_PORTS PARSE_CONF'
1041         _program_exec_restartable_loop_operation__routine ()
1042         {
1043                 local origin origin_ini origin_esc dbpath origin_req
1044                 origin=$1
1045                 pkgsys_is_pkgtool "$origin" && return
1046                 dbpath=${DBDIR}/requires/$origin
1047                 origin_esc=`str_escape_regexp "$origin"`
1048                 grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
1049                 if ! grep -q -E "^$origin_esc$" "${DBDIR}/noneed.list" 2> /dev/null
1050                 then
1051                         if [ -e "$dbpath/initial_orig" ]
1052                         then
1053                                 origin_ini=`cat "$dbpath/initial_orig"`
1054                                 [ -e "${DBDIR}/initial/$origin_ini/installed_version" \
1055                                         -a `cat "${DBDIR}/initial/$origin_ini/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
1056                                         && return
1057                         fi
1058                         [ -e "${DBDIR}/initial/$origin/installed_version" \
1059                                 -a `cat "${DBDIR}/initial/$origin/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
1060                                 && return
1061                 fi
1062                 if [ -e "$dbpath/requirements.all.full" ]
1063                 then
1064                         grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" "$dbpath/requirements.all.full" | \
1065                                 fileedit_add_lines_if_new "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
1066                 fi
1067                 fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
1068         }
1069         _program_exec_and_record_completion__operation ()
1070         {
1071                 local num_leaves num_leaves_prev
1072                 message_section_title "Inspection of new primary leaf ports"
1073                 program_exec_restartable_loop_operation leaf_ports_primary_candidates
1074                 wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' ' > ${DBDIR}/num_leaves
1075                 cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
1076                 message_echo "  `cat "${DBDIR}/num_leaves"` primary leaf port(s) is/are found."
1077                 message_echo
1078         }
1079         program_exec_and_record_completion INSPECT_PRIMARY_LEAF_PORTS
1080 fi
1081
1082 # Inspection of requirements of new leaf ports
1083 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1084 then
1085         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE INSPECT_PRIMARY_LEAF_PORTS PARSE_CONF'
1086         _program_exec_and_record_completion__operation ()
1087         {
1088                 local num_leaves num_leaves_prev num_inspect num_leaves_new
1089                 message_section_title "Inspection of requirements of new leaf ports"
1090                 message_echo "INFO: The inspection proceeds by iterative method."
1091                 while :
1092                 do
1093                         _program_exec_restartable_loop_operation__routine ()
1094                         {
1095                                 local origin origin_esc dbpath
1096                                 origin=$1
1097                                 pkgsys_is_pkgtool "$origin" && return
1098                                 dbpath=${DBDIR}/requires/$origin
1099                                 origin_esc=`str_escape_regexp "$origin"`
1100                                 grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
1101                                 grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
1102                                         "$dbpath/dependents.all.full" > /dev/null 2>&1 && return
1103                                 cat "$dbpath/requirements.all.full" 2> /dev/null \
1104                                         >> ${DBDIR}/leaf_ports_secondary_candidates.new_requirements || :
1105                                 fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
1106                         }
1107                         program_exec_restartable_loop_operation leaf_ports_secondary_candidates
1108                         num_leaves_prev=`cat "${DBDIR}/num_leaves"`
1109                         num_leaves=`wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' '`
1110                         num_leaves_new=`echo $(($num_leaves-$num_leaves_prev)) | tr -d ' '`
1111                         if [ $num_leaves_new -eq 0 ]
1112                         then
1113                                 message_echo "  No more leaf port is found."
1114                                 message_echo "  $num_leaves leaf port(s) is/are found in total."
1115                                 break
1116                         fi
1117                         {
1118                                 grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
1119                                         "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
1120                                 cat "${DBDIR}/leaf_ports_secondary_candidates.new_requirements" || :
1121                         } | grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" | sort -u \
1122                                 > ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp || :
1123                         program_reset_loop_for_stage INSPECT_REQUIREMENTS_OF_LEAF_PORTS
1124                         mv "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp" \
1125                                 "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
1126                         cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
1127                         echo "$num_leaves" > ${DBDIR}/num_leaves
1128                         num_inspect=`wc -l < ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates | tr -d ' '`
1129                         message_echo "  $num_leaves_new leaf port(s) is/are newly found; continue for $num_inspect candidate(s)."
1130                 done
1131                 grep -E -f "${DBDIR}/grep.leaf_ports.pattern" "${DBDIR}/inspected_ports" | sort -u > ${DBDIR}/leaf_ports || :
1132                 message_echo
1133         }
1134         program_exec_and_record_completion INSPECT_REQUIREMENTS_OF_LEAF_PORTS
1135 fi
1136
1137 # Order the ports considering dependencies
1138 PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
1139 _program_exec_and_record_completion__operation ()
1140 {
1141         message_section_title "Ordering dependencies"
1142         if ! database_build_order_ports_considering_dependencies
1143         then
1144                 message_echo "ERROR: Unsatisfied dependencies are remained:" >&2
1145                 message_cat "${DBDIR}/unsatisfied.list"
1146                 message_echo "*** Aborted by ${APPNAME}"
1147                 message_echo "The ports tree seems broken. You might have caught an incomplete version."
1148                 message_echo "You are encouraged to update the ports tree by portsnap(8)."
1149                 message_echo "Then execute"
1150                 message_echo " ${APPNAME} clean"
1151                 message_echo "before restart."
1152                 temp_terminate_process () { :; }
1153                 exit 1
1154         fi
1155         message_echo
1156 }
1157 program_exec_and_record_completion ORDER_ALL_DEPENDENCIES
1158
1159 # Selection of removing leaf ports
1160 PROGRAM_DEPENDS='INSPECT_REQUIREMENTS_OF_LEAF_PORTS'
1161 _program_exec_and_record_completion__operation ()
1162 {
1163         message_section_title "Selection of removing leaf ports"
1164         deinstall_select_leaf_ports_to_delete
1165         message_echo
1166 }
1167 program_exec_and_record_completion SELECT_LEAF_PORTS
1168
1169 # Selection of removing obsolete ports
1170 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES PARSE_CONF'
1171 _program_exec_and_record_completion__operation ()
1172 {
1173         message_section_title "Selection of removing obsolete ports"
1174         deinstall_select_obsolete_ports_to_delete
1175         message_echo
1176 }
1177 program_exec_and_record_completion SELECT_OBSOLETE_PORTS
1178
1179 # Collection of leaf ports to delete
1180 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1181 then
1182         PROGRAM_DEPENDS='SELECT_LEAF_PORTS'
1183         _program_exec_and_record_completion__operation ()
1184         {
1185                 local src src_unselected reqptn_file src_with_initial_origins
1186                 message_section_title "Collecting leaf ports to delete"
1187                 src=${DBDIR}/leaf_ports
1188                 src_unselected=${DBDIR}/leaf_ports_to_delete.unselected
1189                 src_with_initial_origins=${DBDIR}/leaf_ports.with_ini
1190                 reqptn_file=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
1191                 cat "$src_unselected" 2> /dev/null | while read origin
1192                 do
1193                         cat "${DBDIR}/requires/$origin/requirements.all.full" || :
1194                 done | sort -u | str_escape_regexp_filter \
1195                         | sed 's/^/^/;s/$/$/' > $reqptn_file
1196                 database_query_add_initial_origins < $src > $src_with_initial_origins
1197                 message_echo
1198         }
1199         program_exec_and_record_completion COLLECT_LEAF_PORTS_TO_DELETE
1200 fi
1201
1202 # Collection of obsolete ports to delete
1203 PROGRAM_DEPENDS='SELECT_OBSOLETE_PORTS'
1204 _program_exec_and_record_completion__operation ()
1205 {
1206         local src src_selected src_unselected dst_selected reqptn_file
1207         message_section_title "Collecting obsolete ports to delete"
1208         src=${DBDIR}/obsolete_ports.can_be_deleted
1209         src_selected=${DBDIR}/obsolete_ports_to_delete.selected
1210         src_unselected=${DBDIR}/obsolete_ports_to_delete.unselected
1211         dst_selected=${DBDIR}/obsolete_ports_to_delete
1212         reqptn_file=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
1213         cat "$src_unselected" 2> /dev/null | while read origin
1214         do
1215                 cat "${DBDIR}/initial/$origin/requirements.run.full" || :
1216                 cat "${DBDIR}/obsolete/$origin/requirements.run.full" || :
1217         done | sort -u | str_escape_regexp_filter \
1218                 | sed 's/^/^/;s/$/$/' > $reqptn_file
1219         grep -v -E -f "$reqptn_file" "$src_selected" > $dst_selected 2> /dev/null || :
1220         message_echo
1221 }
1222 program_exec_and_record_completion COLLECT_OBSOLETE_PORTS_TO_DELETE
1223
1224 # Set up the list of ports to reinstall
1225 PROGRAM_DEPENDS='ORDER_ALL_DEPENDENCIES'
1226 _program_exec_and_record_completion__operation ()
1227 {
1228         message_section_title "Setting up the list of ports to reinstall"
1229         cp -p "${DBDIR}/reinst_order.list" "${DBDIR}/stage.loop_list/reinst_todo"
1230         message_echo
1231 }
1232 program_exec_and_record_completion SETUP_REINST_TODO
1233
1234 # Composition of a list for deinstallation of obsolete and leaf packages
1235 PROGRAM_DEPENDS='COLLECT_LEAF_PORTS_TO_DELETE COLLECT_OBSOLETE_PORTS_TO_DELETE'
1236 _program_exec_and_record_completion__operation ()
1237 {
1238         local reqptn_leaf reqptn_obs leaf_selected leaf_selected_src obs_selected obs_selected_src grepptn preserved
1239         message_section_title "Composing a list for deinstallation of obsolete and leaf packages"
1240         reqptn_leaf=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
1241         reqptn_obs=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
1242         leaf_selected_src=${DBDIR}/leaf_ports_to_delete.selected
1243         leaf_selected=${DBDIR}/leaf_ports_to_delete
1244         obs_selected_src=${DBDIR}/obsolete_ports_to_delete.selected
1245         obs_selected=${DBDIR}/obsolete_ports_to_delete
1246         grepptn=${DBDIR}/ports_to_delete.grep_pattern
1247         grepptn_col1=${DBDIR}/ports_to_delete.grep_pattern_col1
1248         preserved=${TMPDIR}/LIST_DEINST_PKGS::preserved
1249         if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1250         then
1251                 cat "$reqptn_leaf" "$reqptn_obs" 2> /dev/null | sort -u > $grepptn
1252                 grep -v -E -f "$grepptn" "$leaf_selected_src" 2> /dev/null \
1253                         | database_query_add_initial_origins > $leaf_selected || :
1254                 cat "$obs_selected" "$leaf_selected" 2> /dev/null || :
1255         else
1256                 rm -f "$leaf_selected"
1257                 cat "$obs_selected" 2> /dev/null
1258         fi | sort -u > ${DBDIR}/stage.loop_list/ports_to_delete
1259         str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
1260                 | sed 's/^/^/;s/$/$/' > $grepptn
1261         str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
1262                 | sed 's/^/^/;s/$/[[:space:]]/' > $grepptn_col1
1263         cat "${DBDIR}/leaf_ports.with_ini" "${DBDIR}/obsolete_ports" 2> /dev/null \
1264                 | grep -E -v -f "$grepptn" > ${DBDIR}/stage.loop_list/ports_to_restore || :
1265         if [ $opt_batch_mode = no ]
1266         then
1267                 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ] && \
1268                         grep -v -E -f "$grepptn" "$leaf_selected_src" > $preserved 2> /dev/null
1269                 then
1270                         message_echo "INFO: Following leaf ports are preserved because required by other preserved leaf/obsolete ports."
1271                         message_echo "----------------"
1272                         while read origin
1273                         do
1274                                 pkgtag=`cat "${DBDIR}/required/$origin/pkgtag" 2> /dev/null` || :
1275                                 if [ -n "$pkgtag" ]
1276                                 then
1277                                         echo "$origin" "($pkgtag)"
1278                                 else
1279                                         echo "$origin"
1280                                 fi
1281                         done < $preserved
1282                         message_echo "----------------"
1283                 fi
1284                 if grep -v -E -f "$grepptn" "$obs_selected_src" > $preserved 2> /dev/null
1285                 then
1286                         message_echo "INFO: Following obsolete ports are preserved because required by other obsolete ports."
1287                         message_echo "----------------"
1288                         while read origin
1289                         do
1290                                 pkgtag=`cat "${DBDIR}/initial/$origin/installed_version" 2> /dev/null` || :
1291                                 if [ -n "$pkgtag" ]
1292                                 then
1293                                         echo "$origin" "($pkgtag)"
1294                                 else
1295                                         echo "$origin"
1296                                 fi
1297                         done < $preserved
1298                         message_echo "----------------"
1299                 fi
1300         fi
1301         message_echo
1302 }
1303 program_exec_and_record_completion LIST_DEINST_PKGS
1304
1305 # Collect entire distfiles list
1306 if [ $opt_inspect_entire_distinfo = yes ]
1307 then
1308         PROGRAM_DEPENDS=''
1309         _program_exec_and_record_completion__operation ()
1310         {
1311                 message_section_title "Collecting entire distfiles list"
1312                 find "${PORTSDIR}" -depth 3 -name distinfo -exec cat {} \; \
1313                         | grep '^SHA256 ' | sed -E 's/^SHA256 \(([^)]*)\).*/\1/' \
1314                         | sort -u > ${DBDIR}/distfiles.entire.tmp
1315                 mv "${DBDIR}/distfiles.entire.tmp" "${DBDIR}/distfiles.entire"
1316                 message_echo
1317         }
1318         program_exec_and_record_completion COLLECT_ALL_DISTFILES_LIST
1319 fi
1320
1321 # Inspection of all required distfiles
1322 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES COLLECT_ALL_DISTFILES_LIST'
1323 _program_exec_and_record_completion__operation ()
1324 {
1325         message_section_title "Summarizing distfiles list"
1326         cat "${DBDIR}/distfiles.entire" "${DBDIR}/distfiles.inspected" 2> /dev/null \
1327                 | sort -u | str_escape_regexp_filter \
1328                 | sed 's|^|^\\.\\/|; s|$|$|' > ${DBDIR}/distfiles.grep.pattern || :
1329         message_echo
1330 }
1331 program_exec_and_record_completion DISTFILES_LIST
1332
1333 # Clean up of reinstallation status for preparation
1334 PROGRAM_DEPENDS='REDO_INIT INSPECT_ALL_DEPENDENCIES'
1335 _program_exec_and_record_completion__operation ()
1336 {
1337         message_section_title "Cleaning up of reinstallation status for preparation"
1338         rm -rf "${DBDIR}/status.ports"
1339         message_echo
1340 }
1341 program_exec_and_record_completion CLEANUP_REINST_STATUS
1342
1343 # Completion of building the temporary database
1344 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'
1345 _program_exec_and_record_completion__operation ()
1346 {
1347         message_section_title "The temporary database is completely built up"
1348         message_echo
1349 }
1350 program_exec_and_record_completion PREPARATION
1351
1352
1353 # ==================================================
1354 # ====================== MAIN ======================
1355 # ==================================================
1356
1357 # Execute command operations which must be done before actual (re/de)installation processes
1358 command_exec_before_actual_re_de_installation "$@"
1359
1360 # Set termination messages
1361 temp_terminate_process ()
1362 {
1363         temp_terminate_process_common
1364 }
1365
1366 # Reinstallation of remained ports
1367 PROGRAM_DEPENDS='PREPARATION'
1368 _program_exec_restartable_loop_operation__routine ()
1369 {
1370         reinstall_exec "$@"
1371 }
1372 _program_exec_and_record_completion__operation ()
1373 {
1374         local _MSG_CURRENT_STAGE_general
1375         _MSG_CURRENT_STAGE_general="reinstallation"
1376         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1377         message_section_title "Reinstallation"
1378         program_exec_restartable_loop_operation reinst_todo
1379         reinstall_restore_conflicts
1380         temp_set_msg_current_stage
1381         message_echo
1382 }
1383 program_exec_and_record_completion REINSTALLATION
1384
1385 # Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again 
1386 PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1387 _program_exec_restartable_loop_operation__routine ()
1388 {
1389         deinstall_restore "$@"
1390 }
1391 _program_exec_and_record_completion__operation ()
1392 {
1393         local _MSG_CURRENT_STAGE_general
1394         _MSG_CURRENT_STAGE_general="restoration of unselected obsolete/leaf packages"
1395         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1396         message_section_title "Restoration of unselected obsolete/leaf packages"
1397         program_exec_restartable_loop_operation ports_to_restore
1398         temp_set_msg_current_stage
1399         message_echo
1400 }
1401 program_exec_and_record_completion RESTORE_ONCE_DEINST_PKGS
1402
1403 # Deinstallation of unused obsolete and leaf packages
1404 PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1405 _program_exec_restartable_loop_operation__routine ()
1406 {
1407         deinstall_exec "$@"
1408 }
1409 _program_exec_and_record_completion__operation ()
1410 {
1411         local _MSG_CURRENT_STAGE_general
1412         _MSG_CURRENT_STAGE_general="deinstallation of obsolete/leaf packages"
1413         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1414         message_section_title "Deinstallation of unused obsolete/leaf packages"
1415         program_exec_restartable_loop_operation ports_to_delete
1416         temp_set_msg_current_stage
1417         message_echo
1418 }
1419 program_exec_and_record_completion DEINST_UNUSED_PKGS
1420
1421 # Clean up obsolete or unused distfiles
1422 if [ $opt_only_target_scope = no -a $opt_keep_distfiles = no ]
1423 then
1424         PROGRAM_DEPENDS='REINSTALLATION DISTFILES_LIST'
1425         _program_exec_and_record_completion__operation ()
1426         {
1427                 local tmp_distfiles_exists
1428                 message_section_title "Cleaning up obsolete or unused distfiles"
1429                 tmp_distfiles_exists=${TMPDIR}/CLEANUP_OBSLETE_DISTFILES::distfiles_exists
1430                 [ $opt_dry_run = yes ] && message_echo "INFO: The operations are not actually carried out."
1431                 ( set -e; cd "${DISTDIR}" && find . -type f ) \
1432                         | sed 's|^\./||' | sort -u > $tmp_distfiles_exists
1433                 fileedit_manipulate_old_lines "$tmp_distfiles_exists" "${DBDIR}/distfiles.entire" \
1434                         | while read distfile
1435                 do
1436                         if [ $opt_batch_mode = no ]
1437                         then
1438                                 echo "  $distfile"
1439                         fi
1440                         [ $opt_dry_run = yes ] && continue
1441                         rm -f "${DISTDIR}/$distfile"
1442                 done
1443                 message_echo
1444         }
1445         program_exec_and_record_completion CLEANUP_OBSLETE_DISTFILES
1446 fi
1447
1448 # Rebuild of package database
1449 PROGRAM_DEPENDS='REINSTALLATION RESTORE_ONCE_DEINST_PKGS DEINST_UNUSED_PKGS'
1450 _program_exec_and_record_completion__operation ()
1451 {
1452         which -s pkgdb || return 0
1453         message_section_title "Rebuilding package database for portupgrade"
1454         pkgdb -fu
1455         message_echo
1456 }
1457 program_exec_and_record_completion REBUILD_PKGDB
1458
1459
1460 # ==================================================
1461 # ================ ENDING MESSAGES =================
1462 # ==================================================
1463
1464 # Notice of failures
1465 exists_unresolved_ports=
1466 message_summary_dependents_of_failed_reinstallation failure || exists_unresolved_ports=y
1467 message_summary_dependents_of_failed_reinstallation redo || exists_unresolved_ports=y
1468 message_summary_dependents_of_failed_reinstallation conflict || exists_unresolved_ports=y
1469 [ -n "$exists_unresolved_ports" ] && message_summary_advice_on_manual_solution
1470
1471 # End
1472 temp_terminate_process () { :; }
1473
1474 if [ -z "$exists_unresolved_ports" ]
1475 then
1476         message_section_title "COMPLETELY DONE"
1477         message_echo "- E N D -"
1478 else
1479         message_warn_no_achieved_progress || :
1480         message_section_title "Done with some unresolved problems"
1481         message_echo "- To be continued -"
1482 fi