OSDN Git Service

Version 3.0.5+toward_3.0.6_20140531202509
[portsreinstall/current.git] / lib / libcommand.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Operations of commands as well as check of command line arguments -
5 # Copyright (C) 2013-2014 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Variables =============
10 COMMAND_MODE=do
11 COMMAND_SHIFT=0
12 COMMAND_OPERATION=
13 COMMAND_SAVE_DIR=
14 COMMAND_LOAD_FILE=
15 COMMAND_SHOW_SUBJECT=
16 COMMAND_DO_MODE=all
17 COMMAND_RESTART=
18 COMMAND_SHOW_OPTIONS=
19 COMMAND_SHOW_DEPTAG=
20 COMMAND_SHOW_LEVEL=
21
22 # ============= Check the number of following command line arguments (in case glob arguments are needed) =============
23 _command_parse_args__chk_glob_args ()
24 {
25         local nargs
26         nargs=1
27         [ $nargs -gt 0 ] && return
28         message_echo "ERROR: No port glob is specified." >&2
29         exit 1
30 }
31
32 # ============= Check the number of following command line arguments (in case without arguments) =============
33 _command_parse_args__chk_no_arg ()
34 {
35         local nargs term_redundant_argument
36         nargs=$1
37         [ $nargs -eq 0 ] && return
38         term_redundant_argument='A redundant argument is'
39         [ $nargs -gt 1 ] && term_redundant_argument='Redundant arguments are'
40         message_echo "ERROR: $term_redundant_argument specified." >&2
41         exit 1
42 }
43
44 # ============= Execute command operations before getting the temporary database ready =============
45 command_exec_before_db_creation ()
46 {
47         local COMMAND_RESTART COMMAND_MODE COMMAND_OPERATION
48         COMMAND_RESTART="$@"
49         COMMAND_MODE=${1:-do}
50         shift || :
51         case $COMMAND_MODE in
52         clean)
53                 COMMAND_OPERATION=${1:-normal}
54                 shift || :
55                 case $COMMAND_OPERATION in
56                 force)
57                         message_echo "INFO: The temporary database is tried to be cleaned up without checking the privilege."
58                         rm -rf "${DBDIR}"
59                         message_echo "Done"
60                         exit
61                         ;;
62                 esac
63                 _command_parse_args__chk_no_arg $#
64                 ;;
65         esac
66 }
67
68 # ============= Check and parse command line arguments =============
69 command_parse_args ()
70 {
71         local num_args_init
72         num_args_init=$#
73         COMMAND_RESTART="$@"
74         COMMAND_MODE=${1:-do}
75         shift || :
76         case $COMMAND_MODE in
77         clean)
78                 COMMAND_OPERATION=${1:-normal}
79                 shift || :
80                 case $COMMAND_OPERATION in
81                 normal)
82                         misc_chk_privilege
83                         ;;
84                 esac
85                 _command_parse_args__chk_no_arg $#
86                 ;;
87         reset)
88                 misc_chk_privilege
89                 COMMAND_OPERATION=${1:-all}
90                 shift || :
91                 case $COMMAND_OPERATION in
92                 all|keepopts)
93                         ;;
94                 *)
95                         message_echo "ERROR: Invalid operation [$COMMAND_OPERATION]; it must be empty, \"all\" or \"keepopts\"." >&2
96                         exit 1
97                         ;;
98                 esac
99                 _command_parse_args__chk_no_arg $#
100                 ;;
101         ok|taboo|need|noneed)
102                 misc_chk_privilege
103                 [ $COMMAND_MODE = ok ] && database_query_chk_preparation_completion
104                 temp_warn_obsolete_temp_db
105                 COMMAND_OPERATION=$1
106                 shift || :
107                 case $COMMAND_OPERATION in
108                 add|del)
109                         ;;
110                 '')
111                         message_echo "ERROR: Missing operation which must be \"add\" or \"del\"." >&2
112                         exit 1
113                         ;;
114                 *)
115                         message_echo "ERROR: Invalid operation [$COMMAND_OPERATION]; it must be \"add\" or \"del\"." >&2
116                         exit 1
117                         ;;
118                 esac
119                 _command_parse_args__chk_glob_args $#
120                 ;;
121         reselect)
122                 misc_chk_privilege
123                 database_query_chk_preparation_completion
124                 temp_warn_obsolete_temp_db
125                 COMMAND_OPERATION=$1
126                 shift || :
127                 case $COMMAND_OPERATION in
128                 leaves)
129                         if [ -e "${DBDIR}/inspected_ports_only_partially" ]
130                         then
131                                 message_echo "ERROR: Leaf ports cannot be analyzed because the dependency inspection is partial." >&2
132                                 message_echo "Executing redo command with -N option by disabling -o option fixes this situation." >&2
133                                 exit 1
134                         fi
135                         ;;
136                 obsolete)
137                         ;;
138                 '')
139                         message_echo "ERROR: Missing operation which must be \"add\" or \"del\"." >&2
140                         exit 1
141                         ;;
142                 *)
143                         message_echo "ERROR: Invalid operation [$COMMAND_OPERATION]; it must be \"add\" or \"del\"." >&2
144                         exit 1
145                         ;;
146                 esac
147                 _command_parse_args__chk_glob_args $#
148                 ;;
149         save)
150                 misc_chk_privilege
151                 if [ ! -d "${DBDIR}" ]
152                 then
153                         message_echo "ERROR: The temporary database has not been created yet." >&2
154                         exit 1
155                 fi
156                 COMMAND_SAVE_DIR=$1
157                 shift || :
158                 _command_parse_args__chk_no_arg $#
159                 if [ -z "$COMMAND_SAVE_DIR" ]
160                 then
161                         message_echo "ERROR: Directory to save the temporary database archive is not specified." >&2
162                         exit 1
163                 fi
164                 if [ ! -d "$COMMAND_SAVE_DIR" ]
165                 then
166                         message_echo "ERROR: Directory [$COMMAND_SAVE_DIR] is not found." >&2
167                         exit 1
168                 fi
169                 ;;
170         load)
171                 misc_chk_privilege
172                 if [ -e "${DBDIR}/in_use" ]
173                 then
174                         message_echo "ERROR: A temporary database exists." >&2
175                         message_echo "You must execute" >&2
176                         message_echo "        ${APPNAME} clean" >&2
177                         message_echo "before executing \"load\" command." >&2
178                         exit 1
179                 fi
180                 COMMAND_LOAD_FILE=$1
181                 shift || :
182                 _command_parse_args__chk_no_arg $#
183                 if [ -z "$COMMAND_LOAD_FILE" ]
184                 then
185                         message_echo "ERROR: No temporary database archive is specified." >&2
186                         exit 1
187                 fi
188                 if [ ! -f "$COMMAND_LOAD_FILE" ]
189                 then
190                         message_echo "ERROR: The temporary database archive is not found." >&2
191                         exit 1
192                 fi
193                 COMMAND_LOAD_FILE=`realpath "$COMMAND_LOAD_FILE"`
194                 ;;
195         glob)
196                 _command_parse_args__chk_glob_args $#
197                 ;;
198         options)
199                 _command_parse_args__chk_no_arg $#
200                 ;;
201         reconf|rmconf|forget|escape|restore)
202                 misc_chk_privilege
203                 temp_warn_obsolete_temp_db
204                 _command_parse_args__chk_glob_args $#
205                 ;;
206         pkgsanity)
207                 misc_chk_privilege
208                 temp_warn_obsolete_temp_db
209                 ;;
210         show)
211                 database_query_chk_preparation_completion
212                 temp_warn_obsolete_temp_db
213                 if ! expr "$1" : '@.*' > /dev/null
214                 then
215                         COMMAND_SHOW_SUBJECT=${1:-todo}
216                         shift || :
217                 else
218                         COMMAND_SHOW_SUBJECT=todo
219                 fi
220                 COMMAND_SHOW_OPTIONS=$1
221                 if expr "$COMMAND_SHOW_OPTIONS" : '@.*' > /dev/null
222                 then
223                         COMMAND_SHOW_DEPTAG=`expr "$COMMAND_SHOW_OPTIONS," : '@\(.*\)' | cut -d , -f 1` || :
224                         COMMAND_SHOW_LEVEL=`expr "$COMMAND_SHOW_OPTIONS," : '@\(.*\)' | cut -d , -f 2` || :
225                         case $COMMAND_SHOW_DEPTAG in
226                         all|run|build|'')       ;;
227                         *)
228                                 message_echo "ERROR: Invalid show option [$COMMAND_SHOW_OPTIONS]." >&2
229                                 exit 1
230                                 ;;
231                         esac
232                         case $COMMAND_SHOW_LEVEL in
233                         full|direct|'') ;;
234                         *)
235                                 message_echo "ERROR: Invalid show option [$COMMAND_SHOW_OPTIONS]." >&2
236                                 exit 1
237                                 ;;
238                         esac
239                         shift || :
240                 fi
241                 case $COMMAND_SHOW_SUBJECT in
242                 todo|done|redo|resolved|failure|taboo|need|noneed|restored|deleted|conflict)
243                         _command_parse_args__chk_no_arg $#
244                         ;;
245                 initrequirements|requirements|initdependents|dependents|status)
246                         _command_parse_args__chk_glob_args $#
247                         ;;
248                 *)
249                         message_echo "ERROR: Invalid subject [$COMMAND_SHOW_SUBJECT]." >&2
250                         exit 1
251                         ;;
252                 esac
253                 ;;
254         all|prepare)
255                 COMMAND_DO_MODE=$COMMAND_MODE
256                 COMMAND_MODE=do
257                 misc_chk_privilege
258                 temp_warn_obsolete_temp_db
259                 _command_parse_args__chk_no_arg $#
260                 ;;
261         redo|do)
262                 COMMAND_DO_MODE=${1:-all}
263                 shift || :
264                 case $COMMAND_DO_MODE in
265                 all|prepare);;
266                 *)
267                         message_echo "ERROR: Invalid operation mode [$COMMAND_DO_MODE]." >&2
268                         exit 1
269                         ;;
270                 esac
271                 misc_chk_privilege
272                 temp_warn_obsolete_temp_db
273                 _command_parse_args__chk_no_arg $#
274                 if [ "$COMMAND_DO_MODE" = prepare ]
275                 then
276                         COMMAND_RESTART=prepare
277                 else
278                         COMMAND_RESTART=
279                 fi
280                 ;;
281         *)
282                 message_echo "ERROR: Invalid command [$COMMAND_MODE]." >&2
283                 exit 1
284                 ;;
285         esac
286         COMMAND_SHIFT=$(($num_args_init - $#))
287 }
288
289 # ============= Notify that option settings are reset =============
290 command_exec_without_pkgtools__notify_reset_options ()
291 {
292         message_echo "NOTE: Option settings are ignored (because of no effect) and reset."
293 }
294
295 # ============= Execute command operations which do not need package tools =============
296 command_exec_without_pkgtools ()
297 {
298         local dbdir_parent 
299         case $COMMAND_MODE in
300         clean)
301                 message_echo "Starting to clean up the temporary database..."
302                 command_exec_without_pkgtools__notify_reset_options
303                 rm -rf "${DBDIR}"
304                 message_echo "Done"
305                 exit
306                 ;;
307         load)
308                 message_echo "Starting to load the temporary database from the archive..."
309                 command_exec_without_pkgtools__notify_reset_options
310                 dbdir_parent=`dirname "${DBDIR}"`
311                 [ -d "$dbdir_parent" ] || mkdir -p "$dbdir_parent"
312                 tar xzf "$COMMAND_LOAD_FILE" -C "$dbdir_parent" --exclude "*/.lock"
313                 message_echo "Done"
314                 exit
315                 ;;
316         esac
317 }
318
319 # ============= Notify that option settings are ignored because of no effect =============
320 _command_exec_irrespective_of_saved_options__notify_ignored_options ()
321 {
322         message_echo "NOTE: Option settings are ignored because they have no effect on this command."
323 }
324
325 # ============= Operations of forget command =============
326 command_forget ()
327 {
328         message_echo "The temporary database is trying to forget about the specified ports as much as possible."
329         message_echo "Concretely, the data on each of the specified ports and their requirements/dependents is removed unless initially installed or required by other preserved ports."
330         message_echo
331         
332         # Preparation for inspection of the specified ports
333         PROGRAM_DEPENDS=''
334         _program_exec_and_record_completion__operation ()
335         {
336                 message_section_title "Preparation for inspection of the specified ports"
337                 rm -rf "${DBDIR}/forget"
338                 mkdir "${DBDIR}/forget"
339                 for list in masters remove_scope
340                 do
341                         rm -f "${DBDIR}/stage.loop_list/forget_$list"*
342                 done
343                 message_echo
344         }
345         program_exec_and_record_completion FORGET::PREPARATION_INSPECT_MASTER
346         
347         # (Re)initialization of the specified ports to inspect
348         pkgsys_eval_ports_glob "$@" > ${DBDIR}/stage.loop_list/forget_masters
349         
350         # Inspection of the specified ports
351         PROGRAM_DEPENDS='FORGET::PREPARATION_INSPECT_MASTER'
352         _program_exec_restartable_loop_operation__routine ()
353         {
354                 local origin origin_orig
355                 origin=$1
356                 if [ -e "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern" ]
357                 then
358                         origin_orig=`echo "$origin" \
359                                 | sed -E -f "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"`
360                 else
361                         origin_orig=$origin
362                 fi
363                 if [ ! -e "${DBDIR}/initial/$origin/installed_version" \
364                         -a ! -e "${DBDIR}/initial/$origin_orig/installed_version" \
365                         -a `cat "${DBDIR}/requires/$origin/dependents.all.full" 2> /dev/null | wc -l` -eq 0 ]
366                 then
367                         message_echo "$origin"
368                         echo "$origin" >> ${DBDIR}/forget/remove.master
369                         cat "${DBDIR}/requires/$origin/requirements.all.full" \
370                                 2> /dev/null >> ${DBDIR}/forget/remove.scope || :
371                         database_build_forget "$origin"
372                 fi
373         }
374         _program_exec_and_record_completion__operation ()
375         {
376                 message_section_title "Inspection of the specified ports"
377                 message_echo "----------------"
378                 program_exec_restartable_loop_operation forget_masters
379                 message_echo "----------------"
380                 cat "${DBDIR}/forget/remove.scope" 2> /dev/null \
381                         | sort -u > ${DBDIR}/forget/remove.scope.tmp
382                 mv "${DBDIR}/forget/remove.scope.tmp" "${DBDIR}/forget/remove.scope"
383                 cat "${DBDIR}/forget/remove.master" "${DBDIR}/forget/remove.scope" 2> /dev/null \
384                         | str_escape_regexp_filter \
385                         | sed 's/^/^/;s/$/$/' > ${DBDIR}/forget/remove.scope.grep_pattern
386                 ln -f "${DBDIR}/forget/remove.scope" "${DBDIR}/stage.loop_list/forget_remove_scope"
387                 message_echo
388         }
389         program_exec_and_record_completion FORGET::INSPECT_MASTER
390         
391         # Inspection of the requirements of the specified ports to remove
392         PROGRAM_DEPENDS='FORGET::INSPECT_MASTER'
393         _program_exec_restartable_loop_operation__routine ()
394         {
395                 local origin origin_orig
396                 origin=$1
397                 if [ -e "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern" ]
398                 then
399                         origin_orig=`echo "$origin" \
400                                 | sed -E -f "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"`
401                 else
402                         origin_orig=$origin
403                 fi
404                 if [ ! -e "${DBDIR}/initial/$origin/installed_version" \
405                         -a ! -e "${DBDIR}/initial/$origin_orig/installed_version" ] \
406                         && ! grep -v -E -f "${DBDIR}/forget/remove.scope.grep_pattern" \
407                                 "${DBDIR}/requires/$origin/dependents.all.full" \
408                                 > /dev/null 2>&1
409                 then
410                         message_echo "$origin"
411                         database_build_forget "$origin"
412                         echo "$origin" >> ${DBDIR}/forget/remove
413                 fi
414         }
415         _program_exec_and_record_completion__operation ()
416         {
417                 message_section_title "Inspection of the requirements of the specified ports to remove"
418                 message_echo "----------------"
419                 program_exec_restartable_loop_operation forget_remove_scope
420                 message_echo "----------------"
421                 cat "${DBDIR}/forget/remove.master" "${DBDIR}/forget/remove" 2> /dev/null \
422                         | str_escape_regexp_filter \
423                         | sed 's/^/^/;s/$/$/' > ${DBDIR}/forget/remove.grep_pattern
424                 cat "${DBDIR}/inspected_ports.update" 2> /dev/null | sort -u \
425                         | grep -v -E -f "${DBDIR}/forget/remove.grep_pattern" \
426                                 > ${DBDIR}/inspected_ports.update.tmp || :
427                 mv "${DBDIR}/inspected_ports.update.tmp" "${DBDIR}/inspected_ports.update"
428                 message_echo
429         }
430         program_exec_and_record_completion FORGET::INSPECT_REQUIREMENTS_OF_REMOVED_PORTS
431         
432         # Set up so that ports are inspected again in the building process of the temporary database
433         program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
434         
435         # Clean up the database for this command because it is no more effective
436         program_deregister_stage_complete FORGET::PREPARATION_INSPECT_MASTER
437         message_echo "Done"
438 }
439
440 # ============= Execute command operations which are irrespective of option settings =============
441 command_exec_irrespective_of_saved_options ()
442 {
443         local dbfile tmp_manually_done_diff evalated_globs dbdir_parent dbdir_node arcfile grandtitle title isfirst origin origin_regexp backup_pkg origin_orig origin_replace pkg_orig tmp_done_orig tmp_pkgsanity nlines iline pkg make_target
444         case $COMMAND_MODE in
445         ok)
446                 dbfile=${DBDIR}/manually_done.list
447                 [ -e "$dbfile" ] || touch "$dbfile"
448                 cp "$dbfile" "$dbfile.tmp"
449                 case $COMMAND_OPERATION in
450                 add)
451                         pkgsys_register_evaluated_globs add "$dbfile.tmp" "$@"
452                         message_echo "`str_linearize_list_and \"$*\"` is/are registered to the list of manually resolved ports"
453                         ;;
454                 del)
455                         pkgsys_register_evaluated_globs remove "$dbfile.tmp" "$@"
456                         message_echo "`str_linearize_list_and \"$*\"` is/are deregistered from the list of manually resolved ports"
457                         ;;
458                 esac
459                 tmp_manually_done_diff_old=${TMPDIR}/command_exec_irrespective_of_saved_options:manually_done.list.diff_old
460                 tmp_manually_done_diff_new=${TMPDIR}/command_exec_irrespective_of_saved_options:manually_done.list.diff_new
461                 if fileedit_manipulate_old_new_lines "$dbfile" "$dbfile.tmp" \
462                         "$tmp_manually_done_diff_old" "$tmp_manually_done_diff_new"
463                 then
464                         while read origin
465                         do
466                                 database_record_failure "$origin"
467                         done < $tmp_manually_done_diff_old
468                         while read origin
469                         do
470                                 database_record_success "$origin"
471                         done < $tmp_manually_done_diff_new
472                 fi
473                 mv "$dbfile.tmp" "$dbfile"
474                 _command_exec_irrespective_of_saved_options__notify_ignored_options
475                 message_echo "Now the following ports have been manually resolved:"
476                 message_cat "$dbfile"
477                 exit
478                 ;;
479         taboo)
480                 evalated_globs=`str_linearize_list_and "$@"`
481                 case $COMMAND_OPERATION in
482                 add)
483                         pkgsys_register_evaluated_globs add "${DBDIR}/taboo.list" "$@"
484                         message_echo "$evalated_globs is/are registered to the list of ports to be ignored."
485                         ;;
486                 del)
487                         pkgsys_register_evaluated_globs remove "${DBDIR}/taboo.list" "$@"
488                         message_echo "$evalated_globs is/are deregistered from the list of ports to be ignored."
489                         ;;
490                 esac
491                 fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" > ${DBDIR}/taboo.all.list
492                 _command_exec_irrespective_of_saved_options__notify_ignored_options
493                 message_echo "Now the following ports are registered to be ignored:"
494                 message_cat "${DBDIR}/taboo.all.list"
495                 exit
496                 ;;
497         need)
498                 evalated_globs=`str_linearize_list_and "$@"`
499                 case $COMMAND_OPERATION in
500                 add)
501                         pkgsys_register_evaluated_globs add "${DBDIR}/need.list" "$@"
502                         message_echo "$evalated_globs is/are registered to the list of necessary ports."
503                         ;;
504                 del)
505                         pkgsys_register_evaluated_globs remove "${DBDIR}/need.list" "$@"
506                         message_echo "$evalated_globs is/are deregistered from the list of necessary ports."
507                         ;;
508                 esac
509                 str_escape_regexp_filter < ${DBDIR}/need.list \
510                         | sed 's/^/^/; s/$/$/' > ${DBDIR}/need.grep_pattern
511                 {
512                         sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "${DBDIR}/need.list" || :
513                         cat "${DBDIR}/need.list" || :
514                 } 2> /dev/null | sort -u > ${DBDIR}/need.with_replaced.list
515                 program_deregister_stage_complete DETERMINE_SPECIFIED_TARGETS
516                 _command_exec_irrespective_of_saved_options__notify_ignored_options
517                 message_echo "Now the following ports are registered to be necessary:"
518                 message_cat "${DBDIR}/need.list"
519                 exit
520                 ;;
521         noneed)
522                 evalated_globs=`str_linearize_list_and "$@"`
523                 case $COMMAND_OPERATION in
524                 add)
525                         pkgsys_register_evaluated_globs add "${DBDIR}/noneed.list" "$@"
526                         message_echo "$evalated_globs is/are registered to the list of unnecessary ports."
527                         ;;
528                 del)
529                         pkgsys_register_evaluated_globs remove "${DBDIR}/noneed.list" "$@"
530                         message_echo "$evalated_globs is/are deregistered from the list of unnecessary ports."
531                         ;;
532                 esac
533                 program_deregister_stage_complete INSPECT_PRIMARY_LEAF_PORTS
534                 _command_exec_irrespective_of_saved_options__notify_ignored_options
535                 message_echo "Now the following ports are registered to be unnecessary:"
536                 message_cat "${DBDIR}/noneed.list"
537                 exit
538                 ;;
539         reselect)
540                 case $COMMAND_OPERATION in
541                 leaves)
542                         if ! deinstall_select_leaf_ports_to_delete force
543                         then
544                                 case $? in
545                                 2)
546                                         message_echo "INFO: No leaf port is found."
547                                         ;;
548                                 3)
549                                         message_echo "INFO: Leaf ports are undefined because requirements of some ports are not fully inspected."
550                                         ;;
551                                 esac
552                         else
553                                 program_deregister_stage_complete COLLECT_LEAF_PORTS_TO_DELETE
554                         fi
555                         ;;
556                 obsolete)
557                         if ! deinstall_select_obsolete_ports_to_delete force
558                         then
559                                 case $? in
560                                 2)
561                                         message_echo "INFO: No obsolete package is found."
562                                         ;;
563                                 esac
564                         else
565                                 program_deregister_stage_complete COLLECT_OBSOLETE_PORTS_TO_DELETE
566                         fi
567                         ;;
568                 esac
569                 exit
570                 ;;
571         save)
572                 dbdir_parent=`dirname "${DBDIR}"`
573                 dbdir_node=`basename "${DBDIR}"`
574                 arcfile=`realpath "$COMMAND_SAVE_DIR"`/${APPNAME}_`date +%Y%m%d_%H%M%S`.tar.gz
575                 _command_exec_irrespective_of_saved_options__notify_ignored_options
576                 message_echo "Starting to save the temporary database as [$arcfile]..."
577                 tar czf "$arcfile" -C "$dbdir_parent" "$dbdir_node"
578                 message_echo "Done"
579                 exit
580                 ;;
581         glob)
582                 _command_exec_irrespective_of_saved_options__notify_ignored_options
583                 message_echo "Evaluated port origins are as follows:"
584                 pkgsys_eval_ports_glob "$@"
585                 exit
586                 ;;
587         reconf|rmconf)
588                 _command_exec_irrespective_of_saved_options__notify_ignored_options
589                 case $COMMAND_MODE in
590                 reconf)
591                         message_echo "Reconfigure the specified port options."
592                         make_target=config
593                         ;;
594                 rmconf)
595                         message_echo "The specified port options are reset to the default."
596                         make_target=rmconfig
597                         ;;
598                 esac
599                 message_echo "Affected parts of the temporary database are reset automatically."
600                 for origin in `pkgsys_eval_ports_glob "$@"`
601                 do
602                         origin_regexp=`str_escape_regexp "$origin"`
603                         if grep -q -E "^$origin_regexp$" "${DBDIR}/inspected_ports" 2> /dev/null
604                         then
605                                 database_build_make "$origin" $make_target
606                                 database_build_patch_reconf "$origin"
607                         else
608                                 message_echo "$origin (not inspected)"
609                                 continue
610                         fi
611                 done
612                 program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
613                 message_echo "Done"
614                 exit
615                 ;;
616         forget)
617                 _command_exec_irrespective_of_saved_options__notify_ignored_options
618                 command_forget "$@"
619                 exit
620                 ;;
621         escape)
622                 _command_exec_irrespective_of_saved_options__notify_ignored_options
623                 message_echo "Backing up and deleting the following packages for a temporary escape:"
624                 message_echo
625                 for origin in `pkgsys_eval_ports_glob "$@"`
626                 do
627                         pkgsys_register_evaluated_globs add "${DBDIR}/taboo.list" "$origin"
628                         message_echo "  Registered $origin as taboo."
629                         pkg=`pkg_info_qO "$origin"` || continue
630                         [ -n "$pkg" ] || continue
631                         if backup_pkg=`pkgsys_get_backup_pkg "$origin"`
632                         then
633                                 message_echo "INFO: A backup package for $pkg ($origin) already exists as $backup_pkg."
634                         elif backup_pkg=`pkgsys_create_backup_pkg "$pkg" "${DBDIR}/backup_packages"`
635                         then
636                                 message_echo "  Backed up $pkg ($origin) into $backup_pkg"
637                         else
638                                 message_echo "ERROR: Failed to back up $pkg ($origin)." >&2
639                                 message_echo >&2
640                                 continue
641                         fi
642                         pkg_delete_f "$pkg" || \
643                         {
644                                 message_echo "ERROR: Failed to deinstall $pkg ($origin)." >&2
645                                 message_echo >&2
646                         }
647                         message_echo "  Deinstalled $pkg ($origin)."
648                         message_echo
649                 done
650                 fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" > ${DBDIR}/taboo.all.list
651                 message_echo "Done"
652                 exit
653                 ;;
654         restore)
655                 _command_exec_irrespective_of_saved_options__notify_ignored_options
656                 message_echo "Restoring the following temporary escaped packages:"
657                 message_echo
658                 tmp_done_orig=${TMPDIR}/command_exec_irrespective_of_saved_options::restore::done_orig
659                 cp /dev/null "$tmp_done_orig"
660                 for origin in `pkgsys_eval_ports_glob "$@"`
661                 do
662                         pkgsys_register_evaluated_globs remove "${DBDIR}/taboo.list" "$origin"
663                         message_echo "  Deregistered $origin from taboo."
664                         origin_regexp=`str_escape_regexp "$origin"`
665                         grep -E -q "^$origin_regexp$" "$tmp_done_orig" || :
666                         if pkg_info_eO "$origin"
667                         then
668                                 pkg=`pkg_info_qO "$origin"` || :
669                                 message_echo "WARNING: $pkg ($origin) is already installed." >&2
670                                 message_echo >&2
671                                 continue
672                         fi
673                         origin_orig=`echo "$origin" \
674                                 | sed -E -f "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"`
675                         if [ "x$origin_orig" = "x$origin" ] && pkg_info_eO "$origin_orig"
676                         then
677                                 pkg_orig=`pkg_info_qO "$origin_orig"` || :
678                                 message_echo "WARNING: An original version of $origin ($pkg_orig, $origin_orig) is already installed." >&2
679                                 message_echo >&2
680                                 continue
681                         fi
682                         origin_replace=`echo "$origin" \
683                                 | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern"`
684                         if [ "x$origin_replace" != "x$origin" ]
685                         then
686                                 if pkg_info_eO "$origin_replace"
687                                 then
688                                         pkg_replace=`pkg_info_qO "$origin_replace"` || :
689                                         message_echo "WARNING: A replacement of $origin ($pkg_replace, $origin_replace) is already installed." >&2
690                                         message_echo >&2
691                                         continue
692                                 fi
693                                 if backup_pkg=`pkgsys_get_backup_pkg "$origin_replace" 2> /dev/null`
694                                 then
695                                         message_echo "INFO: $origin is replaced with $origin_replace ($pkg_replace)."
696                                         echo "$origin_replace" >> $tmp_done_orig
697                                         origin=$origin_replace
698                                 fi
699                         else
700                                 backup_pkg=
701                         fi
702                         if [ -z "$backup_pkg" ] && ! backup_pkg=`pkgsys_get_backup_pkg "$origin" 2> /dev/null`
703                         then
704                                 message_echo "ERROR: Backup for $origin is not found." >&2
705                                 message_echo >&2
706                                 continue
707                         fi
708                         pkg=`pkgsys_pkgarc_to_pkgname "$backup_pkg"`
709                         if reinstall_chk_forbidden_conflicts "$pkg"
710                         then
711                                 message_echo "WARNING: $pkg ($origin) is skipped because it conflicts with installed packages." >&2
712                                 message_echo >&2
713                                 continue
714                         fi
715                         if ! pkg_add_fF "$backup_pkg"
716                         then
717                                 message_echo "ERROR: Failed to restore $pkg ($origin)." >&2
718                                 message_echo >&2
719                         fi
720                         message_echo "  Restored $pkg ($origin)."
721                         message_echo
722                 done
723                 fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" > ${DBDIR}/taboo.all.list
724                 message_echo "Done"
725                 exit
726                 ;;
727         pkgsanity)
728                 tmp_pkgs=${TMPDIR}/command_exec_irrespective_of_saved_options:pkgs
729                 tmp_orgs=${TMPDIR}/command_exec_irrespective_of_saved_options:orgs
730                 tmp_pkgs_for_an_org=${TMPDIR}/command_exec_irrespective_of_saved_options:pkgs_for_an_org
731                 tmp_pkgs_for_an_org_msg=${TMPDIR}/command_exec_irrespective_of_saved_options:pkgs_for_an_org_msg
732                 _command_exec_irrespective_of_saved_options__notify_ignored_options
733                 if [ $# -eq 0 ]
734                 then
735                         message_echo "Sanity check of the installed files for each package:"
736                         message_echo
737                         pkg_info_Ea > $tmp_pkgs
738                         pkg_info_qoa > $tmp_orgs
739                 else
740                         message_echo "Examining the installed files for each specified package:"
741                         message_echo
742                         pkgsys_eval_ports_glob "$@" > $tmp_orgs
743                         while read origin
744                         do
745                                 pkg_info_qO "$origin" || :
746                         done < $tmp_orgs | grep -v '^[[:space:]]*$' > $tmp_pkgs
747                 fi
748                 message_echo "<< Phase 1: Check and fix duplicated packages registrations for the same port origin >>"
749                 message_echo
750                 while read origin
751                 do
752                         [ `pkg_info_qO "$origin" | wc -l` -gt 1 ] || continue
753                         pkg_info_qO "$origin" | while read pkg
754                         do
755                                 echo "$((0+`pkg_check_sanity \"$pkg\" | wc -l`))" "$pkg"
756                         done | sort -g > $tmp_pkgs_for_an_org
757                         pkg_valid=`head -n 1 "$tmp_pkgs_for_an_org" | cut -d ' ' -f 2`
758                         message_echo "Port [$origin] has multiply registered packages."
759                         message_echo "The valid one will be [$pkg_valid]."
760                         message_echo "Invalid one(s) will be as follows and to be deleted:"
761                         sed 1d "$tmp_pkgs_for_an_org" | cut -d ' ' -f 2 > $tmp_pkgs_for_an_org_msg
762                         message_cat "$tmp_pkgs_for_an_org_msg"
763                         errout=/dev/stderr
764                         [ "x$opt_batch_mode" = xyes ] && errout=/dev/null
765                         if backup_pkg=`pkgsys_create_backup_pkg "$pkg_valid" "${DBDIR}/backup_packages"`
766                         message_echo
767                         then
768                                 pkg_delete_f `cat "$tmp_pkgs_for_an_org"` 2> $errout || {
769                                         message_echo "WARNING: Deletion of the broken packages may not be fully successful, but continuing anyway." >&2
770                                         message_echo >&2
771                                 }
772                                 pkg_add_fF "$backup_pkg" || {
773                                         message_echo "WARNING: Reinstallation of the most valid package failed, but continuing anyway." >&2
774                                         message_echo >&2
775                                 }
776                         else
777                                 message_echo "WARNING: Backup of the most valid package failed, but continuing anyway." >&2
778                                 pkg_delete_f `cat "$tmp_pkgs_for_an_org"` 2> $errout || {
779                                         message_echo "WARNING: Deletion of the broken packages may not be fully successful, but continuing anyway." >&2
780                                         message_echo >&2
781                                 }
782                         fi
783                 done < $tmp_orgs
784                 
785                 message_echo "<< Phase 2: Check and mark broken packages for reinstallation >>"
786                 message_echo
787                 nlines=`wc -l < $tmp_pkgs`
788                 iline=1
789                 while [ $iline -le $nlines ]
790                 do
791                         pkg=`sed -n ${iline}p "$tmp_pkgs"`
792                         iline=$((${iline}+1))
793                         origin=`pkg_info_qo "$pkg"` || continue
794                         [ -n "$origin" ] || continue
795                         origin_regexp=`str_escape_regexp "$origin"`
796                         grep -q -E "^$origin_regexp$" "${DBDIR}/damaged_package" 2>/dev/null && continue
797                         pkgsys_sanitychk_pkgcontents "$pkg" is_reinstall_encouraged && continue
798                         if [ ! -d "${PORTSDIR}/$origin" ]
799                         then
800                                 message_echo "WARNING: $pkg ($origin) is obsolete." >&2
801                                 message_echo >&2
802                                 continue
803                         fi
804                         if [ $is_reinstall_encouraged = no ]
805                         then
806                                 if [ $opt_batch_mode = no ]
807                                 then
808                                         message_echo "Do you want to reinstall it? (y/[n])"
809                                         message_query_yn_default_no || continue
810                                 fi
811                         else
812                                 if [ $opt_batch_mode = no ]
813                                 then
814                                         message_echo "Do you want to reinstall it? ([y]/n)"
815                                         message_query_yn_default_yes || continue
816                                 fi
817                                 database_record_reconf_recover_sanity "$origin"
818                         fi
819                 done
820                 message_echo "Done"
821                 exit
822                 ;;
823         redo)
824                 if [ $opt_reload_conf = yes ]
825                 then
826                         program_deregister_stage_complete SAVE_PREV_CONF
827                 fi
828                 ;;
829         esac
830 }
831
832 # ============= Output of "options" command =============
833 _command_exec_before_tools_upgrade__options ()
834 {
835         local opt_control group_reset group_remain reset_opts result_opts str_opt_control str_rstoption notice_reset notice_result
836         opt_control=$1
837         group_reset=$2
838         group_remain=$3
839         reset_opts=`options_inverse_parse $group_reset`
840         result_opts=`options_inverse_parse $group_remain`
841         if [ $is_batch_mode = yes ]
842         then
843                 printf '%s\t%s\t%s\n' "$opt_control" "$reset_opts" "$result_opts"
844         else
845                 str_opt_control=`echo "$opt_control" | sed -E 's/(.)/-\1 /g;s/ *$//'`
846                 str_rstoption=Option`[ \`echo -n "$opt_control" | wc -c\` -ge 2 ] && echo s` || :
847                 notice_reset=`[ -z "$reset_opts" ] && echo ' (nothing)'` || :
848                 notice_result=`[ -z "$result_opts" ] && echo ' (default)'` || :
849                 echo "$str_rstoption [$str_opt_control] will reset [$reset_opts]$notice_reset so that the settings become [$result_opts]$notice_result."
850         fi
851 }
852
853 # ============= Execute command operations which should be done without upgrade of tools =============
854 command_exec_before_tools_upgrade ()
855 {
856         local flag_filter_skip_unchanged flag_filter_only_target pkgnamedb dbsuffix list origin_target
857         case $COMMAND_MODE in
858         reset)
859                 message_echo "Starting to reset the temporary database by preserving the initial snapshot of installed packages..."
860                 find "${DBDIR}" -depth 1 \
861                         -not \( -name saved_options.sh \
862                                 -or -name initial -or -name MYVERSION \
863                                 -or -name backup_failure -or -name installed_ports\* \) \
864                         -exec rm -rf {} \; 2> /dev/null || :
865                 case $COMMAND_OPERATION in
866                 all)
867                         command_exec_without_pkgtools__notify_reset_options
868                         rm -f "${DBDIR}/saved_options.sh"
869                         ;;
870                 keepopts)
871                         message_echo "INFO: option settings are preserved."
872                         ;;
873                 esac
874                 find "${DBDIR}/initial" -depth 2 -type d \
875                         | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/inspected_ports.update
876                 mkdir -p "${DBDIR}/stage.loop_list"
877                 message_echo "Done"
878                 exit
879                 ;;
880         options)
881                 ( set -e
882                         is_batch_mode=$opt_batch_mode
883                         options_set_default
884                         [ -e "${DBDIR}/saved_options.sh" ] && . "${DBDIR}/saved_options.sh"
885                         savedopts=`options_inverse_parse`
886                         if [ $is_batch_mode = yes ]
887                         then
888                                 printf '\t%s\n' "$savedopts"
889                         else
890                                 echo "The saved setting is [$savedopts]."
891                         fi
892                         _command_exec_before_tools_upgrade__options M \
893                                 'renewable_anytime' 'non_renewable renewable_in_redo_on_target renewable_in_redo_on_conf'
894                         _command_exec_before_tools_upgrade__options N \
895                                 'renewable_in_redo_on_target' 'non_renewable renewable_anytime renewable_in_redo_on_conf'
896                         _command_exec_before_tools_upgrade__options L \
897                                 'renewable_in_redo_on_conf' 'non_renewable renewable_anytime renewable_in_redo_on_target'
898                         _command_exec_before_tools_upgrade__options MN \
899                                 'renewable_anytime renewable_in_redo_on_target' 'non_renewable renewable_in_redo_on_conf'
900                         _command_exec_before_tools_upgrade__options ML \
901                                 'renewable_anytime renewable_in_redo_on_conf' 'non_renewable renewable_in_redo_on_target'
902                         _command_exec_before_tools_upgrade__options NL \
903                                 'renewable_in_redo_on_target renewable_in_redo_on_conf' 'non_renewable renewable_anytime'
904                         _command_exec_before_tools_upgrade__options MNL \
905                                 'renewable_anytime renewable_in_redo_on_target renewable_in_redo_on_conf' 'non_renewable'
906                 )
907                 exit
908                 ;;
909         show)
910                 flag_filter_skip_unchanged=
911                 flag_filter_only_target=
912                 pkgnamedb='requires obsolete initial'
913                 [ -n "$COMMAND_SHOW_DEPTAG" ] || COMMAND_SHOW_DEPTAG=`options_get_dependency_type`
914                 [ -n "$COMMAND_SHOW_LEVEL" ] || COMMAND_SHOW_LEVEL=`options_get_dependency_level`
915                 dbsuffix=$COMMAND_SHOW_DEPTAG.$COMMAND_SHOW_LEVEL
916                 case $COMMAND_SHOW_SUBJECT in
917                 todo|done|redo|resolved|failure|taboo|need|noneed|deleted|restored|conflict)
918                         database_query_show_single_list_exec "$COMMAND_SHOW_SUBJECT" \
919                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" || :
920                         ;;
921                 initrequirements)
922                         grandtitle="Dependencies based on the initially installed packages"
923                         title="The following port(s) was/were required by %s:"
924                         list=requirements.$dbsuffix
925                         pkgnamedb='initial'
926                         [ $COMMAND_SHOW_DEPTAG = none ] && \
927                                 message_echo "WARNING: This command has no meaning with the current options setting." >&2
928                         database_query_for_each_matching_port "$grandtitle" "$title" "$list" "$pkgnamedb" \
929                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" "$@"
930                         ;;
931                 requirements)
932                         grandtitle="Dependencies based on the latest ports tree"
933                         title="The following port(s) is/are required by %s:"
934                         list=requirements.$dbsuffix
935                         pkgnamedb='requires obsolete'
936                         [ $COMMAND_SHOW_DEPTAG = none ] && \
937                                 message_echo "WARNING: This command has no meaning with the current options setting." >&2
938                         database_query_for_each_matching_port "$grandtitle" "$title" "$list" "$pkgnamedb" \
939                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" "$@"
940                         ;;
941                 initdependents)
942                         grandtitle="Dependencies based on the initially installed packages"
943                         title="The following port(s) depended on %s:"
944                         list=dependents.$dbsuffix
945                         pkgnamedb='initial'
946                         [ $COMMAND_SHOW_DEPTAG = none ] && \
947                                 message_echo "WARNING: This command has no meaning with the current options setting." >&2
948                         database_query_for_each_matching_port "$grandtitle" "$title" "$list" "$pkgnamedb" \
949                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" "$@"
950                         ;;
951                 dependents)
952                         grandtitle="Dependencies based on the latest ports tree"
953                         title="The following port(s) depend(s) on %s:"
954                         list=dependents.$dbsuffix
955                         pkgnamedb='requires obsolete'
956                         [ $COMMAND_SHOW_DEPTAG = none ] && \
957                                 message_echo "WARNING: This command has no meaning with the current options setting." >&2
958                         database_query_for_each_matching_port "$grandtitle" "$title" "$list" "$pkgnamedb" \
959                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" "$@"
960                         ;;
961                 status)
962                         grandtitle="Success/failure status in (re)installation"
963                         lists='todo|done|redo|resolved|failure|taboo|need|noneed|deleted|restored|conflict'
964                         database_query_for_list_inclusion_of_matching_port "$grandtitle" "$lists" "$pkgnamedb" \
965                                 "$COMMAND_SHOW_DEPTAG" "$COMMAND_SHOW_LEVEL" "$@"
966                         ;;
967                 esac
968                 exit
969                 ;;
970         esac
971 }
972
973 # ============= Execute command operations which must be done before building the temporary database =============
974 command_exec_before_building_tempdb ()
975 {
976         case $COMMAND_MODE in
977         redo)
978                 program_deregister_stage_complete REDO_INIT
979                 if [ $opt_reset_targets = yes ]
980                 then
981                         program_deregister_stage_complete DETERMINE_SPECIFIED_TARGETS
982                         program_deregister_stage_complete INSPECT_ALL_DEPENDENCIES
983                         rm -rf "${DBDIR}/targets"
984                 fi
985                 ;;
986         esac
987         program_deregister_stage_complete FORGET::PREPARATION_INSPECT_MASTER
988 }
989
990 # ============= Execute command operations which must be done before actual (re/de)installation processes =============
991 command_exec_before_actual_re_de_installation ()
992 {
993         local tmp_msg
994         case $COMMAND_MODE in
995         do|redo)
996                 case $COMMAND_DO_MODE in
997                 prepare)
998                         tmp_msg=${TMPDIR}/command_exec_before_actual_re_de_installation:msg
999                         cat > "$tmp_msg" << eof
1000 Done (skipped reinstallation) at `message_timestamp`
1001
1002  You can restart this process from the aborted/terminated point by executing without options or arguments as:
1003   ${APPNAME}
1004 eof
1005                         message_cat "$tmp_msg"
1006                         temp_terminate_process ()
1007                         {
1008                         }
1009                         exit
1010                         ;;
1011                 esac
1012                 ;;
1013         esac
1014 }