OSDN Git Service

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