OSDN Git Service

Version 3.0.0
[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 origin_requirement in `cat "$dbpath/requirements.all.direct" 2> /dev/null`
232                 do
233                         database_query_is_default_conf "$origin_requirement" quiet && continue
234                         echo "Non-default requirement $origin_requirement," >> $tmp_msg
235                         is_customized=yes
236                 done
237                 { [ $is_customized = yes ] && cat "$tmp_msg"; } > $dbpath/is_customized.tmp
238                 mv "$dbpath/is_customized.tmp" "$dbpath/is_customized"
239         fi
240         [ `wc -c < $dbpath/is_customized` -eq 0 ] && return
241         if [ "x$mode" != xquiet ]
242         then
243                 message_echo "INFO: This port is configured to be non-default because of"
244                 message_cat 3<< eof
245 `sed 's/^/         /' "$dbpath/is_customized"`
246 eof
247                 message_echo "      so the prebuilt package is not used."
248         fi
249         return 1
250 }
251
252 # ============= Output of "show" command for each matching port =============
253 database_query_for_each_matching_port ()
254 {
255         local grandtitle title list isfirst origin_target pkg_target table_target
256         grandtitle=$1
257         title=$2
258         list=$3
259         pkgnamedb=$4
260         deptag=$5
261         level=$6
262         shift 6
263         message_echo "[$grandtitle]"
264         message_dependency_scope
265         message_echo
266         isfirst=y
267         for origin_target in `pkgsys_eval_ports_glob "$@"`
268         do
269                 pkg_target=
270                 for table_target in $pkgnamedb
271                 do
272                         pkg_target=`cat "${DBDIR}/$table_target/$origin_target/pkgtag" 2> /dev/null` || :
273                         [ -n "$pkg_target" ] && break
274                 done
275                 [ -n "$pkg_target" ] || continue
276                 [ "$isfirst" = y ] || message_echo
277                 isfirst=n
278                 [ $opt_batch_mode = no ] && printf "$title\n" "$origin_target ($pkg_target)"
279                 list_target=
280                 for table_target in $pkgnamedb
281                 do
282                         list_target=${DBDIR}/$table_target/$origin_target/$list
283                         [ -e "$list_target" ] && break
284                 done
285                 [ -e "$list_target" ] || continue
286                 if [ $opt_batch_mode = no ]
287                 then
288                         while read origin
289                         do
290                                 pkg=
291                                 for table in $pkgnamedb
292                                 do
293                                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
294                                         [ -n "$pkg" ] && break
295                                 done
296                                 [ -n "$pkg" ] || continue
297                                 echo "$origin ($pkg)"
298                         done < $list_target
299                 else
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                                 printf '%s\t%s\t%s\t%s\n' "$origin_target" "$pkg_target" "$origin" "$pkg"
310                         done < $list_target
311                 fi
312         done
313         if [ "$isfirst" = y ]
314         then
315                 message_echo "ERROR: No matching port for the glob(s) is in the temporary database." >&2
316                 exit 1
317         fi
318         :
319 }
320
321 # ============= Output of "show" command for a single list =============
322 database_query_show_single_list ()
323 {
324         local list pkgnamedb flag_filter_skip_unchanged flag_filter_only_target tmpflag_exists put_blankline
325         list=$1
326         pkgnamedb=$2
327         flag_filter_skip_unchanged=$3
328         flag_filter_only_target=$4
329         tmpflag_exists=${TMPDIR}/database_query_show_single_list::exists_item
330         if [ `cat "${DBDIR}/$list" 2> /dev/null | wc -l` -eq 0 ]
331         then
332                 message_echo "INFO: No item is registered in this list."
333                 return 1
334         fi
335         rm -f "$tmpflag_exists"
336         put_blankline=
337         if [ -n "$flag_filter_only_target" \
338                 -a -n "$opt_target_itself$opt_target_dependents$opt_target_requirements" ]
339         then
340                 message_echo "INFO: Ports outside of the target scope are excluded."
341                 put_blankline=y
342         fi
343         if [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes ]
344         then
345                 message_echo "INFO: Ports which have been the newest with their all requirements from the first are excluded."
346                 put_blankline=y
347         fi
348         [ -n "$put_blankline" ] && message_echo
349         while read origin
350         do
351                 [ -n "$flag_filter_skip_unchanged" -a $opt_skip_unchanged = yes \
352                         -a ! -e "${DBDIR}/requires/$origin/$flag_filter_skip_unchanged" ] \
353                         && continue
354                 if [ -n "$flag_filter_only_target" ]
355                 then
356                         database_query_get_target_attributes currentorigin "$origin"
357                         [ -n "${currentorigin_is_relevant}" ] || continue
358                         database_query_is_a_port_suppressed "$origin" && continue
359                 fi
360                 pkg=
361                 for table in $pkgnamedb
362                 do
363                         pkg=`cat "${DBDIR}/$table/$origin/pkgtag" 2> /dev/null` || :
364                         [ -n "$pkg" ] && break
365                 done
366                 [ -n "$pkg" ] || continue
367                 touch "$tmpflag_exists"
368                 if [ $opt_batch_mode = no ]
369                 then
370                         echo "$origin ($pkg)"
371                 else
372                         printf '%s\t%s\n' "$origin" "$pkg"
373                 fi
374         done < ${DBDIR}/$list
375         [ -e "$tmpflag_exists" ] && return
376         message_echo "INFO: No item is registered in this list."
377         return 1
378 }
379
380 # ============= Check whether the upgrade is necessary for a port =============
381 database_query_is_necessary_upgrade ()
382 {
383         local origin nodedir dbsuffix tmpfile_new tmpfile_old tmpfile_diff
384         origin=$1
385         nodedir=${DBDIR}/requires/$origin
386         [ -e "$nodedir/installed_by_pkg" ] && return 1
387         dbsuffix=`options_get_dependency_type`.`options_get_dependency_level`
388         tmpfile_new=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.new
389         tmpfile_old=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.old
390         tmpfile_diff=${TMPDIR}/database_query_is_necessary_upgrade:failed_requirements.diff
391         [ -e "$nodedir/failed_requirements.${dbsuffix}.previous" ] || return
392         sort -u "$nodedir/failed_requirements.${dbsuffix}" > $tmpfile_new 2> /dev/null || :
393         sort -u "$nodedir/failed_requirements.${dbsuffix}.previous" > $tmpfile_old 2> /dev/null || :
394         fileedit_exists_old_lines "$tmpfile_old" "$tmpfile_new"
395 }
396
397 # ============= Actual operations of "show" command for a single list =============
398 database_query_show_single_list_exec ()
399 {
400         local subject deptag level dbsuffix flag_filter_skip_unchanged flag_filter_only_target pkgnamedb
401         subject=$1
402         deptag=$2
403         level=$3
404         dbsuffix=$deptag.$level
405         flag_filter_skip_unchanged=
406         flag_filter_only_target=
407         pkgnamedb='requires obsolete initial'
408         case $subject in
409         todo)
410                 message_echo "The following ports remain in the (re)installation queue for the current do/redo process:"
411                 message_echo "It is noted that ports to be skipped can be included here."
412                 message_dependency_scope
413                 message_echo
414                 list=stage.loop_list/reinst_todo.remain
415                 [ ${DBDIR}/reinst_order.list -nt ${DBDIR}/$list ] && list=reinst_order.list
416                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
417                 flag_filter_only_target=y
418                 ;;
419         done)
420                 message_echo "The following ports have been successfully (re)installed or newly installed:"
421                 message_dependency_scope
422                 message_echo
423                 list=success.$dbsuffix.list
424                 flag_filter_skip_unchanged=necessary_upgrade_completed.$dbsuffix
425                 flag_filter_only_target=y
426                 ;;
427         redo)
428                 message_echo "The following ports need (re)installation but are to be skipped until any of their failed requirements succeeds:"
429                 message_dependency_scope
430                 message_echo
431                 list=todo_after_requirements_succeed.$dbsuffix.list
432                 flag_filter_skip_unchanged=necessary_upgrade.$dbsuffix
433                 flag_filter_only_target=y
434                 ;;
435         resolved)
436                 message_echo "The following ports had problems which have been manually resolved:"
437                 message_echo
438                 list=manually_done.list
439                 ;;
440         failure)
441                 message_echo "The following ports experienced failures and kept to be old or uninstalled:"
442                 message_echo
443                 database_query_show_list_failure
444                 return
445                 ;;
446         conflict)
447                 message_echo "The following ports are temporarily deleted due to conflicts:"
448                 message_echo
449                 database_query_show_list_failed_conflicts_restoration
450                 return
451                 ;;
452         taboo)
453                 message_echo "The following ports are registered as taboo:"
454                 message_echo
455                 list=taboo.all.list
456                 ;;
457         need)
458                 message_echo "The following ports are registered as necessary:"
459                 message_echo
460                 list=need.list
461                 ;;
462         noneed)
463                 message_echo "The following ports are registered as unnecessary:"
464                 message_echo
465                 list=noneed.list
466                 ;;
467         restored)
468                 message_echo "The following leaf, obsolete or unneeded ports had been once deleted but are to be or have been restored:"
469                 message_echo
470                 list=stage.loop_list/ports_to_restore
471                 pkgnamedb='obsolete initial'
472                 flag_filter_only_target=y
473                 ;;
474         deleted)
475                 message_echo "The following leaf, obsolete or unneeded ports are to be or have been deleted:"
476                 message_echo
477                 list=stage.loop_list/ports_to_delete
478                 pkgnamedb='obsolete initial'
479                 flag_filter_only_target=y
480                 ;;
481         esac
482         database_query_show_single_list "$list" "$pkgnamedb" \
483                 "$flag_filter_skip_unchanged" "$flag_filter_only_target"
484 }