OSDN Git Service

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