OSDN Git Service

8d5f91b6279d0a717694fcbca0a4630d63e8d1e3
[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_command_specific_preconfiguration ()
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_command_specific_preconfiguration ()
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_command_specific_preconfiguration
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_determine_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_portoptiondbs_to_globs < $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                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1121         }
1122         _program_exec_and_record_completion__operation ()
1123         {
1124                 local _MSG_CURRENT_STAGE_general
1125                 _MSG_CURRENT_STAGE_general="reinstallation"
1126                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1127                 message_section_title "Reinstallation"
1128                 program_exec_restartable_loop_operation reinst_todo
1129                 [ "x$PROGRAM_STEP_COUNTER_LAST_SKIPPED" = xyes ] && message_stage_title "$PROGRAM_STEP_COUNTER"
1130                 reinstall_restore_conflicts
1131                 temp_set_msg_current_stage
1132                 message_echo
1133         }
1134         program_exec_and_record_completion REINSTALLATION
1135 }
1136
1137 # ============= Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again  =============
1138 command_do_restore_needed_obsolete_and_leaf_packages ()
1139 {
1140         local PROGRAM_DEPENDS
1141         PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1142         _program_exec_restartable_loop_operation__routine ()
1143         {
1144                 deinstall_restore "$@"
1145         }
1146         _program_exec_and_record_completion__operation ()
1147         {
1148                 local _MSG_CURRENT_STAGE_general
1149                 _MSG_CURRENT_STAGE_general="restoration of unselected obsolete/leaf packages"
1150                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1151                 message_section_title "Restoration of unselected obsolete/leaf packages"
1152                 program_exec_restartable_loop_operation ports_to_restore
1153                 [ "x$PROGRAM_STEP_COUNTER_LAST_SKIPPED" = xyes ] && message_stage_title "$PROGRAM_STEP_COUNTER"
1154                 temp_set_msg_current_stage
1155                 message_echo
1156         }
1157         program_exec_and_record_completion RESTORE_ONCE_DEINST_PKGS
1158 }
1159
1160 # ============= Deinstallation of unused obsolete and leaf packages =============
1161 command_do_deinstallation_of_unused_obsolete_and_leaf_packages ()
1162 {
1163         local PROGRAM_DEPENDS
1164         PROGRAM_DEPENDS='REDO_INIT LIST_DEINST_PKGS'
1165         _program_exec_restartable_loop_operation__routine ()
1166         {
1167                 deinstall_exec "$@"
1168         }
1169         _program_exec_and_record_completion__operation ()
1170         {
1171                 local _MSG_CURRENT_STAGE_general
1172                 _MSG_CURRENT_STAGE_general="deinstallation of obsolete/leaf packages"
1173                 temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
1174                 message_section_title "Deinstallation of unused obsolete/leaf packages"
1175                 program_exec_restartable_loop_operation ports_to_delete
1176                 [ "x$PROGRAM_STEP_COUNTER_LAST_SKIPPED" = xyes ] && message_stage_title "$PROGRAM_STEP_COUNTER"
1177                 temp_set_msg_current_stage
1178                 message_echo
1179         }
1180         program_exec_and_record_completion DEINST_UNUSED_PKGS
1181 }
1182
1183 # ============= Clean up obsolete or unused distfiles =============
1184 command_do_clean_up_obsolete_or_unused_distfiles ()
1185 {
1186         local PROGRAM_DEPENDS
1187         if [ $opt_only_target_scope = no -a $opt_keep_distfiles = no ]
1188         then
1189                 PROGRAM_DEPENDS='REINSTALLATION DISTFILES_LIST'
1190                 _program_exec_and_record_completion__operation ()
1191                 {
1192                         local tmp_distfiles_exists
1193                         message_section_title "Cleaning up obsolete or unused distfiles"
1194                         tmp_distfiles_exists=${TMPDIR}/CLEANUP_OBSLETE_DISTFILES::distfiles_exists
1195                         [ $opt_dry_run = yes ] && message_echo "INFO: The operations are not actually carried out."
1196                         ( set -e; cd "${DISTDIR}" && find . -type f ) \
1197                                 | sed 's|^\./||' | sort -u > $tmp_distfiles_exists
1198                         fileedit_manipulate_old_lines "$tmp_distfiles_exists" "${DBDIR}/distfiles.entire" \
1199                                 | while read distfile
1200                         do
1201                                 if [ $opt_batch_mode = no ]
1202                                 then
1203                                         echo "  $distfile"
1204                                 fi
1205                                 [ $opt_dry_run = yes ] && continue
1206                                 rm -f "${DISTDIR}/$distfile"
1207                         done
1208                         message_echo
1209                 }
1210                 program_exec_and_record_completion CLEANUP_OBSLETE_DISTFILES
1211         fi
1212 }
1213
1214 # ============= Rebuild of package database =============
1215 command_do_rebuild_of_package_database ()
1216 {
1217         local PROGRAM_DEPENDS
1218         PROGRAM_DEPENDS='REINSTALLATION RESTORE_ONCE_DEINST_PKGS DEINST_UNUSED_PKGS'
1219         _program_exec_and_record_completion__operation ()
1220         {
1221                 which -s pkgdb || return 0
1222                 message_section_title "Rebuilding package database for portupgrade"
1223                 if grep -q @ "${DBDIR}/stage.loop_list/reinst_todo"
1224                 then
1225                         message_echo "INFO: Skipped because of lacking flavor support."
1226                 else
1227                         pkgdb -fu
1228                 fi
1229                 message_echo
1230         }
1231         program_exec_and_record_completion REBUILD_PKGDB
1232 }
1233
1234 # =============Operation of redo command irrespective of option settings =============
1235 command_do_redo__command_all_exec_irrespective_of_saved_options ()
1236 {
1237         [ $opt_reload_conf = yes ] || return 0
1238         program_deregister_stage_complete SAVE_PREV_CONF
1239         program_deregister_stage_complete ALL_COMPLETE
1240         rm -f "${DBDIR}"/complete
1241 }
1242
1243 # ============= Preparation of the temporary database =============
1244 command_do_prepare ()
1245 {
1246         # Meta process for redo
1247         command_do_meta_process_for_redo
1248         
1249         # Determine specified targets
1250         command_do_determine_specified_targets
1251         
1252         # Show specified targets
1253         command_do_show_specified_targets
1254         
1255         # Determine all target ports
1256         command_do_determine_all_target_ports
1257         
1258         # Loop considering cases that port options are changed after inspection
1259         while true
1260         do
1261                 # Prepare for inspecting all dependencies
1262                 command_do_prepare_for_inspect_all_dependencies
1263                 
1264                 # Inspection of all dependencies
1265                 command_do_inspection_of_all_dependencies
1266                 
1267                 # Convert dependency-lists to actual ones
1268                 command_do_convert_dependency_lists_to_actual_ones
1269                 
1270                 # Completion of recursive requirement lists
1271                 command_do_completion_of_recursive_requirement_lists
1272                 
1273                 # Trim dependency lists by removing uninspected ports
1274                 command_do_trim_dependency_lists_by_removing_uninspected_ports
1275                 
1276                 # Inspection of dependents
1277                 command_do_inspection_of_dependents
1278                 
1279                 # End the loop when no change is made on port options after the inspection
1280                 command_do_reset_changed_portdb && break
1281         done
1282         
1283         # Remove duplicated lines in dependents lists
1284         command_do_remove_duplicated_lines_in_dependents_lists
1285         
1286         # Remove duplicated lines in ignored dependents lists
1287         command_do_remove_duplicated_lines_in_ignored_dependents_lists
1288         
1289         # Preparation of target attribute information
1290         command_do_preparation_of_target_attribute_information
1291         
1292         # Post-process after the preparation of target attribute information
1293         command_do_post_process_after_the_preparation_of_target_attribute_information
1294         
1295         # Build of data on complement to new dependents for target attribute information
1296         command_do_build_of_data_on_complement_to_new_dependents_for_target_attribute_information
1297         
1298         # Parse target attribute information
1299         command_do_parse_target_attribute_information
1300         
1301         # Inspection of necessity
1302         command_do_inspection_of_necessity
1303         
1304         # Inspection of necessary upgrades
1305         command_do_inspection_of_necessary_upgrades
1306         
1307         # Preparation for inspection of new leaf ports
1308         command_do_preparation_for_inspection_of_new_leaf_ports
1309         
1310         # Inspection of new primary leaf ports
1311         command_do_inspection_of_new_primary_leaf_ports
1312         
1313         # Inspection of requirements of new leaf ports
1314         command_do_inspection_of_requirements_of_new_leaf_ports
1315         
1316         # Order the ports considering dependencies
1317         command_do_order_the_ports_considering_dependencies
1318         
1319         # Selection of removing leaf ports
1320         command_do_selection_of_removing_leaf_ports
1321         
1322         # Selection of removing obsolete ports
1323         command_do_selection_of_removing_obsolete_ports
1324         
1325         # Collection of leaf ports to delete
1326         command_do_collection_of_leaf_ports_to_delete
1327         
1328         # Collection of obsolete ports to delete
1329         command_do_collection_of_obsolete_ports_to_delete
1330         
1331         # Set up the list of ports to reinstall
1332         command_do_set_up_the_list_of_ports_to_reinstall
1333         
1334         # Composition of a list for deinstallation of obsolete and leaf packages
1335         command_do_composition_of_a_list_for_deinstallation_of_obsolete_and_leaf_packages
1336         
1337         # Collect entire distfiles list
1338         command_do_collect_entire_distfiles_list
1339         
1340         # Inspection of all required distfiles
1341         command_do_inspection_of_all_required_distfiles
1342         
1343         # Clean up of reinstallation status for preparation
1344         command_do_clean_up_of_reinstallation_status_for_preparation
1345         
1346         # Completion of building the temporary database
1347         command_do_completion_of_building_the_temporary_database
1348 }
1349
1350 # ============= Reset the progress of reinstallation for retrial =============
1351 command_do_reset_for_reinst_retrial ()
1352 {
1353         program_deregister_stage_complete REINSTALLATION
1354         program_deregister_stage_complete RESTORE_ONCE_DEINST_PKGS
1355         program_deregister_stage_complete DEINST_UNUSED_PKGS
1356         rm -rf "${DBDIR}/status.ports" "${DBDIR}/new_success_in_current_run"
1357 }
1358
1359 # ============= Main operation of do/redo =============
1360 command_do_main ()
1361 {
1362         local ntrial
1363         # Reset termination messages
1364         temp_reset_termination_messages_common
1365         
1366         ntrial=0
1367         while true
1368         do
1369                 if [ $ntrial -gt 0 ]
1370                 then
1371                         message_echo "########## RETRIAL ($ntrial) OF (RE)INSTALLATION ##########"
1372                         message_echo
1373                 fi
1374                 
1375                 if [ $opt_fetch_only = yes ]
1376                 then
1377                         # Reinstallation of remained ports
1378                         command_do_reinstallation_of_remained_ports
1379                         
1380                         message_echo "Completed the fetch only mode."
1381                         exit
1382                 elif [ $opt_delete_then_reinstall = no ]
1383                 then
1384                         # Reinstallation of remained ports
1385                         command_do_reinstallation_of_remained_ports
1386                         
1387                         # Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again 
1388                         command_do_restore_needed_obsolete_and_leaf_packages
1389                         
1390                         # Deinstallation of unused obsolete and leaf packages
1391                         command_do_deinstallation_of_unused_obsolete_and_leaf_packages
1392                 else
1393                         # Deinstallation of unused obsolete and leaf packages
1394                         command_do_deinstallation_of_unused_obsolete_and_leaf_packages
1395                         
1396                         # Reinstallation of remained ports
1397                         command_do_reinstallation_of_remained_ports
1398                         # Restoration of obsolete and leaf packages which have been deinstalled but unselected from the deletion list again 
1399                         
1400                         command_do_restore_needed_obsolete_and_leaf_packages
1401                 fi
1402                 
1403                 # Clean up obsolete or unused distfiles
1404                 command_do_clean_up_obsolete_or_unused_distfiles
1405                 
1406                 # Rebuild of package database
1407                 command_do_rebuild_of_package_database
1408                 
1409                 # Retry if incomplete
1410                 command_do_is_everything_resolved && break
1411                 database_query_is_any_progress || break
1412                 command_do_reset_for_reinst_retrial
1413                 ntrial=$(($ntrial+1))
1414         done
1415         :
1416 }
1417
1418 # ============= Check whether everything is resolved =============
1419 command_do_is_everything_resolved ()
1420 {
1421         local subject
1422         for subject in failure redo conflict
1423         do
1424                 database_query_show_single_list_exec "$subject" \
1425                         `options_get_dependency_type` `options_get_dependency_level` > /dev/null 2> /dev/null && return 1
1426         done
1427         :
1428 }
1429
1430 # ============= Notice of failures =============
1431 command_do_failure_notice ()
1432 {
1433         local exists_unresolved_ports
1434         exists_unresolved_ports=
1435         message_summary_dependents_of_failed_reinstallation failure || exists_unresolved_ports=y
1436         message_summary_dependents_of_failed_reinstallation redo || exists_unresolved_ports=y
1437         message_summary_dependents_of_failed_reinstallation conflict || exists_unresolved_ports=y
1438         [ "x$exists_unresolved_ports" = xy ] || return 0
1439         message_summary_advice_on_manual_solution
1440         return 1
1441 }
1442
1443 # ============= Ending process =============
1444 command_do_ending_process ()
1445 {
1446         local PROGRAM_DEPENDS
1447         temp_terminate_process () { :; }
1448         if command_do_failure_notice
1449         then
1450                 if [ $opt_no_opening_message = yes ]
1451                 then
1452                         message_echo "Done as ${APPNAME}"
1453                         return
1454                 fi
1455                 message_section_title "COMPLETELY DONE"
1456                 if [ $opt_fetch_only = no -a $opt_dry_run = no ]
1457                         then
1458                         PROGRAM_DEPENDS='REBUILD_PKGDB CLEANUP_OBSLETE_DISTFILES '
1459                         _program_exec_and_record_completion__operation ()
1460                         {
1461                         }
1462                         program_exec_and_record_completion ALL_COMPLETE
1463                         message_echo "- E N D -"
1464                 else
1465                         message_echo "INFO: Redo for the real (re)installation."
1466                 fi
1467         else
1468                 message_warn_no_achieved_progress
1469                 message_section_title "Done with some unresolved problems"
1470                 message_echo "- To be continued -"
1471         fi
1472 }