OSDN Git Service

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