OSDN Git Service

[NEW] show heritage command is added. The database records ports which have not eithe...
[portsreinstall/current.git] / lib / liboptions.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Interface of libraries for command line options -
5 # Copyright (C) 2013-2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Variables =============
10 OPTIONS_ERRNO=0 # 0: no error, 1: configuration error, 2: internal error
11 OPTIONS_SHIFT=0
12
13 # ============= Database of options which are given at each run and not saved =============
14 # [Syntax of option databases]
15 # short_name, long_name, variable, defult_vaule, set_value
16 # Columns are delimited by tab characters.
17 options_db_onetime ()
18 {
19         cat << eof
20 eof
21 }
22
23 # ============= Database of options which are saved and renewable at each run =============
24 options_db_saved_and_renewable ()
25 {
26         cat << eof
27 eof
28 }
29
30 # ============= Database of options which are saved and renewable only at the initial runs of redo command (on target specification) =============
31 options_db_saved_and_renewable_in_redo_on_target ()
32 {
33         cat << eof
34 eof
35 }
36
37 # ============= Database of options which are saved and renewable only at the initial runs of redo command (on configuration files) =============
38 options_db_saved_and_renewable_in_redo_on_conf ()
39 {
40         cat << eof
41 eof
42 }
43
44 # ============= Database of options which are saved and not renewable until the temporary database is cleaned =============
45 options_db_saved_and_non_renewable ()
46 {
47         cat << eof
48 eof
49 }
50
51 # ============= Regularize the option value =============
52 options_regularize ()
53 {
54 }
55
56 # ============= Database of all options to be saved =============
57 options_db_saved ()
58 {
59         options_db_saved_and_renewable
60         options_db_saved_and_renewable_in_redo_on_target
61         options_db_saved_and_renewable_in_redo_on_conf
62         options_db_saved_and_non_renewable
63 }
64
65 # ============= Database of all options =============
66 options_db_all ()
67 {
68         options_db_saved
69         options_db_onetime
70 }
71
72 # ============= Database for selected option sets =============
73 options_db ()
74 {
75         if [ $# -gt 0 ]
76         then
77                 while [ $# -gt 0 ]
78                 do
79                         case $1 in
80                         renewable_anytime )
81                                 options_db_saved_and_renewable
82                                 ;;
83                         renewable_in_redo_on_target )
84                                 options_db_saved_and_renewable_in_redo_on_target
85                                 ;;
86                         renewable_in_redo_on_conf )
87                                 options_db_saved_and_renewable_in_redo_on_conf
88                                 ;;
89                         non_renewable )
90                                 options_db_saved_and_non_renewable
91                                 ;;
92                         saved )
93                                 options_db_saved
94                                 ;;
95                         onetime )
96                                 options_db_onetime
97                                 ;;
98                         all )
99                                 options_db_all
100                                 ;;
101                         *)
102                                 message_echo "ERROR: Invalid argument [$1] for options_inverse_parse" >&2
103                                 exit 1;;
104                         esac
105                         shift
106                 done
107         else
108                 options_db_all
109         fi | sort -u
110 }
111
112 # ============= Convert from a short option name to the corresponding variable name =============
113 options_convert_shortname_to_varname ()
114 {
115         local shortname
116         shortname=$1
117         options_db_all | grep -m 1 "^${shortname}[[:space:]]" | cut -f 3 | sort -u
118 }
119
120 # ============= Dump all command line arguments and options =============
121 options_dump_args ()
122 {
123         echo -n "`echo "$0" | sed -E 's/(.)/\\\\\\1/g'`"
124         while [ $# -ge 1 ]
125         do
126                 echo -n " `echo "$1" | sed -E 's/(.)/\\\\\\1/g'`"
127                 shift
128         done
129 }
130
131 # ============= Get default option settings =============
132 options_default ()
133 {
134         options_db_all | cut -f 3,4 | sort -u | sed -E 's/[[:space:]]/=/'
135 }
136
137 # ============= Initialize option settings with the default values =============
138 options_set_default ()
139 {
140         options_default > ${TMPDIR}/default_optvals.sh
141         . "${TMPDIR}/default_optvals.sh"
142 }
143
144 # ============= Get the argument for getopts =============
145 options_getopts_arg ()
146 {
147         options_db_all | cut -f 1,5 | grep -v '^[[:space:]]' | sort -u \
148                 | sed -E 's/[[:space:]]:$/:/;s/[[:space:]].*$//' | tr -d '\n'
149 }
150
151 # ============= Get option settings =============
152 options_getopts_only_short ()
153 {
154         local OPTERR getopts_option option command OPTARG nshifts val
155         OPTERR=0
156         getopts_option=`options_getopts_arg`
157         while getopts $getopts_option option > /dev/null
158         do
159                 val=`str_escape_replaceval "$OPTARG"`
160                 command=`options_db_all | grep -m 1 "^${option}[[:space:]]" \
161                         | cut -f 3,5 | sed -E 's/[[:space:]]/=/;s/:$/'$val'/' || :`
162                 [ -n "$command" ] || return 1
163                 echo -n "$command;OPTIND=$OPTIND;"
164         done
165 }
166
167 # ============= Get option settings =============
168 options_getopts ()
169 {
170         local OPTIND option command nshifts val erropt
171         nshifts=0
172         erropt=
173         OPTIONS_SHIFT=0
174         OPTIONS_ERRNO=2
175         while [ $# -gt 0 ]
176         do
177                 eval `( set -e; options_getopts_only_short "$@")`
178                 shift $(($OPTIND-1))
179                 nshifts=$(($nshifts+$OPTIND-1))
180                 [ "x$1" = "x--" ] && break
181                 expr "x$1" : '^x-.*' > /dev/null || break
182                 [ $# -eq 0 ] && break
183                 erropt=$1
184                 option=`expr "x$1" : '^x--\([a-zA-Z0-9][a-zA-Z0-9-]*\).*'` || break
185                 command=`options_db_all | cut -f 2,3,5 | grep -m 1 "^${option}[[:space:]]" \
186                         | cut -f 2,3 | sed -E 's/[[:space:]]/=/' || :`
187                 [ -n "$command" ] || break
188                 if expr "$command" : '^[^=]*=:$' > /dev/null
189                 then
190                         expr "x$1" : '^x--[a-zA-Z0-9][a-zA-Z0-9-]*=.*' > /dev/null || break
191                         val=`expr "x$1" : '^x--[a-zA-Z0-9][a-zA-Z0-9-]*=\(.*\)'` || :
192                         eval `expr "$command" : '^\([^=]*=\).*'`\$val
193                 else
194                         [ "x$1" = "x--$option" ] || break
195                         eval $command
196                 fi
197                 nshifts=$(($nshifts+1))
198                 shift
199                 OPTIND=1
200                 erropt=
201         done
202         [ -z "$erropt" ] \
203                 || { message_echo "ERROR: Illeagal option [$erropt]" >&2; OPTIONS_ERRNO=1; return 1; }
204         OPTIONS_SHIFT=$nshifts
205         OPTIONS_ERRNO=0
206 }
207
208 # ============= Filter option value definitions to pick up selected groups =============
209 options_filter ()
210 {
211         grep `options_db "$@" | cut -f 3 | sed 's/^/-e ^/;s/$/=/'`
212 }
213
214 # ============= Compose an option set in a command line form from the current settings =============
215 options_inverse_parse ()
216 {
217         options_db "$@" | while read short_name long_name variable defult_vaule set_value
218         do
219                 eval val=\$$variable
220                 eval val_def=$defult_vaule
221                 eval val_set=$set_value
222                 if [ "x$set_value" = x: ]
223                 then
224                         [ "x$val" = "x$val_def" ] \
225                                 || misc_get_all_vardefs | grep -m 1 "^$variable=" \
226                                         | sed "s/^[^=]*=/-$short_name /"
227                 elif [ "x$val" = "x$val_set" ]
228                 then
229                         echo -n "-$short_name"
230                         echo
231                 fi
232         done | tr '\n' ' ' | sed 's/ *$//'
233 }
234
235 # ============= Filter option value definitions to pick up non-default ones =============
236 options_filter_configured ()
237 {
238         local tmpptn
239         tmpptn=${TMPDIR}/options_filter_configured:ptn
240         options_db "$@" | while read short_name long_name variable defult_vaule set_value
241         do
242                 eval val=\$$variable
243                 eval val_def=$defult_vaule
244                 [ "x$val" = "x$val_def" ] || echo "^$variable="
245         done > $tmpptn
246         grep -f "$tmpptn"
247 }
248
249 # ============= Check inclusion of invalid options intending to be renewed =============
250 options_chk_invalid_optvals_renewal ()
251 {
252         local  dbgroup comment_condition invalid_options num_invalid_options term_opts delimiter
253         dbgroup=$1
254         comment_condition=$2
255         misc_get_all_vardefs | options_filter_configured "$dbgroup" \
256                 > ${TMPDIR}/options_renewed_optvals:invalid_options_defs
257         invalid_options=`options_inverse_parse "$dbgroup" < ${TMPDIR}/options_renewed_optvals:invalid_options_defs`
258         num_invalid_options=`wc -l < ${TMPDIR}/options_renewed_optvals:invalid_options_defs`
259         if [ $num_invalid_options -ne 0 ]
260         then
261                 term_opts="Option $invalid_options is"
262                 [ $num_invalid_options -gt 1 ] && term_opts="Options $invalid_options are"
263                 delimiter=
264                 [ -n "$comment_condition" ] && delimiter=' '
265                 message_echo "ERROR: $term_opts invalid in restarted runs${delimiter}${comment_condition}." >&2
266                 return 1
267         fi
268 }
269
270 # ============= Get renewed option value definitions as well as checking their validity =============
271 options_renewed_optvals ()
272 {
273         local flag_shortname dbgroup flag_varname flag
274         flag_shortname=$1
275         dbgroup=$2
276         flag_varname=`options_convert_shortname_to_varname "$flag_shortname"`
277         eval "flag=\$$flag_varname"
278         if [ "x$flag" = xyes ]
279         then
280                 misc_get_all_vardefs | options_filter "$dbgroup"
281         else
282                 options_chk_invalid_optvals_renewal "$dbgroup" "without -$flag_shortname"
283         fi
284 }
285
286 # ============= Select new target ports specified by globs if duplicated for each glob pattern =============
287 options_select_new_ports_if_duplicated ()
288 {
289         local option dstfile optargs tmp_target_ports tmp_existing_ports tmp_new_ports itemlist globs_list nlines iline title desc
290         option=$1
291         dstfile=$2
292         shift 2
293         optargs="$*"
294         tmp_target_ports=${TMPDIR}/options_select_new_ports_if_duplicated:target_ports
295         tmp_existing_ports=${TMPDIR}/options_select_new_ports_if_duplicated:existing_ports
296         tmp_new_ports=${TMPDIR}/options_select_new_ports_if_duplicated:new_ports
297         globs_list=${TMPDIR}/options_select_new_ports_if_duplicated::globs_list
298         itemlist=${TMPDIR}/options_select_new_ports_if_duplicated::itemlist
299         cp /dev/null "$dstfile.tmp"
300         echo "$optargs" | sed -E 's/[ :]+/\
301 /g' | grep -v '^$' | sort -u > $globs_list
302         nlines=`wc -l < $globs_list`
303         iline=1
304         while [ $iline -le $nlines ]
305         do
306                 glob=`sed -n ${iline}p "$globs_list"`
307                 iline=$(($iline+1))
308                 rm -f "$tmp_target_ports"
309                 pkgsys_register_evaluated_globs add "$tmp_target_ports" "$glob"
310                 if [ `cat "$tmp_target_ports" 2> /dev/null | wc -l` -eq 0 ]
311                 then
312                         message_echo "WARNING: No matching port for target glob [$glob]." >&2
313                         continue
314                 fi
315                 cp /dev/null "$tmp_existing_ports"
316                 cp /dev/null "$tmp_new_ports"
317                 while read origin
318                 do
319                         if pkgsys_exists_or_existed_from_orig "$origin" \
320                                 || cat "${DBDIR}/installed_ports" "${DBDIR}/targets_specified_so_far" 2> /dev/null \
321                                         | grep -q -Fx "$origin"
322                         then
323                                 echo "$origin" >> $tmp_existing_ports
324                         else
325                                 echo "$origin" >> $tmp_new_ports
326                         fi
327                 done < $tmp_target_ports
328                 cat "$tmp_existing_ports" >> $dstfile.tmp
329                 if [ $opt_allow_new_targets = yes ]
330                 then
331                         if [ `wc -l < $tmp_new_ports` -gt 1 ]
332                         then
333                                 title="Uninspected ports matching a glob pattern [$glob] for -$option option"
334                                 desc='Checked ones are newly installed.'
335                                 while read origin
336                                 do
337                                         echo "$origin '' off"
338                                         printf '%s\t""\t%s\n' "$origin" '' "$val"
339                                 done < $tmp_new_ports > $itemlist
340                                 misc_dialog_checklist "$title" "$desc" "$dstfile.tmp" "$itemlist"
341                         else
342                                 cat "$tmp_new_ports" >> $dstfile.tmp
343                         fi
344                 else
345                         [ `wc -l < $tmp_new_ports` -eq 0 ] || \
346                                 message_echo "WARNING: Ignored not-yet-installed ports for target glob [$glob]." >&2
347                         if [ `wc -l < $tmp_existing_ports` -eq 0 ]
348                         then
349                                 message_echo "WARNING: No available matching port for target glob [$glob]." >&2
350                         fi
351                 fi
352         done
353         mv "$dstfile.tmp" "$dstfile"
354 }
355
356 # ============= Get the database type of dependency algorithm for the current option setting =============
357 options_get_dependency_type ()
358 {
359         case $opt_include_buildtime_dependencies+$opt_include_runtime_dependencies in
360         yes+yes )
361                 echo all
362                 ;;
363         no+yes )
364                 echo run
365                 ;;
366         yes+no )
367                 echo build
368                 ;;
369         no+no )
370                 echo none
371                 ;;
372         esac
373 }
374
375 # ============= Parse the database type tag of dependency algorithm and reflect it to option values =============
376 options_parse_dependency_type ()
377 {
378         local deptag
379         deptag=$1
380         case $deptag in
381         all )
382                 opt_include_buildtime_dependencies=yes
383                 opt_include_runtime_dependencies=yes
384                 ;;
385         run )
386                 opt_include_buildtime_dependencies=no
387                 opt_include_runtime_dependencies=yes
388                 ;;
389         build )
390                 opt_include_buildtime_dependencies=yes
391                 opt_include_runtime_dependencies=no
392                 ;;
393         none )
394                 opt_include_buildtime_dependencies=no
395                 opt_include_runtime_dependencies=no
396                 ;;
397         esac
398 }
399
400 # ============= Get the database level of dependency algorithm for the current option setting =============
401 options_get_dependency_level ()
402 {
403         case $opt_only_target_scope in
404         yes )
405                 echo direct
406                 ;;
407         no )
408                 echo full
409                 ;;
410         esac
411 }
412
413 # ============= Parse the database level tag of dependency algorithm and reflect it to option values =============
414 options_parse_dependency_level ()
415 {
416         local level
417         level=$1
418         case $level in
419         direct )
420                 opt_only_target_scope=yes
421                 ;;
422         full )
423                 opt_only_target_scope=no
424                 ;;
425         esac
426 }
427
428 # ============= Get the message term of dependency algorithm for the current option setting =============
429 options_get_dependency_msgterm ()
430 {
431         local scope
432         scope=`options_get_dependency_level`
433         case $opt_include_buildtime_dependencies+$opt_include_runtime_dependencies in
434         yes+yes )
435                 echo "$scope run- and build-time"
436                 ;;
437         no+yes )
438                 echo "$scope run-time"
439                 ;;
440         yes+no )
441                 echo "$scope build-time"
442                 ;;
443         no+no )
444                 echo 'no'
445                 ;;
446         esac
447 }
448
449 # ============= Get effective option value about importing pkgtools.conf(5) =============
450 options_get_effective_opt_load_pkgtoolsconf ()
451 {
452         local effective_opt_load_pkgtoolsconf
453         if [ $opt_load_pkgtoolsconf = undef ]
454         then
455                 if [ -e "$PKGTOOLSCONF" ] && which -s portupgrade
456                 then
457                         effective_opt_load_pkgtoolsconf=default
458                 else
459                         effective_opt_load_pkgtoolsconf=no
460                 fi
461         elif ! which -s portupgrade
462         then
463                 message_echo "WARNING: pkgtools.conf is ignored because portupgrade is not installed." >&2
464                 effective_opt_load_pkgtoolsconf=no
465         fi
466         echo "$effective_opt_load_pkgtoolsconf"
467 }
468
469 # ============= Show the setting of an option group =============
470 options_show_group_setting ()
471 {
472         local opt_control group_reset group_remain reset_opts result_opts str_opt_control str_rstoption notice_reset notice_result
473         opt_control=$1
474         group_reset=$2
475         group_remain=$3
476         reset_opts=`options_inverse_parse $group_reset`
477         result_opts=`options_inverse_parse $group_remain`
478         if [ $is_batch_mode = yes ]
479         then
480                 printf '%s\t%s\t%s\n' "$opt_control" "$reset_opts" "$result_opts"
481         else
482                 str_opt_control=`echo "$opt_control" | sed -E 's/(.)/-\1 /g;s/ *$//'`
483                 str_rstoption=Option`[ \`echo -n "$opt_control" | wc -c\` -ge 2 ] && echo s` || :
484                 notice_reset=`[ -z "$reset_opts" ] && echo ' (nothing)'` || :
485                 notice_result=`[ -z "$result_opts" ] && echo ' (default)'` || :
486                 echo "$str_rstoption [$str_opt_control] will reset [$reset_opts]$notice_reset so that the settings become [$result_opts]$notice_result."
487         fi
488 }
489
490 # ============= Show the all options =============
491 options_show_all ()
492 {
493                 ( set -e
494                         is_batch_mode=$opt_batch_mode
495                         options_set_default
496                         [ -e "${DBDIR}/saved_options.sh" ] && . "${DBDIR}/saved_options.sh"
497                         savedopts=`options_inverse_parse`
498                         if [ $is_batch_mode = yes ]
499                         then
500                                 printf '\t%s\n' "$savedopts"
501                         else
502                                 echo "The saved setting is [$savedopts]."
503                         fi
504                         options_show_group_setting M \
505                                 'renewable_anytime' 'non_renewable renewable_in_redo_on_target renewable_in_redo_on_conf'
506                         options_show_group_setting N \
507                                 'renewable_in_redo_on_target' 'non_renewable renewable_anytime renewable_in_redo_on_conf'
508                         options_show_group_setting L \
509                                 'renewable_in_redo_on_conf' 'non_renewable renewable_anytime renewable_in_redo_on_target'
510                         options_show_group_setting MN \
511                                 'renewable_anytime renewable_in_redo_on_target' 'non_renewable renewable_in_redo_on_conf'
512                         options_show_group_setting ML \
513                                 'renewable_anytime renewable_in_redo_on_conf' 'non_renewable renewable_in_redo_on_target'
514                         options_show_group_setting NL \
515                                 'renewable_in_redo_on_target renewable_in_redo_on_conf' 'non_renewable renewable_anytime'
516                         options_show_group_setting MNL \
517                                 'renewable_anytime renewable_in_redo_on_target renewable_in_redo_on_conf' 'non_renewable'
518                 )
519 }