OSDN Git Service

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