OSDN Git Service

Fixed the wrong implementation of show errormessage.
[portsreinstall/current.git] / lib / libmain.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Common functions of main programs -
5 # Copyright (C) 2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Define the software version =============
10 main_set_version ()
11 {
12         MYVERSION=4.1.0
13         COMPATIBLE_VERSIONS='^(4\.[0-1]\.[0-9])$'
14         # Template for development versions
15         MYVERSION=4.0.0+toward_4.1.0_20180729140632
16         COMPATIBLE_VERSIONS='^(4\.[0-1]\.[0-9]]|4\.[0]\.[0]+(|\+toward_4\.[0]\.[1]+_[0-9]+))$'
17 }
18
19 # ============= Parse options, arguments and control parameters =============
20 # All arguments/options of the main program must be passed.
21 main_parse_options_arguments ()
22 {
23         # ============= Save arguments for upgraded restart =============
24         options_dump_args "$@" > ${TMPDIR}/restart_command.sh
25
26         # ============= Option check =============
27         options_set_default
28
29         options_getopts "$@" || :
30         if [ $OPTIONS_ERRNO -eq 2 ]
31         then
32                 message_echo "INTERNAL ERROR: In parsing options" >&2
33                 exit 1
34         fi
35         shift "${OPTIONS_SHIFT}"
36         
37         options_regularize
38
39         # ============= Argument check for no-command options =============
40         if [ $opt_help_mode -ne 0 -o $opt_show_version = yes ]
41         then
42                 if [ $# -gt 0 ]
43                 then
44                         OPTIONS_ERRNO=1
45                 fi
46         fi
47
48         # ============= Output usage if the case of a help mode or option/argument errors =============
49         if [ $OPTIONS_ERRNO -ne 0 ]
50         then
51                 exit $OPTIONS_ERRNO
52         elif [ $opt_help_mode -eq 1 ]
53         then
54                 usage_short
55                 exit
56         elif [ $opt_help_mode -eq 2 ]
57         then
58                 usage_long | less -r
59                 exit
60         fi
61
62         # ============= Output version number =============
63         if [ $opt_show_version = yes ]
64         then
65                 message_version
66                 exit
67         fi
68
69         # ============= Set up variables for environment of ports and packages =============
70         conf_setup_ports_envs
71         conf_setup_packages_envs
72
73         # ============= Execute command operations before getting the temporary database ready =============
74         command_all_exec_before_db_creation "$@"
75
76         # ============= Creation of temporary database directory =============
77         database_maintain_create
78
79         # ============= Argument check for conventional runs =============
80         command_all_parse_args "$@"
81         shift "${COMMAND_SHIFT}"
82 }
83
84 # ============= Define the common termination messages =============
85 main_define_common_termination_messages ()
86 {
87         temp_terminate_process_common ()
88         {
89                 local errno msg_where
90                 errno=${1:-0}
91                 [ $opt_batch_mode = yes -o $errno -eq 0 ] && return
92                 msg_where=`temp_get_msg_current_stage`
93                 [ -n "$msg_where" ] && msg_where=" during $msg_where"
94                 message_echo
95                 if [ $errno -eq 130 ]
96                 then
97                         message_echo "INFO: Terminated at `message_timestamp`$msg_where."
98                         message_echo
99                         message_echo " You can restart this process from the terminated point by"
100                 else
101                         message_echo "INFO: Aborted at `message_timestamp`$msg_where."
102                         message_echo
103                         message_echo " You may restart this process from the aborted point by"
104                 fi
105                 message_echo "executing without options or arguments as:"
106                 if [ -n "$COMMAND_RESTART" ]
107                 then
108                         message_echo "  ${APPNAME} $COMMAND_RESTART"
109                 else
110                         message_echo "  ${APPNAME}"
111                 fi
112         }
113 }
114
115 # ============= Set termination messages for special commands =============
116 main_set_termination_messages_special ()
117 {
118         temp_terminate_process ()
119         {
120                 local errno tmp_msg
121                 errno=${1:-0}
122                 tmp_msg=${TMPDIR}/temp_terminate_process:msg
123                 [ $errno -eq 0 -o $opt_batch_mode = yes ] && return
124                 temp_terminate_process_common "$errno"
125                 [ -n "$COMMAND_RESTART" ] && return
126                 cat > $tmp_msg << eof
127 Instead, if you only want to construct the temporary database so as to stop before the actual reinstallation, execute as:
128 ${APPNAME} prepare
129 eof
130                 message_cat "$tmp_msg"
131         }
132 }
133
134 # ============= Option settings =============
135 main_option_settings ()
136 {
137         local optcomb_err
138         # Load, renew and save option values
139         optcomb_err=0
140         if [ \( "x$opt_reload_conf" = xyes -o "x$opt_reset_targets" = xyes \) -a "x$COMMAND_MODE" != xredo ]
141         then
142                 message_echo "ERROR: Options -L and -N are available only in the initial run of redo command." >&2
143                 message_echo >&2
144                 optcomb_err=1
145         fi
146         if [ "x$opt_batch_ports_only" = xyes -a "x$opt_interactive_ports_only" = xyes ]
147         then
148                 message_echo "ERROR: Options -A and -I conflict with each other." >&2
149                 message_echo >&2
150                 optcomb_err=1
151         fi
152         if [ -e "${DBDIR}/saved_options.sh" ]
153         then
154                 options_chk_invalid_optvals_renewal non_renewable || optcomb_err=$?
155                 {
156                         options_renewed_optvals M renewable_anytime || optcomb_err=$?
157                         options_renewed_optvals N renewable_in_redo_on_target || optcomb_err=$?
158                         options_renewed_optvals L renewable_in_redo_on_conf || optcomb_err=$?
159                 } > ${TMPDIR}/renewed_optvals.sh
160                 [ $optcomb_err -eq 0 ] || exit $optcomb_err
161                 . "${DBDIR}/saved_options.sh"
162                 . "${TMPDIR}/renewed_optvals.sh"
163         fi
164         misc_is_superuser_privilege && misc_get_all_vardefs | options_filter saved > ${DBDIR}/saved_options.sh
165         :
166 }
167
168 # ============= Save the previous configuration if exists =============
169 main_save_prev_conf ()
170 {
171         local PROGRAM_DEPENDS
172         PROGRAM_DEPENDS=''
173         _program_exec_and_record_completion__operation ()
174         {
175                 rm -rf "${DBDIR}/conf.prev"
176                 [ -d "${DBDIR}/conf" ] && \
177                         cp -Rp "${DBDIR}/conf" "${DBDIR}/conf.prev"
178                 :
179         }
180         program_exec_and_record_completion SAVE_PREV_CONF
181 }
182
183 # ============= Load the saved configuration =============
184 main_load_conf ()
185 {
186         . "${DBDIR}/conf/setenv.sh"
187 }
188
189 # ============= Get complete configuration variable definitions by importing pkgtools.conf(5) if available =============
190 main_get_complete_conf ()
191 {
192         local PROGRAM_DEPENDS
193         PROGRAM_DEPENDS='SAVE_PREV_CONF'
194         _program_exec_and_record_completion__operation ()
195         {
196                 local need_msg
197                 need_msg=no
198                 rm -rf "${DBDIR}/conf"
199                 mkdir -p "${DBDIR}/conf"
200                 [ "x`options_get_effective_opt_load_pkgtoolsconf 2> /dev/null`" != xno -a $opt_batch_mode = no ] \
201                         && need_msg=yes
202                 [ $need_msg = yes ] && \
203                         message_section_title "Parsing pkgtools.conf (by using installed portupgrade)"
204                 conf_get_complete_var_defs > ${DBDIR}/conf/complete_setup.sh
205                 [ $need_msg = yes ] &&  { message_echo "===> ok"; message_echo; }
206                 :
207         }
208         program_exec_and_record_completion GET_COMPLETE_CONF_VAR_DEF
209 }
210
211 # ============= Parse the configuration =============
212 main_parse_conf ()
213 {
214         local PROGRAM_DEPENDS
215         PROGRAM_DEPENDS='GET_COMPLETE_CONF_VAR_DEF'
216         _program_exec_and_record_completion__operation ()
217         {
218                 message_section_title "Parsing the configuration"
219                 conf_manipulate_available_var_defs
220                 . "${DBDIR}/conf/manipulated_defs.sh"
221                 # ALT_MOVED_*
222                 conf_build_effective_MOVED
223                 # Environmental variables
224                 conf_setup_effective_env > ${DBDIR}/conf/setenv.sh
225                 . "${DBDIR}/conf/setenv.sh"
226                 # HOLD_*
227                 conf_parse_vars_for_each_port_glob HOLD
228                 # TABOO_*
229                 conf_parse_vars_for_each_port_glob TABOO
230                 fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" \
231                         > ${DBDIR}/taboo.all.list
232                 # FREEZE_*
233                 conf_parse_vars_for_each_port_glob FREEZE
234                 fileedit_combine_lists "${DBDIR}/conf/FREEZE:PORTS.parsed" "${DBDIR}/freeze.list" \
235                         > ${DBDIR}/freeze.all.list
236                 # NOPKG_*
237                 conf_parse_vars_for_each_port_glob NOPKG
238                 # REPLACE_*
239                 conf_build_replacement_patterns_from_REPLACE
240                 # CONFLICT_*
241                 conf_parse_vars_for_each_port_glob_with_bound_val CONFLICT TARGET DEF
242                 # BUILDCONFLICT_*
243                 conf_parse_vars_for_each_port_glob_with_bound_val BUILDCONFLICT TARGET DEF
244                 # INSTCONFLICT_*
245                 conf_parse_vars_for_each_port_glob_with_bound_val INSTCONFLICT TARGET DEF
246                 # MARG_*
247                 conf_parse_vars_for_each_port_glob_with_bound_val MARG TARGET DEF
248                 # MENV_*
249                 conf_parse_vars_for_each_port_glob_with_bound_val MENV TARGET DEF
250                 # BEFOREBUILD_*
251                 conf_parse_vars_for_each_port_glob_with_bound_val BEFOREBUILD TARGET COMMAND
252                 # BEFOREDEINSTALL_*
253                 conf_parse_vars_for_each_port_glob_with_bound_val BEFOREDEINSTALL TARGET COMMAND
254                 # AFTERINSTALL_*
255                 conf_parse_vars_for_each_port_glob_with_bound_val AFTERINSTALL TARGET COMMAND
256                 message_echo
257         }
258         program_exec_and_record_completion PARSE_CONF
259 }
260
261 # ============= Set up parameters based on options, arguments, environment =============
262 main_setup_parameters ()
263 {
264         # ============= Termination messages during construction of the temporary database =============
265         main_define_common_termination_messages
266         temp_reset_termination_messages_common
267         main_set_termination_messages_special
268
269         # ============= Opening title =============
270
271         message_credit
272         command_all_chk_need_opening_notice && message_opening_notice
273         message_echo
274
275         # ============= Execute command operations which do not need package tools =============
276
277         command_all_exec_without_pkgtools "$@"
278         misc_is_superuser_privilege && database_maintain_mark_use
279         # ============= Definition of environment dependent functions =============
280
281         pkgsys_def_pkgtools
282
283         # ============= Option settings =============
284
285         # Execute command operations which are not affected by saved option settings
286         command_all_exec_irrespective_of_saved_options "$@"
287
288         # Load, renew and save option values
289         main_option_settings
290
291         # Show option values
292         message_show_option_settings
293
294         # ============= Configurations =============
295
296         # Save the previous configuration if exists
297         main_save_prev_conf
298
299         # Get complete configuration variable definitions by importing pkgtools.conf(5) if available
300         main_get_complete_conf
301
302         # Parse the configuration
303         main_parse_conf
304
305         # Load the saved configuration
306         main_load_conf
307 }
308
309 # ============= Operation without packages management tools =============
310 main_operation_without_pkg_management_tools ()
311 {
312         # Execute command operations which should be done without upgrade of tools
313         command_all_exec_before_tools_upgrade "$@"
314
315         # Check whether the temporary database is newer than the ports tree and refresh if so
316         database_maintain_refresh_if_obsolete
317 }
318
319 # ============= Collect all installed packages =============
320 main_collect_all_installed_packages ()
321 {
322         local PROGRAM_DEPENDS
323         PROGRAM_DEPENDS=''
324         _program_exec_and_record_completion__operation ()
325         {
326                 local tmp_installed_ports tmp_installed_pkgs
327                 message_section_title "Collecting all installed packages"
328                 if [ ! -e "${DBDIR}/installed_ports" ]
329                 then
330                         pkg_info_all_flavored_origins > ${DBDIR}/installed_ports.tmp
331                         pkg_info_gen_pkg_origin_table
332                         mv "${DBDIR}/installed_ports.tmp" "${DBDIR}/installed_ports"
333                 fi
334                 message_echo
335         }
336         program_exec_and_record_completion COLLECT_ALL_INSTALLED_PACKAGES
337 }
338
339 # ============= Preliminary inspection of tools which have to be up-to-date =============
340 # (No need depend on PARSE_CONF because INSPECT_ALL_DEPENDENCIES will take the task.)
341 main_preliminary_inspection_of_tools ()
342 {
343         local PROGRAM_DEPENDS
344         PROGRAM_DEPENDS=
345         _program_exec_restartable_loop_operation__routine ()
346         {
347                 local origin
348                 origin=$1
349                 database_build_inspect_dependencies "$origin"
350         }
351         _program_exec_and_record_completion__operation ()
352         {
353                 local DEPTH_INDEX
354                 message_section_title "Preliminary inspection of tools which have to be up-to-date"
355                 {
356                         [ "$PKGSYS_USE_PKGNG" = yes ] && pkgsys_portsmgmt_pkg
357                         pkgsys_is_dialog4ports_used && pkgsys_portsmgmt_dialog4ports
358                         [ -n "$MYPORTORIGIN" ] && echo "$MYPORTORIGIN"
359                 } 2> /dev/null > ${DBDIR}/stage.loop_list/tools_to_inspect
360                 cp /dev/null "${DBDIR}/done_required_ports_to_inspect"
361                 DEPTH_INDEX='--'
362                 program_exec_restartable_loop_operation tools_to_inspect
363                 database_build_post_inspect_dependencies
364                 message_echo
365         }
366         program_exec_and_record_completion PRELIMINARY_INSPECTION_OF_TOOLS
367 }
368
369 # ============= Upgrade of pkg(8) if new =============
370 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
371 main_upgrade_pkg8_if_new ()
372 {
373         local PROGRAM_DEPENDS
374         if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
375                 -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no \
376                 -a "$PKGSYS_USE_PKGNG" = yes ]
377         then
378                 PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
379                 _program_exec_and_record_completion__operation ()
380                 {
381                         local _MSG_CURRENT_STAGE_general
382                         _MSG_CURRENT_STAGE_general="pkg(8) upgrade"
383                         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
384                         message_section_title "Upgrade of `pkgsys_portsmgmt_pkg` if new"
385                         touch "${DBDIR}/target_all"
386                         reinstall_exec `pkgsys_portsmgmt_pkg`
387                         reinstall_restore_conflicts
388                         rm -f "${DBDIR}/target_all"
389                         temp_set_msg_current_stage
390                         message_echo
391                 }
392                 program_exec_and_record_completion UPGRADE_PKGNG
393         fi
394 }
395
396 # ============= Upgrade of dialog4ports(1) if new =============
397 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
398 main_upgrade_dialog4ports1_if_new ()
399 {
400         local PROGRAM_DEPENDS
401         if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
402                 -a $opt_dry_run = no -a $opt_suppress_pkgtools_upadte = no ] \
403                 && pkgsys_is_dialog4ports_used
404         then
405                 PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
406                 _program_exec_and_record_completion__operation ()
407                 {
408                         local _MSG_CURRENT_STAGE_general
409                         _MSG_CURRENT_STAGE_general="dialog4ports(1) upgrade"
410                         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
411                         message_section_title "Upgrade of `pkgsys_portsmgmt_dialog4ports` if new"
412                         touch "${DBDIR}/target_all"
413                         reinstall_exec `pkgsys_portsmgmt_dialog4ports`
414                         reinstall_restore_conflicts
415                         rm -f "${DBDIR}/target_all"
416                         temp_set_msg_current_stage
417                         message_echo
418                 }
419                 program_exec_and_record_completion UPGRADE_DIALOG4PORTS
420         fi
421 }
422
423 # ============= Upgrade of this utility if new =============
424 # (No need depend on PARSE_CONF because REINSTALLATION will take the task.)
425 main_self_upgrade ()
426 {
427         local PROGRAM_DEPENDS
428         if [ \( "$COMMAND_MODE" = do -o "$COMMAND_MODE" = redo \) \
429                 -a $opt_dry_run = no -a $opt_suppress_self_upadte = no \
430                 -a -n "$MYPORTORIGIN" ]
431         then
432                 PROGRAM_DEPENDS='PRELIMINARY_INSPECTION_OF_TOOLS'
433                 _program_exec_and_record_completion__operation ()
434                 {
435                         local _MSG_CURRENT_STAGE_general
436                         _MSG_CURRENT_STAGE_general="pkgng upgrade"
437                         temp_set_msg_current_stage "${_MSG_CURRENT_STAGE_general}"
438                         message_section_title "Upgrade of this utility if new"
439                         touch "${DBDIR}/target_all"
440                         reinstall_exec "$MYPORTORIGIN"
441                         reinstall_restore_conflicts
442                         rm -f "${DBDIR}/target_all"
443                         temp_set_msg_current_stage
444                         message_echo
445                 }
446                 program_exec_and_record_completion UPGRADE_SELF
447         fi
448         if [ "x`${APPNAME} -aV 2> /dev/null`" != "x$MYVERSION" ]
449         then
450                 message_echo "INFO: ${APPNAME} is upgraded and the temporary database needs refresh."
451                 database_maintain_clean_for_self_upgrade || :
452                 message_echo "INFO: Restarting with the new version."
453                 message_echo
454                 temp_trap_for_invoking_new_version
455                 . "${TMPDIR}"/restart_command.sh
456                 exit
457         fi
458 }
459
460 # ============= Overlay onto the temporary database by reflecting changes in configuration =============
461 main_reflect_conf_changes ()
462 {
463         local PROGRAM_DEPENDS
464         PROGRAM_DEPENDS='PARSE_CONF'
465         _program_exec_and_record_completion__operation ()
466         {
467                 local tmpfile_diff tmpfile_old tmpfile_new key
468                 [ -d "${DBDIR}/conf.prev" ] || return 0
469                 message_section_title "Overlay onto the temporary database by reflecting changes in configuration"
470                 tmpfile_old=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::old
471                 tmpfile_new=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::new
472                 tmpfile_updated_ports=${TMPDIR}/PATCH_TO_TMPDB_REFLECT_CONF_CHANGES::updated_ports
473                 if fileedit_manipulate_old_new_lines \
474                         "${DBDIR}/conf.prev/setenv.sh" "${DBDIR}/conf/setenv.sh" "$tmpfile_old" "$tmpfile_new"
475                 then
476                         if grep -q -e ^LOCALBASE= -e ^LINUXBASE= -e ^PORTSDIR= "$tmpfile_old" "$tmpfile_new"
477                         then
478                                 message_echo "ERROR: Migration of the temporary database is unavailable because LOCALBASE, LINUXBASE or PORTSDIR was changed." >&2
479                                 message_echo "        ${APPNAME} clean" >&2
480                                 message_echo "must be executed in advance." >&2
481                                 exit 1
482                         fi
483                 fi
484                 cut -s -d '|' -f 1,2 "${DBDIR}/conf.prev/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.old
485                 cut -s -d '|' -f 1,2 "${DBDIR}/conf/MOVED_ALT.parsed" | tr '|' '\t' > ${TMPDIR}/MOVED_ALT.new
486                 if fileedit_manipulate_old_new_lines \
487                         "${TMPDIR}/MOVED_ALT.old" "${TMPDIR}/MOVED_ALT.new" "$tmpfile_old" "$tmpfile_new"
488                 then
489                         cat "$tmpfile_old" "$tmpfile_new" | while read from to
490                         do
491                                 echo "$from"
492                                 [ -n "$to" ] && echo "$to"
493                         done
494                 fi > $tmpfile_updated_ports
495                 sort -u "${DBDIR}/conf/NOPKG:PORTS.parsed" 2> /dev/null > ${TMPDIR}/NOPKG:PORTS.parsed.new || :
496                 sort -u "${DBDIR}/conf.prev/NOPKG:PORTS.parsed" 2> /dev/null > ${TMPDIR}/NOPKG:PORTS.parsed.old || :
497                 diff "${TMPDIR}/NOPKG:PORTS.parsed.old" "${TMPDIR}/NOPKG:PORTS.parsed.new" | sed -n 's/^[<>] //p' >> $tmpfile_updated_ports
498                 if fileedit_manipulate_old_new_lines \
499                         "${DBDIR}/conf.prev/REPLACE.csv" "${DBDIR}/conf/REPLACE.csv" "$tmpfile_old" "$tmpfile_new"
500                 then
501                         cat "$tmpfile_old" "$tmpfile_new" | while read from to
502                         do
503                                 echo "$from"
504                                 [ -n "$to" ] && echo "$to"
505                         done
506                 fi >> $tmpfile_updated_ports
507                 [ `wc -l < $tmpfile_updated_ports` -gt 0 ] && rm -f "${DBDIR}/REPLACE.complete_sed_pattern"
508                 [ -d "${DBDIR}/conf/each_port" ] && find "${DBDIR}/conf/each_port" -depth 2 \
509                         | while read dbpath
510                 do
511                         origin=`str_dirpath_to_origin "$dbpath"`
512                         dbpath_prev=${DBDIR}/conf.prev/each_port/$origin
513                         diff -r "$dbpath_prev" "$dbpath" > /dev/null 2>&1 && continue
514                         echo "$origin"
515                 done >> $tmpfile_updated_ports
516                 [ -d "${DBDIR}/conf.prev/each_port" ] && find "${DBDIR}/conf.prev/each_port" -depth 2 \
517                         | while read dbpath_prev
518                 do
519                         origin=`str_dirpath_to_origin "$dbpath_prev"`
520                         dbpath=${DBDIR}/conf/each_port/$origin
521                         [ -d "$dbpath" ] && continue
522                         echo "$origin"
523                 done >> $tmpfile_updated_ports
524                 if [ `wc -l < $tmpfile_updated_ports` -gt 0 ]
525                 then
526                         sort -u "$tmpfile_updated_ports" | while read origin
527                         do
528                                 message_echo "Reset for $origin"
529                                 database_build_patch_reconf "$origin"
530                         done
531                         program_deregister_stage_complete PREPARE_FOR_INSPECT_ALL_DEPENDENCIES
532                         program_deregister_stage_complete ALL_COMPLETE
533                 fi
534                 message_echo
535         }
536         program_exec_and_record_completion PATCH_TO_TMPDB_REFLECT_CONF_CHANGES
537 }