OSDN Git Service

Version 3.0.5+toward_3.0.6_20140707112659
[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.0.6
16 # COMPATIBLE_VERSIONS='^(3\.0\.[0-9]+)$'
17 # Template for development versions
18 MYVERSION=3.0.5+toward_3.0.6_20140707112659
19 COMPATIBLE_VERSIONS='^(3\.0\.[0-9]+\+toward_3\.0\.[0-9]+_[0-9]+|3\.0\.[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         message_section_title "Collecting all installed packages"
304         pkg_info_qoa > ${DBDIR}/installed_ports
305         pkg_info_gen_pkg_origin_table
306         str_escape_regexp_filter < "${DBDIR}/installed_ports" \
307                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/installed_ports.grep_pattern
308         message_echo
309 }
310 program_exec_and_record_completion COLLECT_ALL_INSTALLED_PACKAGES
311
312 # Preliminary inspection of tools which have to be up-to-date
313 # (No need depend on PARSE_CONF because INSPECT_ALL_DEPENDENCIES will take the task.)
314 PROGRAM_DEPENDS=
315 _program_exec_restartable_loop_operation__routine ()
316 {
317         local origin
318         origin=$1
319         database_build_inspect_dependencies "$origin"
320 }
321 _program_exec_and_record_completion__operation ()
322 {
323         local DEPTH_INDEX
324         message_section_title "Preliminary inspection of tools which have to be up-to-date"
325         {
326                 [ "$PKGSYS_USE_PKGNG" = yes ] && echo 'ports-mgmt/pkg'
327                 pkgsys_is_dialog4ports_used && echo 'ports-mgmt/dialog4ports'
328                 [ -n "$MYPORTORIGIN" ] && echo "$MYPORTORIGIN"
329         } 2> /dev/null > ${DBDIR}/stage.loop_list/tools_to_inspect
330         DEPTH_INDEX='--'
331         program_exec_restartable_loop_operation tools_to_inspect
332         database_build_post_inspect_dependencies
333         message_echo
334 }
335 program_exec_and_record_completion PRELIMINARY_INSPECTION_OF_TOOLS
336
337 # Upgrade of ports-mgmt/pkg if new
338 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
339 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
340         -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no \
341         -a "$PKGSYS_USE_PKGNG" = yes ]
342 then
343         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
344         _program_exec_and_record_completion__operation ()
345         {
346                 local _MSG_CURRENT_STAGE_general
347                 _MSG_CURRENT_STAGE_general="pkgng upgrade"
348                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
349                 message_section_title "Upgrade of ports-mgmt/pkg if new"
350                 touch "${DBDIR}/target_all"
351                 reinstall_exec ports-mgmt/pkg
352                 reinstall_restore_conflicts
353                 rm -f "${DBDIR}/target_all"
354                 temp_set_msg_current_stage
355                 message_echo
356         }
357         program_exec_and_record_completion UPGRADE_PKGNG
358 fi
359
360 # Upgrade of ports-mgmt/dialog4ports if new
361 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
362 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
363         -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no ] \
364         && pkgsys_is_dialog4ports_used
365 then
366         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
367         _program_exec_and_record_completion__operation ()
368         {
369                 local _MSG_CURRENT_STAGE_general
370                 _MSG_CURRENT_STAGE_general="pkgng dialog4ports"
371                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
372                 message_section_title "Upgrade of dialog4ports if new"
373                 touch "${DBDIR}/target_all"
374                 reinstall_exec ports-mgmt/dialog4ports
375                 reinstall_restore_conflicts
376                 rm -f "${DBDIR}/target_all"
377                 temp_set_msg_current_stage
378                 message_echo
379         }
380         program_exec_and_record_completion UPGRADE_DIALOG4PORTS
381 fi
382
383 # Upgrade of this utility if new
384 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
385 if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
386         -a $opt_dry_run = no -a $opt_suppress_self_upadte = no \
387         -a -n "$MYPORTORIGIN" ]
388 then
389         PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
390         _program_exec_and_record_completion__operation ()
391         {
392                 local _MSG_CURRENT_STAGE_general
393                 _MSG_CURRENT_STAGE_general="pkgng upgrade"
394                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
395                 message_section_title "Upgrade of this utility if new"
396                 touch "${DBDIR}/target_all"
397                 reinstall_exec "$MYPORTORIGIN"
398                 reinstall_restore_conflicts
399                 rm -f "${DBDIR}/target_all"
400                 temp_set_msg_current_stage
401                 message_echo
402         }
403         program_exec_and_record_completion UPGRADE_SELF
404 fi
405
406 if [ "x`${APPNAME} -aV 2> /dev/null`" != "x$MYVERSION" ]
407 then
408         message_echo "INFO: ${APPNAME} is upgraded and the temporary database needs refresh."
409         database_build_clean_for_self_upgrade || :
410         message_echo "INFO: Restarting with the new version."
411         message_echo
412         temp_trap_for_invoking_new_version
413         . "${TMPDIR}"/restart_command.sh
414         exit
415 fi
416
417
418 # ==================================================
419 # ================== PREPARATION ===================
420 # ==================================================
421
422 # ============= Correspondence to configuration changes =============
423
424 # Patch to the temporary database by reflecting changes in configuration
425 PROGRAM_DEPENDS='PARSE_CONF'
426 _program_exec_and_record_completion__operation ()
427 {
428         local tmpfile_diff tmpfile_old tmpfile_new key
429         [ -d "${DBDIR}/conf.prev" ] || return 0
430         message_section_title "Patch to the temporary database by reflecting changes in configuration"
431         tmpfile_old=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::old
432         tmpfile_new=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::new
433         tmpfile_updated_ports=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::updated_ports
434         if fileedit_manipulate_old_new_lines \
435                 "${DBDIR}/conf.prev/setenv.sh" "${DBDIR}/conf/setenv.sh" "$tmpfile_old" "$tmpfile_new"
436         then
437                 if grep -q -e ^LOCALBASE= -e ^LINUXBASE= -e ^PORTSDIR= "$tmpfile_old" "$tmpfile_new"
438                 then
439                         message_echo "ERROR: Migration of the temporary database is unavailable because LOCALBASE, LINUXBASE or PORTSDIR was changed." >&2
440                         message_echo "        ${APPNAME} clean" >&2
441                         message_echo "must be executed in advance." >&2
442                         exit 1
443                 fi
444         fi
445         cut -s -d '|' -f 1,2 "${DBDIR}/conf.prev/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.old
446         cut -s -d '|' -f 1,2 "${DBDIR}/conf/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.new
447         if fileedit_manipulate_old_new_lines \
448                 "${TMPDIR}/MOVED_ALT.old" "${TMPDIR}/MOVED_ALT.new" "$tmpfile_old" "$tmpfile_new"
449         then
450                 cat "$tmpfile_old" "$tmpfile_new" | while read from to
451                 do
452                         echo "$from"
453                         [ -n "$to" ] && echo "$to"
454                 done
455         fi > $tmpfile_updated_ports
456         if fileedit_manipulate_old_new_lines \
457                 "${DBDIR}/conf.prev/REPLACE.csv" "${DBDIR}/conf/REPLACE.csv" "$tmpfile_old" "$tmpfile_new"
458         then
459                 cat "$tmpfile_old" "$tmpfile_new" | while read from to
460                 do
461                         echo "$from"
462                         [ -n "$to" ] && echo "$to"
463                 done
464         fi >> $tmpfile_updated_ports
465         [ `wc -l < $tmpfile_updated_ports` -gt 0 ] && rm -f "${DBDIR}/REPLACE.complete_sed_pattern"
466         [ -d "${DBDIR}/conf/each_port" ] && find "${DBDIR}/conf/each_port" -depth 2 \
467                 | while read dbpath
468         do
469                 origin=`str_dirpath_to_origin "$dbpath"`
470                 dbpath_prev=${DBDIR}/conf.prev/each_port/$origin
471                 diff -r "$dbpath_prev" "$dbpath" > /dev/null 2>&1 && continue
472                 echo "$origin"
473         done >> $tmpfile_updated_ports
474         [ -d "${DBDIR}/conf.prev/each_port" ] && find "${DBDIR}/conf.prev/each_port" -depth 2 \
475                 | while read dbpath_prev
476         do
477                 origin=`str_dirpath_to_origin "$dbpath_prev"`
478                 dbpath=${DBDIR}/conf/each_port/$origin
479                 [ -d "$dbpath" ] && continue
480                 echo "$origin"
481         done >> $tmpfile_updated_ports
482         if [ `wc -l < $tmpfile_updated_ports` -gt 0 ]
483         then
484                 sort -u "$tmpfile_updated_ports" | while read origin
485                 do
486                         database_build_patch_reconf "$origin"
487                 done
488                 program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
489         fi
490         message_echo
491 }
492 program_exec_and_record_completion PATCH_TO_TMPDB_REFLECT_CONF_CHANGES
493
494 # ============= Database construction =============
495
496 # Execute command operations which must be done before building the temporary database
497 command_exec_before_building_tempdb "$@"
498
499 # Meta process for redo
500 PROGRAM_DEPENDS=''
501 _program_exec_and_record_completion__operation ()
502 {
503         rm -f "${DBDIR}/new_success_in_current_run"
504         [ "x$COMMAND_MODE" = xredo ] || return 0
505         message_echo "[REDO mode]"
506         message_echo
507 }
508 program_exec_and_record_completion REDO_INIT
509
510 # Determine specified targets
511 PROGRAM_DEPENDS=''
512 _program_exec_and_record_completion__operation ()
513 {
514         local tag level dbsuffix
515         message_section_title "Determining specified targets"
516         cat "${DBDIR}/stage.loop_list/target_itself.specified" \
517                 "${DBDIR}/stage.loop_list/target_dependents.specified" \
518                 "${DBDIR}/stage.loop_list/target_requirements.specified" \
519                 "${DBDIR}/need.list" \
520                 "${DBDIR}/targets_specified_so_far" 2> /dev/null \
521                 | sort -u > ${DBDIR}/targets_specified_so_far.tmp
522         mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
523         rm -f "${DBDIR}/stage.loop_list/target_itself.specified" \
524                 "${DBDIR}/stage.loop_list/target_dependents.specified" \
525                 "${DBDIR}/stage.loop_list/target_requirements.specified"
526         if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
527         then
528                 options_select_new_ports_if_duplicated O \
529                         "${DBDIR}/stage.loop_list/target_itself.specified" "$opt_target_itself"
530                 options_select_new_ports_if_duplicated t \
531                         "${DBDIR}/stage.loop_list/target_dependents.specified" "$opt_target_dependents"
532                 options_select_new_ports_if_duplicated T \
533                         "${DBDIR}/stage.loop_list/target_requirements.specified" "$opt_target_requirements"
534                 if [ `cat "${DBDIR}/stage.loop_list/target_itself.specified" \
535                         "${DBDIR}/stage.loop_list/target_dependents.specified" \
536                         "${DBDIR}/stage.loop_list/target_requirements.specified" | wc -l` -eq 0 ]
537                 then
538                         message_echo "ERROR: No matching port for target globs." >&2
539                         message_echo >&2
540                         exit 1
541                 fi
542                 cat "${DBDIR}/stage.loop_list/target_itself.specified" \
543                         "${DBDIR}/stage.loop_list/target_dependents.specified" \
544                         "${DBDIR}/stage.loop_list/target_requirements.specified" \
545                         | sort -u > ${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset
546                 cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset" "${DBDIR}/need.list" 2> /dev/null \
547                         | sort -u > ${DBDIR}/need.list.tmp
548                 mv "${DBDIR}/need.list.tmp" "${DBDIR}/need.list"
549                 sort -u "${DBDIR}/need.list" "${DBDIR}/targets_specified_so_far" \
550                         > ${DBDIR}/targets_specified_so_far.tmp
551                 mv "${DBDIR}/targets_specified_so_far.tmp" "${DBDIR}/targets_specified_so_far"
552                 for tag in all run build none
553                 do
554                         for level in direct full
555                         do
556                                 dbsuffix=$tag.$level
557                                 {
558                                         cat "${TMPDIR}/DETERMINE_SPECIFIED_TARGETS.reset"
559                                         cat "${DBDIR}/stage.loop_list/target_dependents.specified" | while read origin
560                                         do
561                                                 nodedir=${DBDIR}/requires/$origin
562                                                 cat "$nodedir/dependents.$dbsuffix" 2> /dev/null
563                                         done
564                                         cat "${DBDIR}/stage.loop_list/target_requirements.specified" | while read origin
565                                         do
566                                                 nodedir=${DBDIR}/requires/$origin
567                                                 cat "$nodedir/requirements.$dbsuffix" 2> /dev/null
568                                         done
569                                 } | sort -u | while read origin
570                                 do
571                                         fileedit_rm_a_line "$origin" "${DBDIR}/success.$dbsuffix.list"
572                                         fileedit_rm_a_line "$origin" "${DBDIR}/todo_after_requirements_succeed.$dbsuffix.list"
573                                         rm -f "${DBDIR}/requires/$origin/succeeded_once"
574                                 done
575                         done
576                 done
577         fi
578         message_echo
579 }
580 program_exec_and_record_completion DETERMINE_SPECIFIED_TARGETS
581
582 # Show specified targets
583 if [ -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" -a $opt_batch_mode = no ]
584 then
585         message_echo "INFO: (Re/de-)installation will be carried out only for the targets:"
586         echo
587         if [ `wc -l < ${DBDIR}/stage.loop_list/target_itself.specified` -gt 0 ]
588         then
589                 message_echo "[Targets only]"
590                 echo "----------------------------------------"
591                 cat "${DBDIR}/stage.loop_list/target_itself.specified"
592                 echo "----------------------------------------"
593                 echo
594         fi
595         if [ `wc -l < ${DBDIR}/stage.loop_list/target_dependents.specified` -gt 0 ]
596         then
597                 message_echo "[Targets with their `options_get_dependency_msgterm` dependents]"
598                 echo "----------------------------------------"
599                 cat "${DBDIR}/stage.loop_list/target_dependents.specified"
600                 echo "----------------------------------------"
601                 echo
602         fi
603         if [ `wc -l < ${DBDIR}/stage.loop_list/target_requirements.specified` -gt 0 ]
604         then
605                 message_echo "[Targets with their `options_get_dependency_msgterm` requirements]"
606                 echo "----------------------------------------"
607                 cat "${DBDIR}/stage.loop_list/target_requirements.specified"
608                 echo "----------------------------------------"
609                 echo
610         fi
611 fi
612
613 # Determine all target ports
614 PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS COLLECT_ALL_INSTALLED_PACKAGES'
615 _program_exec_and_record_completion__operation ()
616 {
617         message_section_title "Determining all target ports"
618         {
619                 if [ $opt_only_target_scope = no ]
620                 then
621                         cat "${DBDIR}/installed_ports" 2> /dev/null || :
622                 fi
623                 cat "${DBDIR}/stage.loop_list/target_itself.specified" || :
624                 cat "${DBDIR}/stage.loop_list/target_dependents.specified" || :
625                 cat "${DBDIR}/stage.loop_list/target_requirements.specified" || :
626                 cat "${DBDIR}/targets_specified_so_far" || :
627         }  2> /dev/null | sort -u > "${DBDIR}/stage.loop_list/ports_to_inspect"
628         message_echo
629 }
630 program_exec_and_record_completion DETERMINE_ALL_TARGET_PORTS
631
632 # Inspection of all dependencies
633 PROGRAM_DEPENDS='PARSE_CONF DETERMINE_ALL_TARGET_PORTS'
634 _program_exec_restartable_loop_operation__routine ()
635 {
636         local origin
637         origin=$1
638         database_build_inspect_dependencies "$origin"
639 }
640 _program_exec_and_record_completion__operation ()
641 {
642         local DEPTH_INDEX 
643         message_section_title "Inspecting dependencies of the all installed packages"
644         [ $opt_only_target_scope = no -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ] && \
645                 message_echo "INFO: Ports which seem irrelevant to the targets are also inspected in order to get complete information."
646         DEPTH_INDEX='--'
647         program_exec_restartable_loop_operation ports_to_inspect
648         database_build_post_inspect_dependencies
649         message_echo
650 }
651 program_exec_and_record_completion INSPECT_ALL_DEPENDENCIES
652
653 # Convert dependency-lists to actual ones
654 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES'
655 _program_exec_restartable_loop_operation__routine ()
656 {
657         local origin table dbtag level tag target
658         origin=$1
659         for table in dependents requirements
660         do
661                 for dbtag in requires obsolete
662                 do
663                         for level in direct full
664                         do
665                                 for tag in all run build
666                                 do
667                                         target=${DBDIR}/$dbtag/$origin/${table}.${tag}.${level}
668                                         if [ -e "$target.src" ]
669                                         then
670                                                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "$target.src" \
671                                                         | grep -v '^$' | sort -u > $target.tmp
672                                                 [ -e "$target" ] && ! diff "$target.tmp" "$target" > /dev/null \
673                                                         && echo "$origin" >> ${DBDIR}/update_dependencies
674                                                 mv "$target.tmp" "$target"
675                                         else
676                                                 [ -e "$target" ] && echo "$origin" >> ${DBDIR}/update_dependencies
677                                                 rm -f "$target"
678                                         fi
679                                 done
680                         done
681                 done
682         done
683 }
684 _program_exec_and_record_completion__operation ()
685 {
686         message_section_title "Conversion of dependency-lists to actual ones"
687         program_exec_restartable_loop_operation convert_dependency_lists
688         sort -u "${DBDIR}/update_dependencies" > ${DBDIR}/update_dependencies.tmp
689         mv "${DBDIR}/update_dependencies.tmp" "${DBDIR}/update_dependencies"
690         str_escape_regexp_filter < ${DBDIR}/update_dependencies \
691                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/update_dependencies.grep_pattern
692         for tag in all run build
693         do
694                 ( cd "${DBDIR}/requires" && \
695                         find . -depth 3 -type f -name requirements.${tag}.full | sed 's|^./||;s|/[^/]*$||' ) \
696                         | grep -v -E -f "${DBDIR}/update_dependencies.grep_pattern" \
697                         | str_escape_regexp_filter | sed 's/^/^/; s/$/$/' \
698                         > ${TMPDIR}/convert_requirements_list:full_complete.grep_pattern || :
699                 ( cd "${DBDIR}/requires" && \
700                         find . -depth 3 -type f -name requirements.${tag}.direct | sed 's|^./||;s|/[^/]*$||' ) \
701                         | grep -v -E -f "${TMPDIR}/convert_requirements_list:full_complete.grep_pattern" \
702                         > ${DBDIR}/stage.loop_list/complete_recursive_${tag}time_reqlists || :
703         done
704         for inspected_level_tmp in direct node
705         do
706                 cat "${DBDIR}/ports.inspected.${inspected_level_tmp}.list" || :
707         done 2> /dev/null | sort -u > ${DBDIR}/stage.loop_list/trim_dependency_lists_rm_uninspected_ports
708         find "${DBDIR}/requires" -depth 2 -type d > ${DBDIR}/stage.loop_list/inspect_dependent
709         [ -e "${DBDIR}/dependents_files" ] && \
710                 mv "${DBDIR}/dependents_files" "${DBDIR}/dependents_files.prev"
711         rm -f "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" "${DBDIR}/dependents_files.tmp"
712         message_echo
713 }
714 program_exec_and_record_completion CONVERT_REQUIREMENTS_LIST
715
716 # Completion of recursive requirement lists
717 for _REQUIREMENT_LISTS_tag in all run build
718 do
719         PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
720         _program_exec_restartable_loop_operation__routine ()
721         {
722                 local tag dbpath origin suffix
723                 tag=${_REQUIREMENT_LISTS_tag}
724                 dbpath=$1
725                 origin=`str_dirpath_to_origin "$dbpath"`
726                 for suffix in '' .orig
727                 do
728                         database_build_get_complete_recursive_dependency requirements.${tag} "$origin" "$suffix" > /dev/null
729                 done
730         }
731         _program_exec_and_record_completion__operation ()
732         {
733                 local tag
734                 tag=${_REQUIREMENT_LISTS_tag}
735                 message_section_title "Completion of ${tag}-time requirement lists"
736                 program_exec_restartable_loop_operation complete_recursive_${tag}time_reqlists
737                 message_echo
738         }
739         program_exec_and_record_completion RECURSIVE_REQUIREMENT_LISTS:${_REQUIREMENT_LISTS_tag}
740 done
741
742 # Trim dependency lists by removing uninspected ports
743 if [ $opt_only_target_scope = yes ]
744 then
745         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST'
746         _program_exec_restartable_loop_operation__routine ()
747         {
748                 local dbpath tag level srcdb
749                 dbpath=$1
750                 for tag in all run build
751                 do
752                         for level in direct full
753                         do
754                                 srcdb=requirements.${tag}.${level}
755                                 [ -e "$dbpath/$srcdb" ] || continue
756                                 grep -E -f "${DBDIR}/inspected_ports.grep_pattern" "$dbpath/$srcdb" \
757                                         > $dbpath/$srcdb.tmp || :
758                                 mv "$dbpath/$srcdb.tmp" "$dbpath/$srcdb"
759                         done
760                 done
761         }
762         _program_exec_and_record_completion__operation ()
763         {
764                 message_section_title "Trimming dependency lists by removing uninspected ports"
765                 program_exec_restartable_loop_operation trim_dependency_lists_rm_uninspected_ports
766                 message_echo
767         }
768         program_exec_and_record_completion TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS
769 fi
770
771 # Inspection of dependents
772 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES CONVERT_REQUIREMENTS_LIST TRIM_DEPENDENCY_LISTS_RM_UNINSPECTED_PORTS'
773 _program_exec_restartable_loop_operation__routine ()
774 {
775         local dbpath origin tag level suffix srcdb dstdb
776         dbpath=$1
777         origin=`str_dirpath_to_origin "$dbpath"`
778         for tag in all run build
779         do
780                 for level in direct full
781                 do
782                         for suffix in '' .orig
783                         do
784                                 srcdb=requirements.${tag}.${level}${suffix}
785                                 dstdb=dependents.${tag}.${level}${suffix}
786                                 [ -e "$dbpath/$srcdb" ] || continue
787                                 while read origin_requirement
788                                 do
789                                         dstpath=${DBDIR}/requires/$origin_requirement
790                                         echo "$dstpath/$dstdb" >> ${DBDIR}/dependents_files.tmp
791                                         [ "$dstpath/$dstdb" -nt "$dbpath/$srcdb" ] && continue
792                                         [ -d "$dstpath" ] || mkdir -p "$dstpath"
793                                         echo "$origin" >> $dstpath/$dstdb.raw
794                                         echo "$dstpath/$dstdb" >> ${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp
795                                 done < $dbpath/$srcdb
796                         done
797                 done
798         done
799 }
800 _program_exec_and_record_completion__operation ()
801 {
802         local dbrequires_valesc
803         message_section_title "Inspection of dependents"
804         dbrequires_valesc=`str_escape_replaceval "${DBDIR}/requires/"`
805         program_exec_restartable_loop_operation inspect_dependent
806         sort -u "${DBDIR}/stage.loop_list/make_dependents_lists_unique.tmp" 2> /dev/null \
807                 > ${DBDIR}/stage.loop_list/make_dependents_lists_unique || :
808         sort -u "${DBDIR}/dependents_files.tmp" 2> /dev/null > ${DBDIR}/dependents_files || :
809         [ -e "${DBDIR}/make_dependents_lists_unique.prev" ] && \
810                 fileedit_manipulate_old_lines "${DBDIR}/dependents_files.prev" "${DBDIR}/dependents_files" \
811                 | xargs rm -f
812         message_echo
813 }
814 program_exec_and_record_completion INSPECT_DEPENDENTS
815
816 # Remove duplicated lines in dependents lists
817 PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST INSPECT_DEPENDENTS'
818 _program_exec_restartable_loop_operation__routine ()
819 {
820         local dbpath tag level dstdb
821         dstdb=$1
822         cat "$dstdb" "$dstdb.raw" 2> /dev/null | sort -u > $dstdb.tmp
823         mv "$dstdb.tmp" "$dstdb"
824         rm -f "$dstdb.raw"
825 }
826 _program_exec_and_record_completion__operation ()
827 {
828         local dbrequires_valesc
829         message_section_title "Removing duplicated items in dependents lists"
830         program_exec_restartable_loop_operation make_dependents_lists_unique
831         message_echo
832 }
833 program_exec_and_record_completion MAKE_DEPENDENTS_LISTS_UNIQUE
834
835 # Preparation of target attribute information
836 for _TARGET_ATTR_INFO_table in requirements dependents itself
837 do
838         [ `cat "${DBDIR}/stage.loop_list/target_${_TARGET_ATTR_INFO_table}.replaced.specified" 2> /dev/null \
839                 | wc -l` -gt 0 ] || continue
840         PROGRAM_DEPENDS='DETERMINE_SPECIFIED_TARGETS CONVERT_REQUIREMENTS_LIST'
841         _program_exec_restartable_loop_operation__routine ()
842         {
843                 local origin dbtargets_valesc table
844                 origin=$1
845                 dbtargets_valesc=`str_escape_replaceval "${DBDIR}/targets/"`
846                 table=${_TARGET_ATTR_INFO_table}
847                 for database in requires initial
848                 do
849                         dbpath=${DBDIR}/$database/$origin
850                         dstpath=${DBDIR}/targets/$origin
851                         [ -d "$dstpath" ] || mkdir -p "$dstpath"
852                         touch "$dstpath/target_itself"
853                         echo "$origin" >> ${DBDIR}/all_targets.lst
854                         [ $table = itself ] && continue
855                         for tag in all run build
856                         do
857                                 for level in direct full
858                                 do
859                                         srcdb=${table}.${tag}.${level}
860                                         dstdb=target_${database}_${table}.${tag}.${level}
861                                         [ -e "$dbpath/$srcdb" ] || continue
862                                         cat "$dbpath/$srcdb" >> ${DBDIR}/all_targets.lst
863                                         sed -E "s/^/$dbtargets_valesc/; s|$|/$dstdb|" "$dbpath/$srcdb" \
864                                                 | fileedit_add_a_line_to_files_if_new "$origin"
865                                 done
866                         done
867                 done
868         }
869         _program_exec_and_record_completion__operation ()
870         {
871                 local table
872                 table=${_TARGET_ATTR_INFO_table}
873                 message_section_title "Preparation of target attribute information for dependency [$table]"
874                 program_exec_restartable_loop_operation target_$table.replaced.specified
875                 message_echo
876         }
877         program_exec_and_record_completion TARGET_ATTR_INFO:${_TARGET_ATTR_INFO_table}
878 done
879
880 # Post-process after the preparation of target attribute information
881 PROGRAM_DEPENDS='MAKE_DEPENDENTS_LISTS_UNIQUE TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents'
882 _program_exec_and_record_completion__operation ()
883 {
884         message_section_title "Post-process after the preparation of target attribute information"
885         sort -u "${DBDIR}/all_targets.lst" 2> /dev/null \
886                 | grep -E -f "${DBDIR}/inspected_ports.grep_pattern" \
887                 | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" \
888                 > ${DBDIR}/all_targets.lst.tmp || :
889         mv "${DBDIR}/all_targets.lst.tmp" "${DBDIR}/all_targets.lst"
890         find "${DBDIR}/targets" -depth 2 -type d > ${DBDIR}/stage.loop_list/build_complement_to_new_dependents_for_targets 2> /dev/null || :
891         {
892                 cat "${DBDIR}/all_targets.lst" "${DBDIR}/need.with_replaced.list" 2> /dev/null || :
893                 find "${DBDIR}/requires" -depth 3 -type f -name installed_version \
894                         | sed -E 's|.*/([^/]+/[^/]+)/[^/]*$|\1|'
895         } | sort -u > ${DBDIR}/stage.loop_list/inspect_necessity
896         cp /dev/null "${DBDIR}/stage.loop_list/parse_target_attr_info"
897         find -E "${DBDIR}/requires" -depth 3 -type f -regex '.*/necessary_port\.(direct|full)$' -delete
898         message_echo
899 }
900 program_exec_and_record_completion TARGET_ATTR_INFO_POSTPROCESS
901
902 # Build of data on complement to new dependents for target attribute information
903 PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS TARGET_ATTR_INFO:requirements TARGET_ATTR_INFO:dependents CONVERT_REQUIREMENTS_LIST'
904 _program_exec_restartable_loop_operation__routine ()
905 {
906         local dbpath origin
907         dbpath=$1
908         origin=`str_dirpath_to_origin "$dbpath"`
909         database_build_complement_to_new_dependents_for_targets "$origin"
910 }
911 _program_exec_and_record_completion__operation ()
912 {
913         message_section_title "Build of data on complement to new dependents for target attribute information"
914         program_exec_restartable_loop_operation build_complement_to_new_dependents_for_targets
915         sort -u "${DBDIR}/stage.loop_list/parse_target_attr_info" > ${DBDIR}/stage.loop_list/parse_target_attr_info.tmp
916         mv "${DBDIR}/stage.loop_list/parse_target_attr_info.tmp" "${DBDIR}/stage.loop_list/parse_target_attr_info"
917         message_echo
918 }
919 program_exec_and_record_completion COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO
920
921 # Parse target attribute information
922 PROGRAM_DEPENDS='COMPLEMENT_TO_NEW_DEPENDENTS_FOR_TARGET_ATTR_INFO'
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_target_attributes "$origin"
929 }
930 _program_exec_and_record_completion__operation ()
931 {
932         message_section_title "Parsing target attribute information"
933         program_exec_restartable_loop_operation parse_target_attr_info
934         message_echo
935 }
936 program_exec_and_record_completion PARSE_TARGET_ATTR_INFO
937
938 # Inspection of necessity
939 PROGRAM_DEPENDS='TARGET_ATTR_INFO_POSTPROCESS RECURSIVE_REQUIREMENT_LISTS:run RECURSIVE_REQUIREMENT_LISTS:build INSPECT_ALL_DEPENDENCIES'
940 _program_exec_restartable_loop_operation__routine ()
941 {
942         local origin
943         origin=$1
944         for level in direct full
945         do
946                 database_build_inspect_necessity_for_only_new_upgrade "$origin" "$level"
947         done
948 }
949 _program_exec_and_record_completion__operation ()
950 {
951         message_section_title "Inspection of necessity"
952         program_exec_restartable_loop_operation inspect_necessity
953         for level in direct full
954         do
955                 find "${DBDIR}/requires" -depth 3 -type f -name "necessary_port.${level}" \
956                         > ${DBDIR}/stage.loop_list/necessary_ports.${level}
957         done
958         message_echo
959 }
960 program_exec_and_record_completion INSPECT_NECESSITY
961
962 # Inspection of necessary upgrades
963 for _NECESSARY_UPDATES_level in direct full
964 do
965         PROGRAM_DEPENDS='INSPECT_NECESSITY INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE'
966         _program_exec_restartable_loop_operation__routine ()
967         {
968                 local markerpath level dbpath origin tag
969                 markerpath=$1
970                 level=${_NECESSARY_UPDATES_level}
971                 dbpath=`dirname "$markerpath"`
972                 origin=`str_dirpath_to_origin "$dbpath"`
973                 database_query_does_a_port_need_update "$origin" || return 0
974                 for tag in all run build none
975                 do
976                         touch "$dbpath/necessary_upgrade.$tag.${level}"
977                         [ -e "$dbpath/dependents.$tag.${level}" ] || continue
978                         while read origin_dependent
979                         do
980                                 touch "${DBDIR}/requires/$origin_dependent/necessary_upgrade.$tag.${level}"
981                         done < $dbpath/dependents.$tag.${level}
982                 done
983         }
984         _program_exec_and_record_completion__operation ()
985         {
986                 local level
987                 level=${_NECESSARY_UPDATES_level}
988                 message_section_title "Inspection of necessary upgrades at the $level level"
989                 program_exec_restartable_loop_operation necessary_ports.${level}
990                 message_echo
991         }
992         program_exec_and_record_completion NECESSARY_UPDATES:${_NECESSARY_UPDATES_level}
993 done
994
995 # Preparation for inspection of new leaf ports
996 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
997 then
998         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PARSE_CONF'
999         _program_exec_and_record_completion__operation ()
1000         {
1001                 message_section_title "Preparation for inspection of new leaf ports"
1002                 find "${DBDIR}/requires" -depth 3 -type f -name dependents.all.full \
1003                         | sed -E 's|.*/([^/]+/[^/]+)/[^/]+$|\1|' \
1004                         | sort -u > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports
1005                 sort -u "${DBDIR}/inspected_ports" > ${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports
1006                 fileedit_manipulate_new_lines \
1007                         "${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:nonleaf_ports" \
1008                         "${TMPDIR}/PREPARE_INSPECT_LEAF_PORTS:inspected_ports" \
1009                         | grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" \
1010                         > ${DBDIR}/stage.loop_list/leaf_ports_primary_candidates || :
1011                 cp /dev/null "${DBDIR}/grep.leaf_ports.pattern"
1012                 cp /dev/null "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
1013                 message_echo
1014         }
1015         program_exec_and_record_completion PREPARE_INSPECT_LEAF_PORTS
1016 fi
1017
1018 # Inspection of new primary leaf ports
1019 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1020 then
1021         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE PREPARE_INSPECT_LEAF_PORTS PARSE_CONF'
1022         _program_exec_restartable_loop_operation__routine ()
1023         {
1024                 local origin origin_ini origin_esc dbpath origin_req
1025                 origin=$1
1026                 pkgsys_is_pkgtool "$origin" && return
1027                 dbpath=${DBDIR}/requires/$origin
1028                 origin_esc=`str_escape_regexp "$origin"`
1029                 grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
1030                 if ! grep -q -E "^$origin_esc$" "${DBDIR}/noneed.list" 2> /dev/null
1031                 then
1032                         if [ -e "$dbpath/initial_orig" ]
1033                         then
1034                                 origin_ini=`cat "$dbpath/initial_orig"`
1035                                 [ -e "${DBDIR}/initial/$origin_ini/installed_version" \
1036                                         -a `cat "${DBDIR}/initial/$origin_ini/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
1037                                         && return
1038                         fi
1039                         [ -e "${DBDIR}/initial/$origin/installed_version" \
1040                                 -a `cat "${DBDIR}/initial/$origin/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ] \
1041                                 && return
1042                 fi
1043                 if [ -e "$dbpath/requirements.all.full" ]
1044                 then
1045                         grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" "$dbpath/requirements.all.full" | \
1046                                 fileedit_add_lines_if_new "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
1047                 fi
1048                 fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
1049         }
1050         _program_exec_and_record_completion__operation ()
1051         {
1052                 local num_leaves num_leaves_prev
1053                 message_section_title "Inspection of new primary leaf ports"
1054                 program_exec_restartable_loop_operation leaf_ports_primary_candidates
1055                 wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' ' > ${DBDIR}/num_leaves
1056                 cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
1057                 message_echo "  `cat "${DBDIR}/num_leaves"` primary leaf port(s) is/are found."
1058                 message_echo
1059         }
1060         program_exec_and_record_completion INSPECT_PRIMARY_LEAF_PORTS
1061 fi
1062
1063 # Inspection of requirements of new leaf ports
1064 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1065 then
1066         PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES MAKE_DEPENDENTS_LISTS_UNIQUE INSPECT_PRIMARY_LEAF_PORTS PARSE_CONF'
1067         _program_exec_and_record_completion__operation ()
1068         {
1069                 local num_leaves num_leaves_prev num_inspect num_leaves_new
1070                 message_section_title "Inspection of requirements of new leaf ports"
1071                 message_echo "INFO: The inspection proceeds by iterative method."
1072                 while :
1073                 do
1074                         _program_exec_restartable_loop_operation__routine ()
1075                         {
1076                                 local origin origin_esc dbpath
1077                                 origin=$1
1078                                 pkgsys_is_pkgtool "$origin" && return
1079                                 dbpath=${DBDIR}/requires/$origin
1080                                 origin_esc=`str_escape_regexp "$origin"`
1081                                 grep -q -E "^$origin_esc$" "${DBDIR}/need.with_replaced.list" 2> /dev/null && return
1082                                 grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
1083                                         "$dbpath/dependents.all.full" > /dev/null 2>&1 && return
1084                                 cat "$dbpath/requirements.all.full" 2> /dev/null \
1085                                         >> ${DBDIR}/leaf_ports_secondary_candidates.new_requirements || :
1086                                 fileedit_add_a_line_if_new "^$origin_esc$" "${DBDIR}/grep.leaf_ports.pattern"
1087                         }
1088                         program_exec_restartable_loop_operation leaf_ports_secondary_candidates
1089                         num_leaves_prev=`cat "${DBDIR}/num_leaves"`
1090                         num_leaves=`wc -l < ${DBDIR}/grep.leaf_ports.pattern | tr -d ' '`
1091                         num_leaves_new=`echo $(($num_leaves-$num_leaves_prev)) | tr -d ' '`
1092                         if [ $num_leaves_new -eq 0 ]
1093                         then
1094                                 message_echo "  No more leaf port is found."
1095                                 message_echo "  $num_leaves leaf port(s) is/are found in total."
1096                                 break
1097                         fi
1098                         {
1099                                 grep -E -v -f "${DBDIR}/grep.leaf_ports.pattern" \
1100                                         "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates" || :
1101                                 cat "${DBDIR}/leaf_ports_secondary_candidates.new_requirements" || :
1102                         } | grep -v -E -f "${DBDIR}/conf/HOLD_PORTS.grep_pattern" | sort -u \
1103                                 > ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp || :
1104                         program_reset_loop_for_stage INSPECT_REQUIREMENTS_OF_LEAF_PORTS
1105                         mv "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates.tmp" \
1106                                 "${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates"
1107                         cp /dev/null "${DBDIR}/leaf_ports_secondary_candidates.new_requirements"
1108                         echo "$num_leaves" > ${DBDIR}/num_leaves
1109                         num_inspect=`wc -l < ${DBDIR}/stage.loop_list/leaf_ports_secondary_candidates | tr -d ' '`
1110                         message_echo "  $num_leaves_new leaf port(s) is/are newly found; continue for $num_inspect candidate(s)."
1111                 done
1112                 grep -E -f "${DBDIR}/grep.leaf_ports.pattern" "${DBDIR}/inspected_ports" | sort -u > ${DBDIR}/leaf_ports || :
1113                 message_echo
1114         }
1115         program_exec_and_record_completion INSPECT_REQUIREMENTS_OF_LEAF_PORTS
1116 fi
1117
1118 # Order the ports considering dependencies
1119 PROGRAM_DEPENDS='CONVERT_REQUIREMENTS_LIST'
1120 _program_exec_and_record_completion__operation ()
1121 {
1122         message_section_title "Ordering dependencies"
1123         if ! database_build_order_ports_considering_dependencies
1124         then
1125                 message_echo "ERROR: Unsatisfied dependencies are remained:" >&2
1126                 message_cat "${DBDIR}/unsatisfied.list"
1127                 message_echo "*** Aborted by ${APPNAME}"
1128                 message_echo "The ports tree seems broken. You might have caught an incomplete version."
1129                 message_echo "You are encouraged to update the ports tree by portsnap(8)."
1130                 message_echo "Then execute"
1131                 message_echo " ${APPNAME} clean"
1132                 message_echo "before restart."
1133                 temp_terminate_process () { :; }
1134                 exit 1
1135         fi
1136         message_echo
1137 }
1138 program_exec_and_record_completion ORDER_ALL_DEPENDENCIES
1139
1140 # Selection of removing leaf ports
1141 PROGRAM_DEPENDS='INSPECT_REQUIREMENTS_OF_LEAF_PORTS'
1142 _program_exec_and_record_completion__operation ()
1143 {
1144         message_section_title "Selection of removing leaf ports"
1145         deinstall_select_leaf_ports_to_delete
1146         message_echo
1147 }
1148 program_exec_and_record_completion SELECT_LEAF_PORTS
1149
1150 # Selection of removing obsolete ports
1151 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES PARSE_CONF'
1152 _program_exec_and_record_completion__operation ()
1153 {
1154         message_section_title "Selection of removing obsolete ports"
1155         deinstall_select_obsolete_ports_to_delete
1156         message_echo
1157 }
1158 program_exec_and_record_completion SELECT_OBSOLETE_PORTS
1159
1160 # Collection of leaf ports to delete
1161 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1162 then
1163         PROGRAM_DEPENDS='SELECT_LEAF_PORTS'
1164         _program_exec_and_record_completion__operation ()
1165         {
1166                 local src src_unselected reqptn_file src_with_initial_origins
1167                 message_section_title "Collecting leaf ports to delete"
1168                 src=${DBDIR}/leaf_ports
1169                 src_unselected=${DBDIR}/leaf_ports_to_delete.unselected
1170                 src_with_initial_origins=${DBDIR}/leaf_ports.with_ini
1171                 reqptn_file=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
1172                 cat "$src_unselected" 2> /dev/null | while read origin
1173                 do
1174                         cat "${DBDIR}/requires/$origin/requirements.all.full" || :
1175                 done | sort -u | str_escape_regexp_filter \
1176                         | sed 's/^/^/;s/$/$/' > $reqptn_file
1177                 database_query_add_initial_origins < $src > $src_with_initial_origins
1178                 message_echo
1179         }
1180         program_exec_and_record_completion COLLECT_LEAF_PORTS_TO_DELETE
1181 fi
1182
1183 # Collection of obsolete ports to delete
1184 PROGRAM_DEPENDS='SELECT_OBSOLETE_PORTS'
1185 _program_exec_and_record_completion__operation ()
1186 {
1187         local src src_selected src_unselected dst_selected reqptn_file
1188         message_section_title "Collecting obsolete ports to delete"
1189         src=${DBDIR}/obsolete_ports.can_be_deleted
1190         src_selected=${DBDIR}/obsolete_ports_to_delete.selected
1191         src_unselected=${DBDIR}/obsolete_ports_to_delete.unselected
1192         dst_selected=${DBDIR}/obsolete_ports_to_delete
1193         reqptn_file=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
1194         cat "$src_unselected" 2> /dev/null | while read origin
1195         do
1196                 cat "${DBDIR}/initial/$origin/requirements.run.full" || :
1197                 cat "${DBDIR}/obsolete/$origin/requirements.run.full" || :
1198         done | sort -u | str_escape_regexp_filter \
1199                 | sed 's/^/^/;s/$/$/' > $reqptn_file
1200         grep -v -E -f "$reqptn_file" "$src_selected" > $dst_selected 2> /dev/null || :
1201         message_echo
1202 }
1203 program_exec_and_record_completion COLLECT_OBSOLETE_PORTS_TO_DELETE
1204
1205 # Set up the list of ports to reinstall
1206 PROGRAM_DEPENDS='ORDER_ALL_DEPENDENCIES'
1207 _program_exec_and_record_completion__operation ()
1208 {
1209         message_section_title "Setting up the list of ports to reinstall"
1210         cp -p "${DBDIR}/reinst_order.list" "${DBDIR}/stage.loop_list/reinst_todo"
1211         message_echo
1212 }
1213 program_exec_and_record_completion SETUP_REINST_TODO
1214
1215 # Composition of a list for deinstallation of obsolete and leaf packages
1216 PROGRAM_DEPENDS='COLLECT_LEAF_PORTS_TO_DELETE COLLECT_OBSOLETE_PORTS_TO_DELETE'
1217 _program_exec_and_record_completion__operation ()
1218 {
1219         local reqptn_leaf reqptn_obs leaf_selected leaf_selected_src obs_selected obs_selected_src grepptn preserved
1220         message_section_title "Composing a list for deinstallation of obsolete and leaf packages"
1221         reqptn_leaf=${DBDIR}/leaf_ports.requirements_of_unselected.grep_pattern
1222         reqptn_obs=${DBDIR}/obsolete_ports.requirements_of_unselected.grep_pattern
1223         leaf_selected_src=${DBDIR}/leaf_ports_to_delete.selected
1224         leaf_selected=${DBDIR}/leaf_ports_to_delete
1225         obs_selected_src=${DBDIR}/obsolete_ports_to_delete.selected
1226         obs_selected=${DBDIR}/obsolete_ports_to_delete
1227         grepptn=${DBDIR}/ports_to_delete.grep_pattern
1228         grepptn_col1=${DBDIR}/ports_to_delete.grep_pattern_col1
1229         preserved=${TMPDIR}/LIST_DEINST_PKGS::preserved
1230         if [ ! -e "${DBDIR}/inspected_ports_only_partially" ]
1231         then
1232                 cat "$reqptn_leaf" "$reqptn_obs" 2> /dev/null | sort -u > $grepptn
1233                 grep -v -E -f "$grepptn" "$leaf_selected_src" 2> /dev/null \
1234                         | database_query_add_initial_origins > $leaf_selected || :
1235                 cat "$obs_selected" "$leaf_selected" 2> /dev/null || :
1236         else
1237                 rm -f "$leaf_selected"
1238                 cat "$obs_selected" 2> /dev/null
1239         fi | sort -u > ${DBDIR}/stage.loop_list/ports_to_delete
1240         str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
1241                 | sed 's/^/^/;s/$/$/' > $grepptn
1242         str_escape_regexp_filter < ${DBDIR}/stage.loop_list/ports_to_delete \
1243                 | sed 's/^/^/;s/$/[[:space:]]/' > $grepptn_col1
1244         cat "${DBDIR}/leaf_ports.with_ini" "${DBDIR}/obsolete_ports" 2> /dev/null \
1245                 | grep -E -v -f "$grepptn" > ${DBDIR}/stage.loop_list/ports_to_restore || :
1246         if [ $opt_batch_mode = no ]
1247         then
1248                 if [ ! -e "${DBDIR}/inspected_ports_only_partially" ] && \
1249                         grep -v -E -f "$grepptn" "$leaf_selected_src" > $preserved 2> /dev/null
1250                 then
1251                         message_echo "INFO: Following leaf ports are preserved because required by other preserved leaf/obsolete ports."
1252                         message_echo "----------------"
1253                         while read origin
1254                         do
1255                                 pkgtag=`cat "${DBDIR}/required/$origin/pkgtag" 2> /dev/null` || :
1256                                 if [ -n "$pkgtag" ]
1257                                 then
1258                                         echo "$origin" "($pkgtag)"
1259                                 else
1260                                         echo "$origin"
1261                                 fi
1262                         done < $preserved
1263                         message_echo "----------------"
1264                 fi
1265                 if grep -v -E -f "$grepptn" "$obs_selected_src" > $preserved 2> /dev/null
1266                 then
1267                         message_echo "INFO: Following obsolete ports are preserved because required by other obsolete ports."
1268                         message_echo "----------------"
1269                         while read origin
1270                         do
1271                                 pkgtag=`cat "${DBDIR}/initial/$origin/installed_version" 2> /dev/null` || :
1272                                 if [ -n "$pkgtag" ]
1273                                 then
1274                                         echo "$origin" "($pkgtag)"
1275                                 else
1276                                         echo "$origin"
1277                                 fi
1278                         done < $preserved
1279                         message_echo "----------------"
1280                 fi
1281         fi
1282         message_echo
1283 }
1284 program_exec_and_record_completion LIST_DEINST_PKGS
1285
1286 # Collect entire distfiles list
1287 if [ $opt_inspect_entire_distinfo = yes ]
1288 then
1289         PROGRAM_DEPENDS=''
1290         _program_exec_and_record_completion__operation ()
1291         {
1292                 message_section_title "Collecting entire distfiles list"
1293                 find "${PORTSDIR}" -depth 3 -name distinfo -exec cat {} \; \
1294                         | grep '^SHA256 ' | sed -E 's/^SHA256 \(([^)]*)\).*/\1/' \
1295                         | sort -u > ${DBDIR}/distfiles.entire.tmp
1296                 mv "${DBDIR}/distfiles.entire.tmp" "${DBDIR}/distfiles.entire"
1297                 message_echo
1298         }
1299         program_exec_and_record_completion COLLECT_ALL_DISTFILES_LIST
1300 fi
1301
1302 # Inspection of all required distfiles
1303 PROGRAM_DEPENDS='INSPECT_ALL_DEPENDENCIES COLLECT_ALL_DISTFILES_LIST'
1304 _program_exec_and_record_completion__operation ()
1305 {
1306         message_section_title "Summarizing distfiles list"
1307         cat "${DBDIR}/distfiles.entire" "${DBDIR}/distfiles.inspected" 2> /dev/null \
1308                 | sort -u | str_escape_regexp_filter \
1309                 | sed 's|^|^\\.\\/|; s|$|$|' > ${DBDIR}/distfiles.grep.pattern || :
1310         message_echo
1311 }
1312 program_exec_and_record_completion DISTFILES_LIST
1313
1314 # Clean up of reinstallation status for preparation
1315 PROGRAM_DEPENDS='REDO_INIT INSPECT_ALL_DEPENDENCIES'
1316 _program_exec_and_record_completion__operation ()
1317 {
1318         message_section_title "Cleaning up of reinstallation status for preparation"
1319         rm -rf "${DBDIR}/status.ports"
1320         message_echo
1321 }
1322 program_exec_and_record_completion CLEANUP_REINST_STATUS
1323
1324 # Completion of building the temporary database
1325 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'
1326 _program_exec_and_record_completion__operation ()
1327 {
1328         message_section_title "The temporary database is completely built up"
1329         message_echo
1330 }
1331 program_exec_and_record_completion PREPARATION
1332
1333
1334 # ==================================================
1335 # ====================== MAIN ======================
1336 # ==================================================
1337
1338 # Execute command operations which must be done before actual (re/de)installation processes
1339 command_exec_before_actual_re_de_installation "$@"
1340
1341 # Set termination messages
1342 temp_terminate_process ()
1343 {
1344         temp_terminate_process_common
1345 }
1346
1347 # Reinstallation of remained ports
1348 PROGRAM_DEPENDS='PREPARATION'
1349 _program_exec_restartable_loop_operation__routine ()
1350 {
1351         reinstall_exec "$@"
1352 }
1353 _program_exec_and_record_completion__operation ()
1354 {
1355         local _MSG_CURRENT_STAGE_general
1356         _MSG_CURRENT_STAGE_general="reinstallation"
1357         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1358         message_section_title "Reinstallation"
1359         program_exec_restartable_loop_operation reinst_todo
1360         reinstall_restore_conflicts
1361         temp_set_msg_current_stage
1362         message_echo
1363 }
1364 program_exec_and_record_completion REINSTALLATION
1365
1366 # Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again 
1367 PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1368 _program_exec_restartable_loop_operation__routine ()
1369 {
1370         deinstall_restore "$@"
1371 }
1372 _program_exec_and_record_completion__operation ()
1373 {
1374         local _MSG_CURRENT_STAGE_general
1375         _MSG_CURRENT_STAGE_general="restoration of unselected obsolete/leaf packages"
1376         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1377         message_section_title "Restoration of unselected obsolete/leaf packages"
1378         program_exec_restartable_loop_operation ports_to_restore
1379         temp_set_msg_current_stage
1380         message_echo
1381 }
1382 program_exec_and_record_completion RESTORE_ONCE_DEINST_PKGS
1383
1384 # Deinstallation of unused obsolete and leaf packages
1385 PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1386 _program_exec_restartable_loop_operation__routine ()
1387 {
1388         deinstall_exec "$@"
1389 }
1390 _program_exec_and_record_completion__operation ()
1391 {
1392         local _MSG_CURRENT_STAGE_general
1393         _MSG_CURRENT_STAGE_general="deinstallation of obsolete/leaf packages"
1394         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1395         message_section_title "Deinstallation of unused obsolete/leaf packages"
1396         program_exec_restartable_loop_operation ports_to_delete
1397         temp_set_msg_current_stage
1398         message_echo
1399 }
1400 program_exec_and_record_completion DEINST_UNUSED_PKGS
1401
1402 # Clean up obsolete or unused distfiles
1403 if [ $opt_only_target_scope = no -a $opt_keep_distfiles = no ]
1404 then
1405         PROGRAM_DEPENDS='REINSTALLATION DISTFILES_LIST'
1406         _program_exec_and_record_completion__operation ()
1407         {
1408                 local tmp_distfiles_exists
1409                 message_section_title "Cleaning up obsolete or unused distfiles"
1410                 tmp_distfiles_exists=${TMPDIR}/CLEANUP_OBSLETE_DISTFILES::distfiles_exists
1411                 [ $opt_dry_run = yes ] && message_echo "INFO: The operations are not actually carried out."
1412                 ( set -e; cd "${DISTDIR}" && find . -type f ) \
1413                         | sed 's|^\./||' | sort -u > $tmp_distfiles_exists
1414                 fileedit_manipulate_old_lines "$tmp_distfiles_exists" "${DBDIR}/distfiles.entire" \
1415                         | while read distfile
1416                 do
1417                         if [ $opt_batch_mode = no ]
1418                         then
1419                                 echo "  $distfile"
1420                         fi
1421                         [ $opt_dry_run = yes ] && continue
1422                         rm -f "${DISTDIR}/$distfile"
1423                 done
1424                 message_echo
1425         }
1426         program_exec_and_record_completion CLEANUP_OBSLETE_DISTFILES
1427 fi
1428
1429 # Rebuild of package database
1430 PROGRAM_DEPENDS='REINSTALLATION RESTORE_ONCE_DEINST_PKGS DEINST_UNUSED_PKGS'
1431 _program_exec_and_record_completion__operation ()
1432 {
1433         which -s pkgdb || return 0
1434         message_section_title "Rebuilding package database for portupgrade"
1435         pkgdb -fu
1436         message_echo
1437 }
1438 program_exec_and_record_completion REBUILD_PKGDB
1439
1440
1441 # ==================================================
1442 # ================ ENDING MESSAGES =================
1443 # ==================================================
1444
1445 # Notice of failures
1446 exists_unresolved_ports=
1447 message_summary_dependents_of_failed_reinstallation failure || exists_unresolved_ports=y
1448 message_summary_dependents_of_failed_reinstallation redo || exists_unresolved_ports=y
1449 message_summary_dependents_of_failed_reinstallation conflict || exists_unresolved_ports=y
1450 [ -n "$exists_unresolved_ports" ] && message_summary_advice_on_manual_solution
1451
1452 # End
1453 temp_terminate_process () { :; }
1454
1455 if [ -z "$exists_unresolved_ports" ]
1456 then
1457         message_section_title "COMPLETELY DONE"
1458         message_echo "- E N D -"
1459 else
1460         message_warn_no_achieved_progress || :
1461         message_section_title "Done with some unresolved problems"
1462         message_echo "- To be continued -"
1463 fi