OSDN Git Service

32803854a62c9fb86890986071b43dbe747bdb91
[portsreinstall/current.git] / lib / libdatabase_build.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Operations for building the temporary database -
5 # Copyright (C) 2013-2016 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Variables =============
10 DATABASE_VERSION=
11 DATABASE_IS_OBSOLETE=no
12
13 # ============= Creation =============
14 database_build_create ()
15 {
16         [ `id -u` -eq 0 -a ! -d "${DBDIR}" ] && mkdir -p "${DBDIR}"
17         misc_lock_duplicated_executions "${DBDIR}/.lock"
18         if [ -e "${DBDIR}/MYVERSION" ]
19         then
20                 if ! grep -q -E "$COMPATIBLE_VERSIONS" "${DBDIR}/MYVERSION" 2> /dev/null
21                 then
22                         message_echo "ERROR: The current temporary database is incompatible. You must delete it by" >&2
23                         message_echo "        ${APPNAME} clean force" >&2
24                         message_echo "       in order to enable the current version." >&2
25                         exit 1
26                 fi
27         elif misc_is_superuser_privilege
28         then
29                 echo "$MYVERSION" > ${DBDIR}/MYVERSION
30         fi
31         DATABASE_VERSION=`cat "${DBDIR}"/MYVERSION 2> /dev/null || :`
32         misc_is_superuser_privilege || return 0
33         for subdir in initial requires replace targets obsolete backup_packages \
34                 stage.loop_list stage.complete stage.reinit_loop stage.depends
35         do
36                 [ -d "${DBDIR}/$subdir" ] || mkdir -p "${DBDIR}/$subdir"
37         done
38 }
39
40 # ============= Refresh the temporary database =============
41 database_build_refresh ()
42 {
43         misc_is_superuser_privilege || return
44         [ $opt_suppress_obsolete_db_clean = no ] || return
45         message_echo "INFO: The temporary database is cleaned up."
46         message_echo
47         [ -d "${DBDIR}" -a ! -d "${DBDIR}.tmp" ] && mv "${DBDIR}" "${DBDIR}.tmp"
48         database_build_create
49         mv "${DBDIR}.tmp/saved_options.sh" "${DBDIR}" 2> /dev/null || :
50         mv "${DBDIR}.tmp/backup_packages" "${DBDIR}" 2> /dev/null || :
51         mv "${DBDIR}.tmp/backup_pkgarcs.lst" "${DBDIR}" 2> /dev/null || :
52         rm -rf "${DBDIR}.tmp"
53 }
54
55 # ============= Clean up the temporary database for upgrade of this utility =============
56 database_build_clean_for_self_upgrade ()
57 {
58         misc_is_superuser_privilege || return
59         [ $opt_suppress_obsolete_db_clean = no ] || return
60         rm -rf "${DBDIR}"
61         database_build_create
62         [ -e "${DBDIR}/MYVERSION" ] && mv "${DBDIR}/MYVERSION" "${DBDIR}/MYVERSION.prev"
63         :
64 }
65
66 # ============= Check whether the temporary database is newer than the ports tree and refresh if so =============
67 database_build_refresh_if_obsolete ()
68 {
69         if [ "${PORTS_INDEX_DB}" -nt "${DBDIR}"/MYVERSION ] && misc_is_superuser_privilege
70         then
71                 if [ $opt_suppress_obsolete_db_clean = no -a "z${command}" = zclean ]
72                 then
73                         DATABASE_IS_OBSOLETE=no
74                         message_echo "WARNING: The temporary database is older than the ports tree." >&2
75                         database_build_refresh || DATABASE_IS_OBSOLETE=yes
76                 else
77                         DATABASE_IS_OBSOLETE=yes
78                 fi
79         else
80                 DATABASE_IS_OBSOLETE=no
81         fi
82 }
83
84 # ============= Register an obsolete origin =============
85 database_build_register_obsolete_port ()
86 {
87         local origin dbpath pkgtag
88         origin=$1
89         dbpath=${DBDIR}/obsolete/$origin
90         [ -e "$dbpath/complete_as_node" ] && return
91         [ -d "${DBDIR}/obsolete/$origin" ] || mkdir -p "${DBDIR}/obsolete/$origin"
92         pkgtag=`pkgsys_pkg_info_qO_init "$origin"`
93         [ -n "$pkgtag" ] || pkgtag='[not installed]'
94         echo "$pkgtag" > ${DBDIR}/obsolete/$origin/pkgtag
95         for table in dependents requirements
96         do
97                 for level in direct full
98                 do
99                         for tag in all run build
100                         do
101                                 srcfile=${DBDIR}/initial/$origin/${table}.${tag}.${level}
102                                 [ -e "$srcfile" ] && ln -f "$srcfile" "$dbpath/${table}.${tag}.${level}.src"
103                         done
104                 done
105         done
106         touch "$dbpath/complete_as_node"
107 }
108
109 # ============= Convert and register if an origin is obsolete =============
110 database_build_convert_and_register_origin_if_obsolete ()
111 {
112         local origin recursedb_in recursedb output_origin iline_db origin_new date_moved why_moved
113         origin=$1
114         recursedb_in=$2
115         recursedb=${recursedb_in:-${PORTS_MOVED_DB}}
116         echo "$origin" > ${TMPDIR}/database_build_convert_and_register_origin_if_obsolete:origin
117         [ -d "${PORTSDIR}/$origin" ] && return
118         database_build_register_obsolete_port "$origin"
119         grep -n -m 1 -E "^`str_escape_regexp \"$origin\"`\|" "$recursedb" 2> /dev/null > ${TMPDIR}/moved.info || :
120         if [ `wc -l < ${TMPDIR}/moved.info` -eq 0 ]
121         then
122                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/obsolete_ports"
123                 if [ -n "$recursedb_in" ]
124                 then
125                         message_echo "${DEPTH_INDEX}  ===> Disappeared port (MOVED broken?)"
126                 else
127                         message_echo "${DEPTH_INDEX}  ===> Nonexistent port (your original?)"
128                 fi
129                 return 1
130         else
131                 iline_db=`cut -d : -f 1 "${TMPDIR}/moved.info"`
132                 sed 1,${iline_db}d "${PORTS_MOVED_DB}" > ${TMPDIR}/MOVED.DB
133                 origin_new=`sed -E 's/^[0-9]+://' "${TMPDIR}/moved.info" | cut -d '|' -f 2 || :`
134                 date_moved=`cut -d '|' -f 3 "${TMPDIR}/moved.info" || :`
135                 why_moved=`cut -d '|' -f 4 "${TMPDIR}/moved.info" || :`
136                 if [ -n "$origin_new" ]
137                 then
138                         message_echo "${DEPTH_INDEX}  ===> Moved to $origin_new at $date_moved because \"$why_moved\""
139                         database_build_convert_and_register_origin_if_obsolete "$origin_new" "${TMPDIR}/MOVED.DB" || return 1
140                 else
141                         message_echo "${DEPTH_INDEX}  ===> Deleted at $date_moved because \"$why_moved\""
142                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/obsolete_ports"
143                         return 1
144                 fi
145         fi
146 }
147 # ============= [Sub-function] Get the output value of converted origin =============
148 _database_build_convert_and_register_origin_if_obsolete__get_origin ()
149 {
150         cat "${TMPDIR}/database_build_convert_and_register_origin_if_obsolete:origin"
151 }
152
153 # ============= Get the make arguments for building the temporary database =============
154 database_build_setup_make_args ()
155 {
156         local origin
157         origin=$1
158         {
159                 for key in LOCALBASE LINUXBASE PORT_DBDIR PORTSDIR DISTDIR PACKAGES PKGREPOSITORY
160                 do
161                         eval echo $key=\$$key
162                 done
163                 echo 'DISABLE_VULNERABILITIES=yes'
164                 if [ $opt_apply_default_config = yes ]
165                 then
166                         if pkgsys_is_dialog4ports_used
167                         then
168                                 echo 'NO_DIALOG=yes'
169                         else
170                                 echo 'BATCH=yes'
171                         fi
172                 fi
173                 dbdir=${DBDIR}/requires/$origin
174                 [ -d "$dbdir" ] || dbdir=${DBDIR}/conf/each_port/$origin
175                 cat "$dbdir/MARG.conf" 2> /dev/null || :
176         } | tr '\n' ' '
177 }
178
179 # ============= Get the make environment variables for building the temporary database =============
180 database_build_setup_make_envs ()
181 {
182         local origin dbdir
183         origin=$1
184         dbdir=${DBDIR}/requires/$origin
185         [ -d "$dbdir" ] || dbdir=${DBDIR}/conf/each_port/$origin
186         cat "$dbdir/MENV.conf" 2> /dev/null || :
187 }
188
189 # ============= Execute make command for building the temporary database =============
190 database_build_make ()
191 {
192         local origin MAKE_ARGS MAKE_ENVS
193         origin=$1
194         shift
195         MAKE_ARGS=`database_build_setup_make_args "$origin"`
196         MAKE_ENVS=`database_build_setup_make_envs "$origin"`
197         env $MAKE_ENVS make -C "${PORTSDIR}/$origin" "$@" $MAKE_ARGS
198 }
199
200 # ============= Set up a temporary database node for the initial state of a port =============
201 database_build_setup_initial_node ()
202 {
203         local origin pkg dbpath
204         origin=$1
205         dbpath=${DBDIR}/initial/$origin
206         [ -e "$dbpath/complete_as_node" ] && return
207         rm -rf "$dbpath"
208         mkdir -p "$dbpath"
209         pkg=`pkg_info_qO "$origin"`
210         if [ -n "$pkg" ]
211         then
212                 echo "$pkg" > $dbpath/installed_version
213                 ln -f "$dbpath/installed_version" "$dbpath/pkgtag"
214                 pkg_info_qr "$pkg" | while read requirement
215                 do
216                         origin_requirement=`pkgsys_init_pkg_orig_by_ambiguous_matching "$requirement" || :`
217                         [ -n "$origin_requirement" ] && echo "$origin_requirement"
218                         :
219                 done > $dbpath/requirements.all.full
220                 pkg_info_qR "$pkg" | while read dependent
221                 do
222                         origin_dependent=`pkgsys_init_pkg_orig_by_ambiguous_matching "$dependent" || :`
223                         [ -n "$origin_dependent" ] && echo "$origin_dependent"
224                         :
225                 done > $dbpath/dependents.all.full
226                 for table in dependents requirements
227                 do
228                         for level in direct full
229                         do
230                                 for tag in all run build
231                                 do
232                                         [ "${tag}.${level}" = all.full ] && continue
233                                         ln -f "$dbpath/${table}.all.full" "$dbpath/${table}.${tag}.${level}"
234                                 done
235                         done
236                 done
237         fi
238         if [ `expr "$pkg" : "^${APPNAME}-[0-9].*"` -gt 0 ]
239         then
240                 [ -d "$dbpath" ] && touch "$dbpath/SUPPRESSED_SELF"
241         elif [ `expr "$pkg" : "^pkg-[0-9].*"` -gt 0 ]
242         then
243                 [ -d "$dbpath" ] && touch "$dbpath/SUPPRESSED_PKGNG"
244         fi
245         touch "$dbpath/complete_as_node"
246 }
247
248 # ============= Set up a temporary database node for the replaced/moved information of a port =============
249 database_build_setup_replace_node ()
250 {
251         local origin_orig origin dbpath
252         origin_orig=$1
253         dbpath=${DBDIR}/replace/$origin_orig
254         if [ ! -e "$dbpath/complete_as_node" ]
255         then
256                 rm -rf "$dbpath"
257                 mkdir -p "$dbpath"
258                 origin=$origin_orig
259                 if echo "$origin_orig" | grep -q -E -f "${DBDIR}/conf/REPLACE.grep_from_pattern"
260                 then
261                         origin=`echo "$origin_orig" | sed -E -f "${DBDIR}/conf/REPLACE.sed_pattern"`
262                         if [ "x$origin_orig" != "x$origin" ]
263                         then
264                                 if [ -n "$origin" ]
265                                 then
266                                         message_echo "${DEPTH_INDEX}  ===> Replaced with $origin by user configuration"
267                                 else
268                                         database_build_register_obsolete_port "$origin_orig"
269                                         message_echo "${DEPTH_INDEX}  ===> Deleted by user configuration"
270                                 fi > $dbpath/message
271                         fi
272                 fi
273                 if [ -n "$origin" ]
274                 then
275                         if database_build_convert_and_register_origin_if_obsolete "$origin" >> $dbpath/message
276                         then
277                                 origin=`_database_build_convert_and_register_origin_if_obsolete__get_origin`
278                         else
279                                 if [ "x$origin" != "x$origin_orig" ]
280                                 then
281                                         message_echo "${DEPTH_INDEX}  ===> Going back to the original port $origin_orig"
282                                         if database_build_convert_and_register_origin_if_obsolete "$origin_orig"
283                                         then
284                                                 origin=`_database_build_convert_and_register_origin_if_obsolete__get_origin`
285                                         else
286                                                 origin=
287                                         fi
288                                 else
289                                         origin=
290                                 fi >> $dbpath/message
291                         fi
292                 fi
293                 [ "x$origin_orig" = "x$origin" ] || echo "$origin" > $dbpath/origin
294                 touch "$dbpath/complete_as_node"
295         fi
296         cat "$dbpath/message" 2> /dev/null || :
297 }
298
299 # ============= Get the inspected level for a port with the current option settings =============
300 database_build_get_inspected_level ()
301 {
302         local origin origin_dependent origin_esc origin_dependent_esc
303         origin=$1
304         origin_dependent=$2
305         origin_esc='^'`str_escape_regexp "$origin"`'$'
306         origin_dependent_esc='^'`str_escape_regexp "$origin_dependent"`'$'
307         if [ $opt_only_target_scope = no ]
308         then
309                 echo full
310         elif ! pkgsys_pkg_info_eO "$origin" \
311                 || grep -E "$origin_esc" "${DBDIR}/stage.loop_list/ports_to_inspect" > /dev/null \
312                 || [ ! -e "${DBDIR}/requires/$origin_dependent/installed_version" ] \
313                 || grep -E "$origin_dependent_esc" "${DBDIR}/stage.loop_list/ports_to_inspect" > /dev/null
314         then
315                 echo direct
316         else
317                 echo node
318         fi
319 }
320
321 # ============= Check whether a port has been inspected in a required level =============
322 database_build_is_port_already_inspected_in_required_level ()
323 {
324         local origin origin_dependent origin_actual origin_esc inspected_level
325         origin=$1
326         origin_dependent=$2
327         origin_actual=`echo "$origin" | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" 2> /dev/null || :`
328         [ -n "$origin_actual" ] || origin_actual=$origin
329         origin_esc='^'`str_escape_regexp "$origin_actual"`'$'
330         inspected_level=`database_build_get_inspected_level "$origin_actual" "$origin_dependent"`
331         grep -q -E "^$origin_esc$" "${DBDIR}/ports.inspected.${inspected_level}.list" \
332                 "${DBDIR}/obsolete_ports" 2> /dev/null || return
333         fileedit_rm_a_line "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
334         [ "x$origin" = "$origin_actual" ] || \
335                 fileedit_rm_a_line "$origin_actual" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
336         :
337 }
338
339 # ============= Update the current package name of a port =============
340 database_build_update_pkgname ()
341 {
342         local origin pkg savefile origin_orig
343         origin=$1
344         savefile=${DBDIR}/requires/$origin/current_version
345         if [ -e "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern" ]
346         then
347                 origin_orig=`echo "$origin" \
348                         | sed -E -f "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"` || :
349                 [ "x$origin_orig" = "x$origin" ] && origin_orig=
350         else
351                 origin_orig=
352         fi
353         echo "$origin_orig" "$origin" | tr ' ' '\n' | grep -v '^$' | while read orig
354         do
355                 pkg=`pkg_info_qO "$orig" || :`
356                 if [ -z "$pkg" -a -e "${DBDIR}/requires/$orig/initial_orig" ]
357                 then
358                         orig_init=`cat "${DBDIR}/requires/$orig/initial_orig"`
359                         pkg=`pkg_info_qO "$orig_init" || :`
360                 fi
361                 [ -n "$pkg" ] && echo "$pkg"
362                 :
363         done > $savefile
364         cat "$savefile"
365 }
366
367 # ============= Get the current package name of a port =============
368 database_build_get_pkgname ()
369 {
370         local origin savefile
371         origin=$1
372         savefile=${DBDIR}/requires/$origin/current_version
373         if [ -e "$savefile" ]
374         then
375                 cat "$savefile"
376         else
377                 database_build_update_pkgname "$origin"
378         fi
379 }
380
381 # ============= Get the new package name of a port =============
382 database_build_get_new_pkgname ()
383 {
384         local origin savefile pkg
385         origin=$1
386         savefile=${DBDIR}/requires/$origin/new_version
387         if [ ! -e "$savefile" ]
388         then
389                 database_build_make "$origin" package-name \
390                         | tr -d '\n' > $savefile
391         fi
392         cat "$savefile"
393 }
394
395 # ============= Build the original message tag showing the version upgrade =============
396 database_build_create_pkgtag ()
397 {
398         local origin dbdir pkg_init pkg_new pkgtag
399         origin=$1
400         dbdir=${DBDIR}/requires/$origin
401         pkg_init=`database_build_get_pkgname "$origin"`
402         [ -n "$pkg_init" -a ! -e "$dbdir/installed_version" ] && \
403                 echo -n "$pkg_init" > $dbdir/installed_version
404         pkg_new=`database_build_get_new_pkgname "$origin"`
405         pkgtag=$pkg_init
406         [ -n "$pkgtag" ] || pkgtag=$pkg_new
407         if [ -z "$pkgtag" ]
408         then
409                 pkgtag='?'
410         
411         elif [ "x$pkg_init" != "x$pkg_new" ]
412         then
413                 if [ -n "$pkg_init" ]
414                 then
415                         pkgtag="$pkg_init => $pkg_new"
416                 else
417                         pkgtag="[new] $pkg_new"
418                 fi
419         fi
420         echo "$pkgtag" > $dbdir/pkgtag.orig
421         echo "$pkgtag" > $dbdir/pkgtag
422 }
423
424 # ============= Update the message tag showing the version upgrade =============
425 database_build_update_pkgtag ()
426 {
427         local origin pkg_init pkg_bak pkg_cur detail pkgtag
428         origin=$1
429         pkg_init=`cat "${DBDIR}/requires/$origin/installed_version" 2> /dev/null | tr '\n' ' ' | sed 's/ *$//'`
430         pkg_bak=`cat "${DBDIR}/requires/$origin/backedup_version" 2> /dev/null | tr '\n' ' ' | sed 's/ *$//'`
431         pkg_cur=`database_build_get_pkgname "$origin" | tr '\n' ' ' | sed 's/ *$//'`
432         detail=
433         if [ "x$pkg_init" != "x$pkg_cur" ]
434         then
435                 if [ -n "$pkg_cur" ]
436                 then
437                         detail=" [currently installed version: $pkg_cur]"
438                 elif [ -n "$pkg_bak" ]
439                 then
440                         detail=" [currently deinstalled, previously installed version: $pkg_bak]"
441                 else
442                         detail=" [currently deinstalled]"
443                 fi
444         fi
445         pkgtag=`cat "${DBDIR}/requires/$origin/pkgtag.orig"`
446         echo "$pkgtag$detail" > ${DBDIR}/requires/$origin/pkgtag
447 }
448
449 # ============= Check whether the currently installed package version is the latest =============
450 database_build_is_currentpkg_latest ()
451 {
452         local origin pkg_cur pkg_new
453         origin=$1
454         pkg_cur=`database_build_get_pkgname "$origin" | tr '\n' ' ' | sed 's/ *$//'`
455         pkg_new=`database_build_get_new_pkgname "$origin"`
456         [ "x$pkg_cur" = "x$pkg_new" ]
457 }
458
459 # ============= Recursively inspect dependencies of a port and build a node database of the information =============
460 database_build_inspect_dependencies ()
461 {
462         local origin_orig origin_dependent origin_orig_regexp origin origin_regexp tag stage dbpath origin_id origin_dependency DEPTH_INDEX_orig nlines iline dist_subdir_rpl inspected_level inspected_levels_compatible origin_tmp inspected_level_tmp conf_updated
463         origin_orig=$1
464         origin_dependent=$2
465         [ -z "$origin_orig" ] && return
466         database_build_is_port_already_inspected_in_required_level "$origin_orig" "$origin_dependent" && return
467         origin_orig_regexp=`str_escape_regexp "$origin_orig"`
468         DEPTH_INDEX_orig=${DEPTH_INDEX}
469         DEPTH_INDEX="${DEPTH_INDEX}--"
470         message_echo "${DEPTH_INDEX} $origin_orig"
471         origin_id=`echo "$origin_orig" | tr / :`
472         database_build_setup_initial_node "$origin_orig"
473         database_build_setup_replace_node "$origin_orig"
474         if [ -e "${DBDIR}/replace/$origin_orig/origin" ]
475         then
476                 origin=`cat "${DBDIR}/replace/$origin_orig/origin"`
477         else
478                 origin=$origin_orig
479         fi
480         origin_regexp=`str_escape_regexp "$origin"`
481         inspected_level=
482         inspected_levels_compatible=
483         if [ -n "$origin" ]
484         then
485                 fileedit_rm_a_line "$origin" "${DBDIR}/obsolete_ports"
486                 dbpath=${DBDIR}/requires/$origin
487                 if [ ! -e "$dbpath/complete_as_node" ]
488                 then
489                         conf_updated=
490                         if grep -q -E -e "^$origin_orig_regexp$" -e "^$origin_regexp$" "${DBDIR}/to_be_reconf" 2> /dev/null
491                         then
492                                 message_echo "${DEPTH_INDEX}  ===> Reconfigured"
493                                 conf_updated=y
494                         fi
495                         rm -rf "$dbpath"
496                         mkdir -p "$dbpath"
497                         [ -n "$conf_updated" ] && touch "$dbpath/conf_updated"
498                         [ "x$origin_orig" = "x$origin" ] || echo "$origin_orig" > $dbpath/initial_orig
499                         [ -e "${DBDIR}/initial/$origin_orig/SUPPRESSED_SELF" ] && touch "$dbpath/SUPPRESSED_SELF"
500                         [ -e "${DBDIR}/initial/$origin_orig/SUPPRESSED_PKGNG" ] && touch "$dbpath/SUPPRESSED_PKGNG"
501                         if [ -d "${DBDIR}/conf/each_port/$origin" ]
502                         then
503                                 cp -R "${DBDIR}/conf/each_port/$origin/"* "$dbpath/" > /dev/null 2>&1 || :
504                         fi
505                         tmp_portsdb_work=${TMPDIR}/database_build_inspect_dependencies:portsdb_work
506                         [ -d "$tmp_portsdb_work" ] || mkdir "$tmp_portsdb_work"
507                         ( set -e
508                                 export PORT_DBDIR=$tmp_portsdb_work
509                                 database_build_make "$origin" showconfig > $dbpath/ports_options.default
510                         )
511                         if [ `wc -c < $dbpath/ports_options.default` -gt 0 ]
512                         then
513                                 if [ $opt_apply_default_config = yes ]
514                                 then
515                                         if ! pkgsys_is_dialog4ports_used
516                                         then
517                                                 printf '\t\n' | database_build_make "$origin" config-conditional > /dev/null
518                                         fi
519                                 else
520                                         database_build_make "$origin" config-conditional
521                                 fi
522                                 database_build_make "$origin" showconfig > $dbpath/ports_options.current
523                         else
524                                 cp /dev/null "$dbpath/ports_options.current"
525                         fi
526                         if [ ! -e "${DBDIR}/initial/$origin_orig/installed_version" ]
527                         then
528                                 cp "${DBDIR}/initial/$origin_orig/installed_version" "$dbpath" 2> /dev/null || :
529                         fi
530                         database_build_create_pkgtag "$origin"
531                         for tag in run build
532                         do
533                                 database_build_make "$origin" $tag-depends-list \
534                                         | sed -E "s/^`str_escape_regexp "${PORTSDIR}"`\///" \
535                                         | grep -Ev "`pkgsys_pkgtools_ports_filter_regexp`" \
536                                         > $dbpath/requirements.$tag.orig || :
537                                 sed -E -f "${DBDIR}/conf/REPLACE.sed_pattern" "$dbpath/requirements.$tag.orig" \
538                                         | grep -v '^$' > $dbpath/requirements.$tag.src || :
539                         done
540                         for stage in orig src
541                         do
542                                 sort -u "$dbpath/requirements.run.${stage}" "$dbpath/requirements.build.${stage}" \
543                                         > $dbpath/requirements.all.direct.${stage}
544                                 mv "$dbpath/requirements.build.${stage}" "$dbpath/requirements.build.direct.${stage}"
545                                 mv "$dbpath/requirements.run.${stage}" "$dbpath/requirements.run.direct.${stage}"
546                         done
547                         touch "$dbpath/complete_as_node"
548                         fileedit_rm_a_line "$origin_orig" "${DBDIR}/to_be_reconf"
549                         fileedit_rm_a_line "$origin" "${DBDIR}/to_be_reconf"
550                 else
551                         for level in direct full
552                         do
553                                 for tag in run build
554                                 do
555                                         rm -f "$dbpath/requirements.${tag}.${level}"
556                                 done
557                         done
558                         for origin_tmp in "$origin" "$origin_orig"
559                         do
560                                 for inspected_level_tmp in full direct node
561                                 do
562                                         fileedit_rm_a_line "$origin_tmp" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
563                                 done
564                         done
565                 fi
566                 inspected_level=`database_build_get_inspected_level "$origin" "$origin_dependent"`
567                 case $inspected_level in
568                 full)
569                         grep -v -E -f "${DBDIR}/installed_ports.grep_pattern" \
570                                 "$dbpath/requirements.all.direct.src" > ${TMPDIR}/missing.$origin_id || :
571                         inspected_levels_compatible='full direct node'
572                         ;;
573                 direct)
574                         grep -v -E -f "${DBDIR}/installed_ports.grep_pattern" \
575                                 "$dbpath/requirements.all.direct.src" > ${TMPDIR}/missing.$origin_id || :
576                         inspected_levels_compatible='direct node'
577                         ;;
578                 node)
579                         cp /dev/null "${TMPDIR}/missing.$origin_id"
580                         inspected_levels_compatible='node'
581                         ;;
582                 esac
583                 nlines=`wc -l < ${TMPDIR}/missing.$origin_id`
584                 iline=1
585                 while [ $iline -le $nlines ]
586                 do
587                         origin_dependency=`sed -n ${iline}p "${TMPDIR}/missing.$origin_id"`
588                         iline=$(($iline+1))
589                         grep -q -E '^'`str_escape_regexp "$origin_dependency"`'$' \
590                                 "${DBDIR}/ports.inspected.list" 2> /dev/null && \
591                                         continue
592                         database_build_inspect_dependencies "$origin_dependency" "$origin"
593                 done
594                 rm -f "${TMPDIR}/missing.$origin_id"
595                 dist_subdir_rpl=`database_query_get_makevar_val "$origin" DIST_SUBDIR | str_escape_replaceval_filter` || :
596                 [ -n "$dist_subdir_rpl" ] && dist_subdir_rpl="$dist_subdir_rpl\/"
597                 database_build_make "$origin" fetch-urlall-list \
598                         | sed -E "s/.*\/([^\/]+)$/$dist_subdir_rpl\1/" \
599                         | sort -u >> ${DBDIR}/distfiles.inspected
600         fi
601         if [ "x$origin_orig" != "x$origin" ]
602         then
603                 if [ -n "$origin" ]
604                 then
605                         for inspected_level_tmp in $inspected_levels_compatible
606                         do
607                                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
608                         done
609                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/ports.inspected.list"
610                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/inspected_ports.update"
611                         fileedit_rm_a_line "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
612                 fi
613         fi
614         for inspected_level_tmp in $inspected_levels_compatible
615         do
616                 fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
617         done
618         fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/ports.inspected.list"
619         fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/inspected_ports.update"
620         fileedit_rm_a_line "$origin_orig" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
621         message_echo "${DEPTH_INDEX}  ===> ok"
622
623         DEPTH_INDEX=${DEPTH_INDEX_orig}
624 }
625
626 # ============= Build and get a list of the complete recursive dependencies of a port =============
627 database_build_get_complete_recursive_dependency ()
628 {
629         local table origin suffix tmpdb_parents dbpath srcfile dstfile loophead origin_esc tmppath dstfile_tmp
630         table=$1
631         origin=$2
632         suffix=$3
633         tmpdb_parents=${TMPDIR}/database_build_get_complete_recursive_dependency.parents
634         dbpath=${DBDIR}/requires/$origin
635         srcfile=$dbpath/$table.direct$suffix
636         [ -e "$srcfile" ] || return 0
637         dstfile=$dbpath/$table.full$suffix
638         if [ ! -e "$dstfile" ]
639         then
640                 origin_esc=`str_escape_regexp "$origin"`
641                 touch "$tmpdb_parents"
642                 num_parents=`wc -l < $tmpdb_parents`
643                 if grep -Eq "^$origin_esc$" "$tmpdb_parents"
644                 then
645                         loophead=`grep -En "^$origin_esc$" "$tmpdb_parents" | tail -n 1 | cut -d : -f 1`
646                         message_echo 'WARNING: The following loop was found:' >&2
647                         message_echo "  $origin" >&2
648                         sed -n $(($loophead+1)),\$p "$tmpdb_parents" | sed 's/^/  -->/' | message_cat >&2
649                         message_echo "  -->$origin" >&2
650                         if [ "x$opt_force_continuation_for_looped_dependency" = xno ]
651                         then
652                                 message_echo 'Resolve the problem manually if possible, and then restart by' >&2
653                                 message_echo "        ${APPNAME} reset keepopts" >&2
654                                 message_echo "        ${APPNAME}" >&2
655                                 message_echo 'Otherwise, you may attempt to forcibly continue by' >&2
656                                 message_echo "        ${APPNAME} -f" >&2
657                                 exit 1
658                         else
659                                 message_echo '(Forcibly continue)' >&2
660                         fi
661                 else
662                         echo "$origin" >> $tmpdb_parents
663                         tmppath=${TMPDIR}/requires/$origin
664                         dstfile_tmp=$tmppath/$table.full$suffix
665                         [ -d "$tmppath" ] || mkdir -p "$tmppath"
666                         while read origin_requirement
667                         do
668                                 echo "$origin_requirement"
669                                 database_build_get_complete_recursive_dependency "$table" "$origin_requirement" "$suffix"
670                         done < $srcfile > $dstfile_tmp
671                         sort -u "$dstfile_tmp" > $dstfile
672                         rm "$dstfile_tmp"
673                         head -n ${num_parents}p "$tmpdb_parents" > $tmpdb_parents.tmp
674                         mv "$tmpdb_parents.tmp" "$tmpdb_parents"
675                 fi
676         fi
677         cat "$dstfile"
678 }
679
680 # ============= Inspect the necessity of requirements of a necessary port even in case of skipping unchanged ports =============
681 # Here the "necessity" means that a port must be kept installed, newly installed or reinstalled for run- or build-time operations.
682 # In other words, "unnecessary" ports are what are not yet installed and not required by any "necessary" ports neither in run- or build-time.
683 database_build_inspect_necessity_for_only_new_upgrade ()
684 {
685         local origin level dbpath tmpfile
686         origin=$1
687         level=$2
688         dbpath=${DBDIR}/requires/$origin
689         [ ! -d "$dbpath" -o -e "$dbpath/necessary_port.${level}" ] && return
690         tmpfile=${TMPDIR}/database_build_inspect_necessity_for_only_new_upgrade:`echo "$origin" | tr / :`
691         if database_query_does_a_port_need_update "$origin"
692         then
693                 sort -u "$dbpath/requirements.build.direct" "$dbpath/requirements.run.${level}" || :
694         else
695                 cat "$dbpath/requirements.run.${level}" || :
696         fi 2> /dev/null > $tmpfile
697         if [ `wc -l < $tmpfile` -gt 0 ]
698         then
699                 while read origin_requirement
700                 do
701                         database_build_inspect_necessity_for_only_new_upgrade "$origin_requirement" "$level"
702                 done < $tmpfile
703         fi
704         rm "$tmpfile"
705         touch "$dbpath/necessary_port.${level}"
706 }
707
708 # ============= Build complement relations to new dependents for targets recursively =============
709 database_build_complement_to_new_dependents_for_targets ()
710 {
711         local origin dbdir reqdir level
712         origin=$1
713         dbdir=${DBDIR}/targets/$origin
714         reqdir=${DBDIR}/requires/$origin
715         [ -d "$dbdir" ] || return 0
716         echo "$origin" >> ${DBDIR}/stage.loop_list/parse_target_attr_info
717         if [ -e "$dbdir/target_itself" ] && database_query_does_a_port_need_update "$origin"
718         then
719                 for level in direct full
720                 do
721                         cat "$reqdir/requirements.all.${level}" 2> /dev/null | while read origin_requirement
722                         do
723                                 fileedit_add_a_line_if_new "$origin" \
724                                         "${DBDIR}/targets/$origin_requirement/complement_for_new_dependents.${level}"
725                         done
726                 done
727                 cat "$reqdir/requirements.all.direct" "$reqdir/requirements.all.full" 2> /dev/null \
728                         | sort -u | while read origin_requirement
729                 do
730                         database_build_complement_to_new_dependents_for_targets "$origin_requirement"
731                 done
732         fi
733 }
734
735 # ============= Build target attribute files recursively =============
736 database_build_target_attributes ()
737 {
738         local origin dbdir reqdir _is_target _is_requires_requirements _is_initial_requirements _is_requires_dependents _is_initial_dependents _is_requires_requirements_complement _is_relevant tag level database table
739         origin=$1
740         dbdir=${DBDIR}/targets/$origin
741         reqdir=${DBDIR}/requires/$origin
742         [ -d "$dbdir" ] || return 0
743         [ -e "$dbdir/COMPLETE_ATTRS" ] && return
744         _is_target=
745         [ -e "$dbdir/target_itself" ] && _is_target=y
746         for tag in all run build none
747         do
748                 for level in direct full
749                 do
750                         _is_relevant=${_is_target}
751                         _is_requires_requirements=
752                         _is_initial_requirements=
753                         _is_requires_dependents=
754                         _is_initial_dependents=
755                         _is_requires_requirements_complement=
756                         for database in requires initial
757                         do
758                                 for table in requirements dependents
759                                 do
760                                         if [ -e "$dbdir/target_${database}_${table}.${tag}.${level}" ]
761                                         then
762                                                 eval _is_${database}_${table}=y
763                                                 _is_relevant=y
764                                         fi
765                                 done
766                         done
767                         if [ -z "${_is_requires_requirements}" -a -e "$dbdir/complement_for_new_dependents.${level}" ]
768                         then
769                                 _is_requires_requirements_complement=y
770                                 _is_relevant=y
771                         fi
772                         [ -n "${_is_relevant}" ] && cat > $dbdir/attrs.${tag}.${level} << eof
773 _is_target=${_is_target}
774 _is_requires_requirements=${_is_requires_requirements}
775 _is_initial_requirements=${_is_initial_requirements}
776 _is_requires_dependents=${_is_requires_dependents}
777 _is_initial_dependents=${_is_initial_dependents}
778 _is_requires_requirements_complement=${_is_requires_requirements_complement}
779 eof
780                 done
781         done
782         touch "$dbdir/COMPLETE_ATTRS"
783 }
784
785 # ============= Order the ports considering dependencies =============
786 database_build_order_ports_considering_dependencies ()
787 {
788         touch "${DBDIR}/reinst_order.list.tmp"
789         cat > ${TMPDIR}/order_dependencies.awk << eof
790 BEGIN {
791         it = 0;
792         i = 0;
793 }
794 {
795         if (NF == 0)
796         {
797                 i = 0;
798         }
799         else
800         {
801                 if (i == 0)
802                 {
803                         target = \$0;
804                         sub (/\/requirements.all\.full$/, "", target);
805                         sub (/^\.\//, "", target);
806                         srcikey[it] = target;
807                         srckeyi[target] = it;
808                         it++;
809                 }
810                 else
811                 {
812                         src[it-1,i-1] = \$0;
813                         srcimax[it-1] = srcsize[it-1] = i;
814                 }
815                 i++;
816         }
817 }
818 END {
819         ntargets = it;
820         norder = 0;
821         order_str = "";
822         icycle = 0;
823         lf_order_str = "";
824         while (1)
825         {
826                 is_operated = 0;
827                 for (it = 0; it < ntargets; it++)
828                 {
829                         if (!(it in srcikey)) continue;
830                         if (srcsize[it] > 0) continue;
831                         is_operated = 1;
832                         target = srcikey[it];
833                         delete srcikey[it];
834                         order[norder++] = target;
835                         order_str = order_str lf_order_str;
836                         order_str = sprintf ("%s%s", order_str, target);
837                         lf_order_str = "\n";
838                         for (jt = 0; jt < ntargets; jt++)
839                         {
840                                 for (j = 0; j < srcimax[jt]; j++)
841                                 {
842                                         if ((jt,j) in src && src[jt,j] == target)
843                                         {
844                                                 delete src[jt,j];
845                                                 srcsize[jt]--;
846                                                 break;
847                                         }
848                                 }
849                         }
850                 }
851                 if (is_operated == 0) break;
852                 icycle++;
853         }
854         reinst_order_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/reinst_order.list.tmp");
855         print order_str > reinst_order_list;
856         unsatisfied = "";
857         for (it = 0; it < ntargets; it++)
858         {
859                 if (srcsize[it] == 0) continue;
860                 reqs = "";
861                 sp_reqs = "";
862                 for (i = 0; i < srcimax[it]; i++)
863                 {
864                         if ((it,i) in src)
865                         {
866                                 reqs = reqs sp_reqs src[it,i];
867                                 sp_reqs = ", ";
868                         }
869                 }
870                 unsatisfied = sprintf ("%s%s [%d] (%s)\n", unsatisfied, srcikey[it], srcsize[it], reqs);
871         }
872         if (unsatisfied != "")
873         {
874                 unsatisfied_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/unsatisfied.list");
875                 print unsatisfied > unsatisfied_list;
876                 exit 1;
877         }
878 }
879 eof
880         (cd "${DBDIR}/requires" && \
881                 find . -depth 3 -name requirements.all.full -exec echo {} \; -exec cat {} \; -exec echo \;) | \
882                 env "DBDIR=${DBDIR}" awk -f "${TMPDIR}"/order_dependencies.awk || return
883         grep -v '^$' "${DBDIR}/reinst_order.list.tmp" > "${DBDIR}/reinst_order.list" || :
884 }
885
886 # ============= [Sub-function] Common operations for resetting configurations for a port =============
887 _database_build_reset_a_port_confdb ()
888 {
889         local origin origin_replace db
890         origin=$1
891         [ -d "${DBDIR}/initial/$origin" -o -d "${DBDIR}/replace/$origin" \
892                 -o -d "${DBDIR}/requires/$origin" -o -d "${DBDIR}/targets/$origin" ] || return 0
893         touch "${DBDIR}/inspected_ports_only_partially"
894         {
895                 echo "$origin"
896                 cat "${DBDIR}/replace/$origin/origin" 2> /dev/null || :
897                 for dbtag in initial requires
898                 do
899                         for tabel in requirements dependents
900                         do
901                                 cat "${DBDIR}/$dbtag/$origin/$tabel.all.full" 2> /dev/null || :
902                                 cat "${DBDIR}/$dbtag/$origin/$tabel.all.full.orig" 2> /dev/null || :
903                                 rm -f "${DBDIR}/$dbtag/$origin/$tabel.run.full" \
904                                         "${DBDIR}/$dbtag/$origin/$tabel.build.full" \
905                                         "${DBDIR}/$dbtag/$origin/is_customized" 2> /dev/null
906                         done
907                 done
908         } | sort -u >> ${DBDIR}/inspected_ports.update
909         for level in full direct node
910         do
911                 fileedit_rm_a_line "$origin" "${DBDIR}/ports.inspected.${level}.list"
912         done
913         fileedit_rm_a_line "$origin" "${DBDIR}/obsolete_ports"
914         fileedit_rm_a_line "$origin" "${DBDIR}/ports.inspected.list"
915         cat "${DBDIR}/replace/$origin/origin" 2> /dev/null || :
916 }
917
918 # ============= Clear database directories for an origin =============
919 database_build_clear_db_dirs ()
920 {
921         local origin db
922         origin=$1
923         for db in requires replace targets obsolete
924         do
925                 rm -rf "${DBDIR}/$db/$origin"
926         done
927 }
928
929 # ============= Remove configurations for a port permanently =============
930 database_build_forget ()
931 {
932         local origin origin_replace
933         origin=$1
934         origin_replace=`_database_build_reset_a_port_confdb "$origin"`
935         fileedit_rm_a_line "$origin" "${DBDIR}/targets_specified_so_far"
936         [ -z "$origin_replace" ] || database_build_forget "$origin_replace"
937         database_build_clear_db_dirs "$origin"
938 }
939
940 # ============= Patch to the temporary database so as to re-inspect and reinstall ports whose configurations were changed =============
941 database_build_patch_reconf ()
942 {
943         local origin origin_replace
944         origin=$1
945         origin_replace=`_database_build_reset_a_port_confdb "$origin"`
946         [ -d "${DBDIR}/initial/$origin" -o -d "${DBDIR}/requires/$origin" ] && \
947                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect"
948         fileedit_add_a_line_if_new "$origin" "${DBDIR}/to_be_reconf"
949         [ -z "$origin_replace" ] || database_build_patch_reconf "$origin_replace"
950         database_build_clear_db_dirs "$origin"
951 }
952
953 # ============= Post-processes after finishing to inspect dependencies =============
954 database_build_post_inspect_dependencies ()
955 {
956         local table
957         touch "${DBDIR}/obsolete_ports" "${DBDIR}/inspected_ports.update"
958         find "${DBDIR}/requires" -depth 2 -type d \
959                 | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/inspected_ports
960         find "${DBDIR}/initial" -depth 2 -type d \
961                 | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/inspected_ports.initial
962         sort -u "${DBDIR}/inspected_ports" "${DBDIR}/inspected_ports.initial" > ${DBDIR}/inspected_ports.all
963         str_escape_regexp_filter < ${DBDIR}/inspected_ports \
964                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.grep_pattern
965         str_escape_regexp_filter < ${DBDIR}/inspected_ports.initial \
966                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.initial.grep_pattern
967         str_escape_regexp_filter < ${DBDIR}/inspected_ports.all \
968                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.all.grep_pattern
969         cat "${DBDIR}/conf/HOLD_PORTS.grep_pattern" "${DBDIR}/need.grep_pattern" \
970                 2> /dev/null > ${TMPDIR}/INSPECT_ALL_DEPENDENCIES:obsolete_ports.exclude.grep_pattern || :
971         grep -v -E -f "${TMPDIR}/INSPECT_ALL_DEPENDENCIES:obsolete_ports.exclude.grep_pattern" \
972                 "${DBDIR}/obsolete_ports" > ${DBDIR}/obsolete_ports.can_be_deleted || :
973         cp /dev/null "${DBDIR}/REPLACE.complete_sed_pattern.tmp"
974         cp /dev/null "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp"
975         find "${DBDIR}/replace" -depth 3 -type f -name origin | while read nodepath
976         do
977                 origin_orig=`expr "$nodepath" : '.*/\([^/][^/]*/[^/][^/]*\)/origin$'`
978                 origin=`cat "$nodepath"`
979                 origin_orig_regexp=`str_escape_regexp "$origin_orig"`
980                 origin_orig_esc=`str_escape_replaceval "$origin_orig"`
981                 origin_regexp=`str_escape_regexp "$origin"`
982                 origin_esc=`str_escape_replaceval "$origin"`
983                 echo "s/^$origin_orig_regexp$/$origin_esc/" >> ${DBDIR}/REPLACE.complete_sed_pattern.tmp
984                 [ -z "$origin_regexp" ] && continue
985                 echo "s/^$origin_regexp$/$origin_orig_esc/" >> ${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp
986         done
987         mv "${DBDIR}/REPLACE.complete_sed_pattern.tmp" "${DBDIR}/REPLACE.complete_sed_pattern"
988         mv "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp" "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"
989         if [ `cat "${DBDIR}/inspected_ports.update" 2> /dev/null | wc -l` -gt 0 ]
990         then
991                 grep -E -f "${DBDIR}/inspected_ports.all.grep_pattern" "${DBDIR}/inspected_ports.update" \
992                         > ${DBDIR}/inspected_ports.update.tmp || :
993                 mv "${DBDIR}/inspected_ports.update.tmp" "${DBDIR}/inspected_ports.update"
994                 if [ $opt_only_target_scope = yes ]
995                 then
996                         touch "${DBDIR}/inspected_ports_only_partially"
997                 else
998                         rm -f "${DBDIR}/inspected_ports_only_partially"
999                 fi
1000                 if program_chk_stage_loop_complete CONVERT_REQUIREMENTS_LIST
1001                 then
1002                         mv "${DBDIR}/inspected_ports.update" "${DBDIR}/stage.loop_list/convert_dependency_lists"
1003                 else
1004                         cat "${DBDIR}/inspected_ports.update" "${DBDIR}/stage.loop_list/convert_dependency_lists" \
1005                                 2> /dev/null | sort -u > ${DBDIR}/stage.loop_list/convert_dependency_lists.tmp
1006                         mv "${DBDIR}/stage.loop_list/convert_dependency_lists.tmp" \
1007                                 "${DBDIR}/stage.loop_list/convert_dependency_lists"
1008                         rm -f "${DBDIR}/inspected_ports.update"
1009                 fi
1010         else
1011                 program_chk_stage_loop_complete CONVERT_REQUIREMENTS_LIST \
1012                         && rm -f "${DBDIR}/stage.loop_list/convert_dependency_lists"
1013         fi
1014         {
1015                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "${DBDIR}/need.list" || :
1016                 cat "${DBDIR}/need.list" || :
1017         } 2> /dev/null | sort -u > ${DBDIR}/need.with_replaced.list
1018         for table in requirements dependents itself
1019         do
1020                 [ -e "${DBDIR}/stage.loop_list/target_$table.specified" ] || continue
1021                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" \
1022                         "${DBDIR}/stage.loop_list/target_$table.specified" \
1023                         > ${DBDIR}/stage.loop_list/target_$table.replaced.specified
1024         done    
1025         cp /dev/null "${DBDIR}/update_dependencies"
1026 }