OSDN Git Service

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