OSDN Git Service

Version 3.0.4
[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" | str_cancat_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                 message_cat 3<< eof
262 `sed 's/^/         /' "$dbpath/is_customized"`
263 eof
264                 message_echo "      so the prebuilt package is not used."
265         fi
266         return 1
267 }
268
269 # ============= Output of lists in which each matching port is registered =============
270 database_query_for_list_inclusion_of_matching_port ()
271 {
272         local grandtitle lists pkgnamedb deptag level isfirst origin_target pkg_target table_target
273         grandtitle=$1
274         lists=$2
275         pkgnamedb=$3
276         deptag=$4
277         level=$5
278         shift 5
279         message_echo "[$grandtitle]"
280         message_dependency_scope
281         message_echo
282         isfirst=y
283         for origin_target in `pkgsys_eval_ports_glob "$@"`
284         do
285                 pkg_target=
286                 for table_target in $pkgnamedb
287                 do
288                         pkg_target=`cat "${DBDIR}/$table_target/$origin_target/pkgtag" 2> /dev/null` || :
289                         [ -n "$pkg_target" ] && break
290                 done
291                 [ -n "$pkg_target" ] || continue
292                 isfirst=n
293                 match=
294                 for subject in `echo "$lists" | tr \| ' '`
295                 do
296                         database_query_exists_in_list "$origin_target" "$subject" "$deptag" "$level" \
297                                 && match="$match $subject"
298                 done
299                 if [ $opt_batch_mode = no ]
300                 then
301                         echo -n "$origin_target ($pkg_target): "
302                         echo "$match" | sed 's/^ *//;s/ /, /g'
303                 else
304                         printf '%s\t%s\t' "$origin_target" "$pkg_target"
305                         echo "$match" | sed 's/^ *//;s/ /,/g'
306                 fi
307         done
308         if [ "$isfirst" = y ]
309         then
310                 message_echo "ERROR: No inspected port matches the glob(s)." >&2
311                 exit 1
312         fi
313         :
314 }
315
316
317 # ============= Output of "show" command for each matching port =============
318 database_query_for_each_matching_port ()
319 {
320         local grandtitle title list pkgnamedb deptag level isfirst origin_target pkg_target table_target list_target
321         grandtitle=$1
322         title=$2
323         list=$3
324         pkgnamedb=$4
325         deptag=$5
326         level=$6
327         shift 6
328         message_echo "[$grandtitle]"
329         message_dependency_scope
330         message_echo
331         isfirst=y
332         for origin_target in `pkgsys_eval_ports_glob "$@"`
333         do
334                 pkg_target=
335                 for table_target in $pkgnamedb
336                 do
337                         pkg_target=`cat "${DBDIR}/$table_target/$origin_target/pkgtag" 2> /dev/null` || :
338                         [ -n "$pkg_target" ] && break
339                 done
340                 [ -n "$pkg_target" ] || continue
341                 [ "$isfirst" = y ] || message_echo
342                 isfirst=n
343                 [ $opt_batch_mode = no ] && printf "$title\n" "$origin_target ($pkg_target)"
344                 list_target=
345                 for table_target in $pkgnamedb
346                 do
347                         list_target=${DBDIR}/$table_target/$origin_target/$list
348                         [ -e "$list_target" ] && break
349                 done
350                 [ -e "$list_target" ] || continue
351                 if [ $opt_batch_mode = no ]
352                 then
353                         while read origin
354                         do
355                                 pkg=
356                                 for table in $pkgnamedb
357                                 do
358                                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
359                                         [ -n "$pkg" ] && break
360                                 done
361                                 [ -n "$pkg" ] || continue
362                                 echo "$origin ($pkg)"
363                         done < $list_target
364                 else
365                         while read origin
366                         do
367                                 pkg=
368                                 for table in $pkgnamedb
369                                 do
370                                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
371                                         [ -n "$pkg" ] && break
372                                 done
373                                 [ -n "$pkg" ] || continue
374                                 printf '%s\t%s\t%s\t%s\n' "$origin_target" "$pkg_target" "$origin" "$pkg"
375                         done < $list_target
376                 fi
377         done
378         if [ "$isfirst" = y ]
379         then
380                 message_echo "ERROR: No inspected port matches the glob(s)." >&2
381                 exit 1
382         fi
383         :
384 }
385
386 # ============= Output of "show" command for a single list =============
387 database_query_show_single_list ()
388 {
389         local list pkgnamedb flag_filter_skip_unchanged flag_filter_only_target tmpflag_exists put_blankline
390         list=$1
391         pkgnamedb=$2
392         flag_filter_skip_unchanged=$3
393         flag_filter_only_target=$4
394         tmpflag_exists=${TMPDIR}/database_query_show_single_list::exists_item
395         if [ `cat "${DBDIR}/$list" 2> /dev/null | wc -l` -eq 0 ]
396         then
397                 message_echo "INFO: No item is registered in this list."
398                 return 1
399         fi
400         rm -f "$tmpflag_exists"
401         put_blankline=
402         if [ -n "$flag_filter_only_target" \
403                 -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
404         then
405                 message_echo "INFO: Ports outside of the target scope are excluded."
406                 put_blankline=y
407         fi
408         if [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes ]
409         then
410                 message_echo "INFO: Ports which have been the newest with their all requirements from the first are excluded."
411                 put_blankline=y
412         fi
413         [ -n "$put_blankline" ] && message_echo
414         while read origin
415         do
416                 [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes \
417                         -a ! -e "${DBDIR}/requires/$origin/$flag_filter_skip_unchanged" ] \
418                         && continue
419                 if [ -n "$flag_filter_only_target" ]
420                 then
421                         database_query_get_target_attributes currentorigin "$origin"
422                         [ -n "${currentorigin_is_relevant}" ] || continue
423                         database_query_is_a_port_suppressed "$origin" && continue
424                 fi
425                 pkg=
426                 for table in $pkgnamedb
427                 do
428                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
429                         [ -n "$pkg" ] && break
430                 done
431                 [ -n "$pkg" ] || continue
432                 touch "$tmpflag_exists"
433                 if [ $opt_batch_mode = no ]
434                 then
435                         echo "$origin ($pkg)"
436                 else
437                         printf '%s\t%s\n' "$origin" "$pkg"
438                 fi
439         done < ${DBDIR}/$list
440         [ -e "$tmpflag_exists" ] && return
441         message_echo "INFO: No item is registered in this list."
442         return 1
443 }
444
445 # ============= Check whether the upgrade is necessary for a port =============
446 database_query_is_necessary_upgrade ()
447 {
448         local origin nodedir dbsuffix tmpfile_new tmpfile_old tmpfile_diff
449         origin=$1
450         nodedir=${DBDIR}/requires/$origin
451         [ -e "$nodedir/installed_by_pkg" ] && return 1
452         dbsuffix=`options_get_dependency_type`.`options_get_dependency_level`
453         tmpfile_new=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.new
454         tmpfile_old=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.old
455         tmpfile_diff=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.diff
456         [ -e "$nodedir/failed_requirements.${dbsuffix}.previous" ] || return
457         sort -u "$nodedir/failed_requirements.${dbsuffix}" > $tmpfile_new 2> /dev/null || :
458         sort -u "$nodedir/failed_requirements.${dbsuffix}.previous" > $tmpfile_old 2> /dev/null || :
459         fileedit_exists_old_lines "$tmpfile_old" "$tmpfile_new"
460 }
461
462 # ============= Actual operations of "show" command for a single list =============
463 database_query_show_single_list_exec ()
464 {
465         local subject deptag level dbsuffix flag_filter_skip_unchanged flag_filter_only_target pkgnamedb
466         subject=$1
467         deptag=$2
468         level=$3
469         dbsuffix=$deptag.$level
470         flag_filter_skip_unchanged=
471         flag_filter_only_target=
472         pkgnamedb='requires obsolete initial'
473         case $subject in
474         todo)
475                 message_echo "The following ports remain in the (re)installation queue for the current do/redo process:"
476                 message_echo "It is noted that ports to be skipped can be included here."
477                 message_dependency_scope
478                 message_echo
479                 list=stage.loop_list/reinst_todo.remain
480                 [ ${DBDIR}/reinst_order.list -nt ${DBDIR}/$list ] && list=reinst_order.list
481                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
482                 flag_filter_only_target=y
483                 ;;
484         done)
485                 message_echo "The following ports have been successfully (re)installed or newly installed:"
486                 message_dependency_scope
487                 message_echo
488                 list=success.$dbsuffix.list
489                 flag_filter_skip_unchanged=necessary_upgrade_completed.$dbsuffix
490                 flag_filter_only_target=y
491                 ;;
492         redo)
493                 message_echo "The following ports need (re)installation but are to be skipped until any of their failed requirements succeeds:"
494                 message_dependency_scope
495                 message_echo
496                 list=todo_after_requirements_succeed.$dbsuffix.list
497                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
498                 flag_filter_only_target=y
499                 ;;
500         resolved)
501                 message_echo "The following ports had problems which have been manually resolved:"
502                 message_echo
503                 list=manually_done.list
504                 ;;
505         failure)
506                 message_echo "The following ports experienced failures and kept to be old or uninstalled:"
507                 message_echo
508                 database_query_show_list_failure
509                 return
510                 ;;
511         conflict)
512                 message_echo "The following ports are temporarily deleted due to conflicts:"
513                 message_echo
514                 database_query_show_list_failed_conflicts_restoration
515                 return
516                 ;;
517         taboo)
518                 message_echo "The following ports are registered as taboo:"
519                 message_echo
520                 list=taboo.all.list
521                 ;;
522         need)
523                 message_echo "The following ports are registered as necessary:"
524                 message_echo
525                 list=need.list
526                 ;;
527         noneed)
528                 message_echo "The following ports are registered as unnecessary:"
529                 message_echo
530                 list=noneed.list
531                 ;;
532         restored)
533                 message_echo "The following leaf, obsolete or unneeded ports had been once deleted but are to be or have been restored:"
534                 message_echo
535                 list=stage.loop_list/ports_to_restore
536                 pkgnamedb='obsolete initial'
537                 flag_filter_only_target=y
538                 ;;
539         deleted)
540                 message_echo "The following leaf, obsolete or unneeded ports are to be or have been deleted:"
541                 message_echo
542                 list=stage.loop_list/ports_to_delete
543                 pkgnamedb='obsolete initial'
544                 flag_filter_only_target=y
545                 ;;
546         esac
547         database_query_show_single_list "$list" "$pkgnamedb" \
548                 "$flag_filter_skip_unchanged" "$flag_filter_only_target"
549 }
550
551 # ============= Check whether a port is registered in a list =============
552 database_query_exists_in_list ()
553 {
554         local origin subject deptag level tmp_list dbsuffix origin_esc origin_ptn
555         origin=$1
556         subject=$2
557         deptag=$3
558         level=$4
559         tmp_list=${TMPDIR}/database_query_exists_in_list:list
560         dbsuffix=$deptag.$level
561         origin_esc=`str_escape_regexp "$origin"`
562         origin_ptn="^$origin_esc$"
563         case $subject in
564         todo)
565                 list=stage.loop_list/reinst_todo.remain
566                 [ ${DBDIR}/reinst_order.list -nt ${DBDIR}/$list ] && list=reinst_order.list
567                 ;;
568         done)
569                 list=success.$dbsuffix.list
570                 ;;
571         redo)
572                 list=todo_after_requirements_succeed.$dbsuffix.list
573                 ;;
574         resolved)
575                 list=manually_done.list
576                 ;;
577         failure)
578                 list=failed.list
579                 ;;
580         conflict)
581                 grep -v -E -f "${DBDIR}/ports_to_delete.grep_pattern_col1" "${DBDIR}/deleted_conflicts" 2> /dev/null \
582                         | grep -q -E "^${origin_esc}[[:space:]]"
583                 return
584                 ;;
585         taboo)
586                 list=taboo.all.list
587                 ;;
588         need)
589                 list=need.list
590                 ;;
591         noneed)
592                 list=noneed.list
593                 ;;
594         restored)
595                 list=stage.loop_list/ports_to_restore
596                 ;;
597         deleted)
598                 list=stage.loop_list/ports_to_delete
599                 ;;
600         esac
601         grep -q -E "$origin_ptn" "${DBDIR}/$list" 2> /dev/null
602 }