OSDN Git Service

Version 3.0.1+toward_3.0.2_20130708223707
[portsreinstall/current.git] / lib / libdatabase_query.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Operations for queries to the temporary database -
5 # Copyright (C) 2013 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Show a list of failed ports with their reasons =============
10 database_query_show_list_failure ()
11 {
12         if [ `cat "${DBDIR}/failed.list" 2> /dev/null | wc -l` -eq 0 ]
13         then
14                 message_echo "INFO: No item is registered in this list."
15                 return 1
16         fi
17         grep -v -E -f "${DBDIR}/ports_to_delete.grep_pattern" "${DBDIR}/failed.list" \
18                 | while read origin
19         do
20                 origin_regexp=`str_escape_regexp "$origin"`
21                 grep -q -E "^$origin_regexp$" "${DBDIR}/stage.loop_list/ports_to_delete" 2> /dev/null \
22                         && continue
23                 note=`cat "${DBDIR}/requires/$origin/note_failtre"`
24                 resolved=no
25                 grep -q -E "^`str_escape_regexp \"$origin\"`$" \
26                         "${DBDIR}/manually_done.list" 2> /dev/null \
27                         && resolved=yes
28                 pkgtag=`cat "${DBDIR}/requires/$origin/pkgtag" 2> /dev/null` || :
29                 if [ $opt_batch_mode = no ]
30                 then
31                         case $resolved in
32                         no)     resolved=;;
33                         yes)    resolved=', resolved';;
34                         esac
35                         if [ -n "$pkgtag" ]
36                         then
37                                 echo "$origin ($pkgtag) (error while [$note]$resolved)"
38                         else
39                                 echo "$origin (error while [$note]$resolved)"
40                         fi
41                 else
42                         printf "%s\t%s\t%s\t%s\n" "$origin" "$pkgtag" "$note" "$resolved"
43                 fi
44         done
45         :
46 }
47
48 # ============= Show a list of failed restoration of conflicts =============
49 database_query_show_list_failed_conflicts_restoration ()
50 {
51         if [ `cat "${DBDIR}/deleted_conflicts" 2> /dev/null | wc -l` -eq 0 ]
52         then
53                 message_echo "INFO: No item is registered in this list."
54                 return 1
55         fi
56         grep -v -E -f "${DBDIR}/ports_to_delete.grep_pattern_col1" "${DBDIR}/deleted_conflicts" \
57                 | while read origin pkg
58                 do
59                         pkg_regexp=`str_escape_regexp "$pkg"`
60                         against=`grep -E "^$pkg_regexp:" "${DBDIR}/forbidden_conflicts" 2> /dev/null | cut -d : -f 2 | sort -u`
61                         if [ $opt_batch_mode = no ]
62                         then
63                                 if [ -n "$pkg" ]
64                                 then
65                                         echo -n "$origin ($pkg)"
66                                 else
67                                         echo -n "$origin"
68                                 fi
69                                 if [ -n "$against" ]
70                                 then
71                                         echo -n " against "
72                                         against=`echo "$against" | tr '\n' ' '`
73                                         str_linearize_list_and "$against"
74                                 else
75                                         echo
76                                 fi
77                         else
78                                 against=`echo "$against" | tr '\n' , | sed 's/,$//'`
79                                 printf '%s\t%s\t%s\n' "$origin" "$pkg" "$against"
80                         fi
81                 done
82         :
83 }
84
85 # ============= Insert initial origins to a list of origins =============
86 database_query_add_initial_origins ()
87 {
88         local origin
89         while read origin
90         do
91                 echo "$origin"
92                 [ -e "${DBDIR}/requires/$origin/initial_orig" ] || continue
93                 cat "${DBDIR}/requires/$origin/initial_orig"
94         done
95         :
96 }
97
98 # ============= Get target attributes =============
99 database_query_get_target_attributes ()
100 {
101         local prefix origin _is_all _is_target _is_requires_requirements _is_initial_requirements _is_requires_dependents _is_initial_dependents _is_requires_requirements_complement _is_relevant infofile tag level
102         prefix=$1
103         origin=$2
104         _is_all=y
105         _is_target=
106         _is_requires_requirements=
107         _is_initial_requirements=
108         _is_requires_dependents=
109         _is_initial_dependents=
110         _is_requires_requirements_complement=
111         _is_relevant=y
112         if [ ! -e "${DBDIR}/target_all" -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
113         then
114                 _is_all=
115                 tag=`options_get_dependency_type`
116                 level=full
117                 [ $opt_only_target_scope = yes ] && level=direct
118                 infofile=${DBDIR}/targets/$origin/attrs.${tag}.${level}
119                 if [ -e "$infofile" ]
120                 then
121                         . "$infofile"
122                 else
123                         _is_relevant=
124                 fi
125         fi
126         eval ${prefix}_is_all=\$\{_is_all\}
127         eval ${prefix}_is_target=\$\{_is_target\}
128         eval ${prefix}_is_requires_requirements=\$\{_is_requires_requirements\}
129         eval ${prefix}_is_initial_requirements=\$\{_is_initial_requirements\}
130         eval ${prefix}_is_requires_dependents=\$\{_is_requires_dependents\}
131         eval ${prefix}_is_initial_dependents=\$\{_is_initial_dependents\}
132         eval ${prefix}_is_requires_requirements_complement=\$\{_is_requires_requirements_complement\}
133         eval ${prefix}_is_relevant=\$\{_is_relevant\}
134 }
135
136 # ============= Check whether (re/de)installation of a port is suppressed =============
137 database_query_is_a_port_suppressed ()
138 {
139         local origin flag
140         origin=$1
141         if [ $opt_suppress_self_upadte = yes ]
142         then
143                 flag=SUPPRESSED_SELF
144         elif [ $opt_suppress_pkgtools_upadte = yes ]
145         then
146                 flag=SUPPRESSED_PKGNG
147         else
148                 return 1
149         fi
150         for db in initial requires
151         do
152                 [ -e "${DBDIR}/$db/$origin/$flag" ] && return
153         done
154         return 1
155 }
156
157 # ============= Check whether a port needs to be updated or upgraded =============
158 database_query_does_a_port_need_update ()
159 {
160         local origin dbpath
161         origin=$1
162         dbpath=${DBDIR}/requires/$origin
163         [ -e "$dbpath/conf_updated" ] && return
164         [ -e "$dbpath/new_version" ] || return
165         ! diff "$dbpath/new_version" "$dbpath/current_version" > /dev/null 2>&1
166 }
167
168 # ============= Check before operations of a command which need the temporary database completely prepared =============
169 database_query_chk_preparation_completion ()
170 {
171         program_chk_stage_complete PREPARATION && return
172         message_echo "ERROR: Database has to be built completely before executing this command." >&2
173         exit 1
174 }
175
176 # ============= Get a make variable value of a port =============
177 database_query_get_makevar_val ()
178 {
179         local origin variable dbdir cache value
180         origin=$1
181         variable=$2
182         dbdir=${DBDIR}/requires/$origin
183         cache=$dbdir/makevar/$variable
184         if [ -e "$cache" ]
185         then
186                 cat "$cache"
187         else
188                 value=`database_build_make "$origin" -V "$variable"`
189                 if [ -d "$dbdir" ] && misc_is_superuser_privilege
190                 then
191                         [ -d "$dbdir/makevar" ] || mkdir "$dbdir/makevar"
192                         echo "$value" > $cache.tmp
193                         mv "$cache.tmp" "$cache"
194                 fi
195                 echo "$value"
196         fi
197 }
198
199 # ============= Check whether configurations for a port is default =============
200 database_query_is_default_conf ()
201 {
202         local origin mode dbpath tmp_msg is_customized is_requiremnt_replaced files origin_regexp tmp_old tmp_new origin_requirement
203         origin=$1
204         mode=$2
205         dbpath=${DBDIR}/requires/$origin
206         if [ ! -e "$dbpath/is_customized" ]
207         then
208                 tmp_msg=${TMPDIR}/database_query_is_default_conf:msg
209                 cp /dev/null "$tmp_msg"
210                 is_customized=no
211                 if [ `ls "${DBDIR}/conf/each_port/$origin" 2> /dev/null | wc -l` -gt 0 ]
212                 then
213                         files=`ls "${DBDIR}/conf/each_port/$origin" | str_cancat_items_for_sentence`
214                         echo "Knobs and miscellaneous customization by $files," >> $tmp_msg
215                         is_customized=yes
216                 fi
217                 if ! diff "$dbpath/ports_options.default" "$dbpath/ports_options.current" > /dev/null 2>&1
218                 then
219                         echo "Non-default port options," >> $tmp_msg
220                         is_customized=yes
221                 fi
222                 origin_regexp=`str_escape_regexp "$origin"`
223                 if grep -q -E "^$origin_regexp$" "${DBDIR}/conf/NOPKG:PORTS.parsed" 2> /dev/null
224                 then
225                         echo "Explicit specification as non-default in ${APPNAME}.conf," >> $tmp_msg
226                         is_customized=yes
227                 fi
228                 tmp_old=${TMPDIR}/database_query_is_default_conf:old
229                 tmp_new=${TMPDIR}/database_query_is_default_conf:new
230                 is_requiremnt_replaced=no
231                 if fileedit_manipulate_old_new_lines "$dbpath/requirements.all.direct.orig" "$dbpath/requirements.all.direct" \
232                         "$tmp_old" "$tmp_new"
233                 then
234                         echo "Replacement in requirements:" >> $tmp_msg
235                         echo "-------- FROM --------" >> $tmp_msg
236                         sed 's/^/ /' "$tmp_old" >> $tmp_msg
237                         echo "--------  TO  --------" >> $tmp_msg
238                         sed 's/^/ /' "$tmp_new" >> $tmp_msg
239                         echo "----------------------" >> $tmp_msg
240                         is_customized=yes
241                 fi
242                 for origin_requirement in `cat "$dbpath/requirements.all.direct" 2> /dev/null`
243                 do
244                         database_query_is_default_conf "$origin_requirement" quiet && continue
245                         echo "Non-default requirement $origin_requirement," >> $tmp_msg
246                         is_customized=yes
247                 done
248                 { [ $is_customized = yes ] && cat "$tmp_msg"; } > $dbpath/is_customized.tmp
249                 mv "$dbpath/is_customized.tmp" "$dbpath/is_customized"
250         fi
251         [ `wc -c < $dbpath/is_customized` -eq 0 ] && return
252         if [ "x$mode" != xquiet ]
253         then
254                 message_echo "INFO: This port is configured to be non-default because of"
255                 message_cat 3<< eof
256 `sed 's/^/         /' "$dbpath/is_customized"`
257 eof
258                 message_echo "      so the prebuilt package is not used."
259         fi
260         return 1
261 }
262
263 # ============= Output of lists in which each matching port is registered =============
264 database_query_for_list_inclusion_of_matching_port ()
265 {
266         local grandtitle lists pkgnamedb deptag level isfirst origin_target pkg_target table_target
267         grandtitle=$1
268         lists=$2
269         pkgnamedb=$3
270         deptag=$4
271         level=$5
272         shift 5
273         message_echo "[$grandtitle]"
274         message_dependency_scope
275         message_echo
276         isfirst=y
277         for origin_target in `pkgsys_eval_ports_glob "$@"`
278         do
279                 pkg_target=
280                 for table_target in $pkgnamedb
281                 do
282                         pkg_target=`cat "${DBDIR}/$table_target/$origin_target/pkgtag" 2> /dev/null` || :
283                         [ -n "$pkg_target" ] && break
284                 done
285                 [ -n "$pkg_target" ] || continue
286                 isfirst=n
287                 match=
288                 for subject in `echo "$lists" | tr \| ' '`
289                 do
290                         database_query_exists_in_list "$origin_target" "$subject" "$deptag" "$level" \
291                                 && match="$match $subject"
292                 done
293                 if [ $opt_batch_mode = no ]
294                 then
295                         echo -n "$origin_target ($pkg_target): "
296                         echo "$match" | sed 's/^ *//;s/ /, /g'
297                 else
298                         printf '%s\t%s\t' "$origin_target" "$pkg_target"
299                         echo "$match" | sed 's/^ *//;s/ /,/g'
300                 fi
301         done
302         if [ "$isfirst" = y ]
303         then
304                 message_echo "ERROR: No inspected port matches the glob(s)." >&2
305                 exit 1
306         fi
307         :
308 }
309
310
311 # ============= Output of "show" command for each matching port =============
312 database_query_for_each_matching_port ()
313 {
314         local grandtitle title list pkgnamedb deptag level isfirst origin_target pkg_target table_target list_target
315         grandtitle=$1
316         title=$2
317         list=$3
318         pkgnamedb=$4
319         deptag=$5
320         level=$6
321         shift 6
322         message_echo "[$grandtitle]"
323         message_dependency_scope
324         message_echo
325         isfirst=y
326         for origin_target in `pkgsys_eval_ports_glob "$@"`
327         do
328                 pkg_target=
329                 for table_target in $pkgnamedb
330                 do
331                         pkg_target=`cat "${DBDIR}/$table_target/$origin_target/pkgtag" 2> /dev/null` || :
332                         [ -n "$pkg_target" ] && break
333                 done
334                 [ -n "$pkg_target" ] || continue
335                 [ "$isfirst" = y ] || message_echo
336                 isfirst=n
337                 [ $opt_batch_mode = no ] && printf "$title\n" "$origin_target ($pkg_target)"
338                 list_target=
339                 for table_target in $pkgnamedb
340                 do
341                         list_target=${DBDIR}/$table_target/$origin_target/$list
342                         [ -e "$list_target" ] && break
343                 done
344                 [ -e "$list_target" ] || continue
345                 if [ $opt_batch_mode = no ]
346                 then
347                         while read origin
348                         do
349                                 pkg=
350                                 for table in $pkgnamedb
351                                 do
352                                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
353                                         [ -n "$pkg" ] && break
354                                 done
355                                 [ -n "$pkg" ] || continue
356                                 echo "$origin ($pkg)"
357                         done < $list_target
358                 else
359                         while read origin
360                         do
361                                 pkg=
362                                 for table in $pkgnamedb
363                                 do
364                                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
365                                         [ -n "$pkg" ] && break
366                                 done
367                                 [ -n "$pkg" ] || continue
368                                 printf '%s\t%s\t%s\t%s\n' "$origin_target" "$pkg_target" "$origin" "$pkg"
369                         done < $list_target
370                 fi
371         done
372         if [ "$isfirst" = y ]
373         then
374                 message_echo "ERROR: No inspected port matches the glob(s)." >&2
375                 exit 1
376         fi
377         :
378 }
379
380 # ============= Output of "show" command for a single list =============
381 database_query_show_single_list ()
382 {
383         local list pkgnamedb flag_filter_skip_unchanged flag_filter_only_target tmpflag_exists put_blankline
384         list=$1
385         pkgnamedb=$2
386         flag_filter_skip_unchanged=$3
387         flag_filter_only_target=$4
388         tmpflag_exists=${TMPDIR}/database_query_show_single_list::exists_item
389         if [ `cat "${DBDIR}/$list" 2> /dev/null | wc -l` -eq 0 ]
390         then
391                 message_echo "INFO: No item is registered in this list."
392                 return 1
393         fi
394         rm -f "$tmpflag_exists"
395         put_blankline=
396         if [ -n "$flag_filter_only_target" \
397                 -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
398         then
399                 message_echo "INFO: Ports outside of the target scope are excluded."
400                 put_blankline=y
401         fi
402         if [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes ]
403         then
404                 message_echo "INFO: Ports which have been the newest with their all requirements from the first are excluded."
405                 put_blankline=y
406         fi
407         [ -n "$put_blankline" ] && message_echo
408         while read origin
409         do
410                 [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes \
411                         -a ! -e "${DBDIR}/requires/$origin/$flag_filter_skip_unchanged" ] \
412                         && continue
413                 if [ -n "$flag_filter_only_target" ]
414                 then
415                         database_query_get_target_attributes currentorigin "$origin"
416                         [ -n "${currentorigin_is_relevant}" ] || continue
417                         database_query_is_a_port_suppressed "$origin" && continue
418                 fi
419                 pkg=
420                 for table in $pkgnamedb
421                 do
422                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
423                         [ -n "$pkg" ] && break
424                 done
425                 [ -n "$pkg" ] || continue
426                 touch "$tmpflag_exists"
427                 if [ $opt_batch_mode = no ]
428                 then
429                         echo "$origin ($pkg)"
430                 else
431                         printf '%s\t%s\n' "$origin" "$pkg"
432                 fi
433         done < ${DBDIR}/$list
434         [ -e "$tmpflag_exists" ] && return
435         message_echo "INFO: No item is registered in this list."
436         return 1
437 }
438
439 # ============= Check whether the upgrade is necessary for a port =============
440 database_query_is_necessary_upgrade ()
441 {
442         local origin nodedir dbsuffix tmpfile_new tmpfile_old tmpfile_diff
443         origin=$1
444         nodedir=${DBDIR}/requires/$origin
445         [ -e "$nodedir/installed_by_pkg" ] && return 1
446         dbsuffix=`options_get_dependency_type`.`options_get_dependency_level`
447         tmpfile_new=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.new
448         tmpfile_old=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.old
449         tmpfile_diff=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.diff
450         [ -e "$nodedir/failed_requirements.${dbsuffix}.previous" ] || return
451         sort -u "$nodedir/failed_requirements.${dbsuffix}" > $tmpfile_new 2> /dev/null || :
452         sort -u "$nodedir/failed_requirements.${dbsuffix}.previous" > $tmpfile_old 2> /dev/null || :
453         fileedit_exists_old_lines "$tmpfile_old" "$tmpfile_new"
454 }
455
456 # ============= Actual operations of "show" command for a single list =============
457 database_query_show_single_list_exec ()
458 {
459         local subject deptag level dbsuffix flag_filter_skip_unchanged flag_filter_only_target pkgnamedb
460         subject=$1
461         deptag=$2
462         level=$3
463         dbsuffix=$deptag.$level
464         flag_filter_skip_unchanged=
465         flag_filter_only_target=
466         pkgnamedb='requires obsolete initial'
467         case $subject in
468         todo)
469                 message_echo "The following ports remain in the (re)installation queue for the current do/redo process:"
470                 message_echo "It is noted that ports to be skipped can be included here."
471                 message_dependency_scope
472                 message_echo
473                 list=stage.loop_list/reinst_todo.remain
474                 [ ${DBDIR}/reinst_order.list -nt ${DBDIR}/$list ] && list=reinst_order.list
475                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
476                 flag_filter_only_target=y
477                 ;;
478         done)
479                 message_echo "The following ports have been successfully (re)installed or newly installed:"
480                 message_dependency_scope
481                 message_echo
482                 list=success.$dbsuffix.list
483                 flag_filter_skip_unchanged=necessary_upgrade_completed.$dbsuffix
484                 flag_filter_only_target=y
485                 ;;
486         redo)
487                 message_echo "The following ports need (re)installation but are to be skipped until any of their failed requirements succeeds:"
488                 message_dependency_scope
489                 message_echo
490                 list=todo_after_requirements_succeed.$dbsuffix.list
491                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
492                 flag_filter_only_target=y
493                 ;;
494         resolved)
495                 message_echo "The following ports had problems which have been manually resolved:"
496                 message_echo
497                 list=manually_done.list
498                 ;;
499         failure)
500                 message_echo "The following ports experienced failures and kept to be old or uninstalled:"
501                 message_echo
502                 database_query_show_list_failure
503                 return
504                 ;;
505         conflict)
506                 message_echo "The following ports are temporarily deleted due to conflicts:"
507                 message_echo
508                 database_query_show_list_failed_conflicts_restoration
509                 return
510                 ;;
511         taboo)
512                 message_echo "The following ports are registered as taboo:"
513                 message_echo
514                 list=taboo.all.list
515                 ;;
516         need)
517                 message_echo "The following ports are registered as necessary:"
518                 message_echo
519                 list=need.list
520                 ;;
521         noneed)
522                 message_echo "The following ports are registered as unnecessary:"
523                 message_echo
524                 list=noneed.list
525                 ;;
526         restored)
527                 message_echo "The following leaf, obsolete or unneeded ports had been once deleted but are to be or have been restored:"
528                 message_echo
529                 list=stage.loop_list/ports_to_restore
530                 pkgnamedb='obsolete initial'
531                 flag_filter_only_target=y
532                 ;;
533         deleted)
534                 message_echo "The following leaf, obsolete or unneeded ports are to be or have been deleted:"
535                 message_echo
536                 list=stage.loop_list/ports_to_delete
537                 pkgnamedb='obsolete initial'
538                 flag_filter_only_target=y
539                 ;;
540         esac
541         database_query_show_single_list "$list" "$pkgnamedb" \
542                 "$flag_filter_skip_unchanged" "$flag_filter_only_target"
543 }
544
545 # ============= Check whether a port is registered in a list =============
546 database_query_exists_in_list ()
547 {
548         local origin subject deptag level tmp_list dbsuffix origin_esc origin_ptn
549         origin=$1
550         subject=$2
551         deptag=$3
552         level=$4
553         tmp_list=${TMPDIR}/database_query_exists_in_list:list
554         dbsuffix=$deptag.$level
555         origin_esc=`str_escape_regexp "$origin"`
556         origin_ptn="^$origin_esc$"
557         case $subject in
558         todo)
559                 list=stage.loop_list/reinst_todo.remain
560                 [ ${DBDIR}/reinst_order.list -nt ${DBDIR}/$list ] && list=reinst_order.list
561                 ;;
562         done)
563                 list=success.$dbsuffix.list
564                 ;;
565         redo)
566                 list=todo_after_requirements_succeed.$dbsuffix.list
567                 ;;
568         resolved)
569                 list=manually_done.list
570                 ;;
571         failure)
572                 list=failed.list
573                 ;;
574         conflict)
575                 grep -v -E -f "${DBDIR}/ports_to_delete.grep_pattern_col1" "${DBDIR}/deleted_conflicts" 2> /dev/null \
576                         | grep -q -E "^${origin_esc}[[:space:]]"
577                 return
578                 ;;
579         taboo)
580                 list=taboo.all.list
581                 ;;
582         need)
583                 list=need.list
584                 ;;
585         noneed)
586                 list=noneed.list
587                 ;;
588         restored)
589                 list=stage.loop_list/ports_to_restore
590                 ;;
591         deleted)
592                 list=stage.loop_list/ports_to_delete
593                 ;;
594         esac
595         grep -q -E "$origin_ptn" "${DBDIR}/$list" 2> /dev/null
596 }