OSDN Git Service

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