OSDN Git Service

ae13e888f948c3ed22f54b3a379779a7a8fc612d
[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 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                                 ln -f "${DBDIR}/initial/$origin/${table}.${tag}.${level}" "$dbpath/${table}.${tag}.${level}.src"
102                         done
103                 done
104         done
105         touch "$dbpath/complete_as_node"
106 }
107
108 # ============= Convert and register if an origin is obsolete =============
109 database_build_convert_and_register_origin_if_obsolete ()
110 {
111         local origin recursedb_in recursedb output_origin iline_db origin_new date_moved why_moved
112         origin=$1
113         recursedb_in=$2
114         recursedb=${recursedb_in:-${PORTS_MOVED_DB}}
115         echo "$origin" > ${TMPDIR}/database_build_convert_and_register_origin_if_obsolete:origin
116         [ -d "${PORTSDIR}/$origin" ] && return
117         database_build_register_obsolete_port "$origin"
118         grep -n -m 1 -E "^`str_escape_regexp \"$origin\"`\|" "$recursedb" 2> /dev/null > ${TMPDIR}/moved.info || :
119         if [ `wc -l < ${TMPDIR}/moved.info` -eq 0 ]
120         then
121                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/obsolete_ports"
122                 if [ -n "$recursedb_in" ]
123                 then
124                         message_echo "${DEPTH_INDEX}  ===> Disappeared port (MOVED broken?)"
125                 else
126                         message_echo "${DEPTH_INDEX}  ===> Nonexistent port (your original?)"
127                 fi
128                 return 1
129         else
130                 iline_db=`cut -d : -f 1 "${TMPDIR}/moved.info"`
131                 sed 1,${iline_db}d "${PORTS_MOVED_DB}" > ${TMPDIR}/MOVED.DB
132                 origin_new=`sed -E 's/^[0-9]+://' "${TMPDIR}/moved.info" | cut -d '|' -f 2 || :`
133                 date_moved=`cut -d '|' -f 3 "${TMPDIR}/moved.info" || :`
134                 why_moved=`cut -d '|' -f 4 "${TMPDIR}/moved.info" || :`
135                 if [ -n "$origin_new" ]
136                 then
137                         message_echo "${DEPTH_INDEX}  ===> Moved to $origin_new at $date_moved because \"$why_moved\""
138                         database_build_convert_and_register_origin_if_obsolete "$origin_new" "${TMPDIR}/MOVED.DB" || return 1
139                 else
140                         message_echo "${DEPTH_INDEX}  ===> Deleted at $date_moved because \"$why_moved\""
141                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/obsolete_ports"
142                         return 1
143                 fi
144         fi
145 }
146 # ============= [Sub-function] Get the output value of converted origin =============
147 _database_build_convert_and_register_origin_if_obsolete__get_origin ()
148 {
149         cat "${TMPDIR}/database_build_convert_and_register_origin_if_obsolete:origin"
150 }
151
152 # ============= Get the make arguments for building the temporary database =============
153 database_build_setup_make_args ()
154 {
155         local origin
156         origin=$1
157         {
158                 for key in LOCALBASE LINUXBASE PORT_DBDIR PORTSDIR DISTDIR PACKAGES PKGREPOSITORY
159                 do
160                         eval echo $key=\$$key
161                 done
162                 echo 'FORCE_PKG_REGISTER=yes'
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                 done > $dbpath/requirements.all.full
219                 pkg_info_qR "$pkg" | while read dependent
220                 do
221                         origin_dependent=`pkgsys_init_pkg_orig_by_ambiguous_matching "$dependent" || :`
222                         [ -n "$origin_dependent" ] && echo "$origin_dependent"
223                 done > $dbpath/dependents.all.full
224                 for table in dependents requirements
225                 do
226                         for level in direct full
227                         do
228                                 for tag in all run build
229                                 do
230                                         [ "${tag}.${level}" = all.full ] && continue
231                                         ln -f "$dbpath/${table}.all.full" "$dbpath/${table}.${tag}.${level}"
232                                 done
233                         done
234                 done
235         fi
236         if [ `expr "$pkg" : "^${APPNAME}-[0-9].*"` -gt 0 ]
237         then
238                 [ -d "$dbpath" ] && touch "$dbpath/SUPPRESSED_SELF"
239         elif [ `expr "$pkg" : "^pkg-[0-9].*"` -gt 0 ]
240         then
241                 [ -d "$dbpath" ] && touch "$dbpath/SUPPRESSED_PKGNG"
242         fi
243         touch "$dbpath/complete_as_node"
244 }
245
246 # ============= Set up a temporary database node for the replaced/moved information of a port =============
247 database_build_setup_replace_node ()
248 {
249         local origin_orig origin dbpath
250         origin_orig=$1
251         dbpath=${DBDIR}/replace/$origin_orig
252         if [ ! -e "$dbpath/complete_as_node" ]
253         then
254                 rm -rf "$dbpath"
255                 mkdir -p "$dbpath"
256                 origin=$origin_orig
257                 if echo "$origin_orig" | grep -q -E -f "${DBDIR}/conf/REPLACE.grep_from_pattern"
258                 then
259                         origin=`echo "$origin_orig" | sed -E -f "${DBDIR}/conf/REPLACE.sed_pattern"`
260                         if [ "x$origin_orig" != "x$origin" ]
261                         then
262                                 if [ -n "$origin" ]
263                                 then
264                                         message_echo "${DEPTH_INDEX}  ===> Replaced with $origin by user configuration"
265                                 else
266                                         database_build_register_obsolete_port "$origin_orig"
267                                         message_echo "${DEPTH_INDEX}  ===> Deleted by user configuration"
268                                 fi > $dbpath/message
269                         fi
270                 fi
271                 if [ -n "$origin" ]
272                 then
273                         if database_build_convert_and_register_origin_if_obsolete "$origin" >> $dbpath/message
274                         then
275                                 origin=`_database_build_convert_and_register_origin_if_obsolete__get_origin`
276                         else
277                                 if [ "x$origin" != "x$origin_orig" ]
278                                 then
279                                         message_echo "${DEPTH_INDEX}  ===> Going back to the original port $origin_orig"
280                                         if database_build_convert_and_register_origin_if_obsolete "$origin_orig"
281                                         then
282                                                 origin=`_database_build_convert_and_register_origin_if_obsolete__get_origin`
283                                         else
284                                                 origin=
285                                         fi
286                                 else
287                                         origin=
288                                 fi >> $dbpath/message
289                         fi
290                 fi
291                 [ "x$origin_orig" = "x$origin" ] || echo "$origin" > $dbpath/origin
292                 touch "$dbpath/complete_as_node"
293         fi
294         cat "$dbpath/message" 2> /dev/null || :
295 }
296
297 # ============= Get the inspected level for a port with the current option settings =============
298 database_build_get_inspected_level ()
299 {
300         local origin origin_dependent origin_esc origin_dependent_esc
301         origin=$1
302         origin_dependent=$2
303         origin_esc='^'`str_escape_regexp "$origin"`'$'
304         origin_dependent_esc='^'`str_escape_regexp "$origin_dependent"`'$'
305         if [ $opt_only_target_scope = no ]
306         then
307                 echo full
308         elif ! pkgsys_pkg_info_eO "$origin" \
309                 || grep -E "$origin_esc" "${DBDIR}/stage.loop_list/ports_to_inspect" > /dev/null \
310                 || [ ! -e "${DBDIR}/requires/$origin_dependent/installed_version" ] \
311                 || grep -E "$origin_dependent_esc" "${DBDIR}/stage.loop_list/ports_to_inspect" > /dev/null
312         then
313                 echo direct
314         else
315                 echo node
316         fi
317 }
318
319 # ============= Check whether a port has been inspected in a required level =============
320 database_build_is_port_already_inspected_in_required_level ()
321 {
322         local origin origin_dependent origin_actual origin_esc inspected_level
323         origin=$1
324         origin_dependent=$2
325         origin_actual=`echo "$origin" | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" 2> /dev/null || :`
326         [ -n "$origin_actual" ] || origin_actual=$origin
327         origin_esc='^'`str_escape_regexp "$origin_actual"`'$'
328         inspected_level=`database_build_get_inspected_level "$origin_actual" "$origin_dependent"`
329         grep -q -E "^$origin_esc$" "${DBDIR}/ports.inspected.${inspected_level}.list" \
330                 "${DBDIR}/obsolete_ports" 2> /dev/null || return
331         fileedit_rm_a_line "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
332         [ "x$origin" = "$origin_actual" ] || \
333                 fileedit_rm_a_line "$origin_actual" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
334         :
335 }
336
337 # ============= Update the current package name of a port =============
338 database_build_update_pkgname ()
339 {
340         local origin pkg savefile
341         origin=$1
342         savefile=${DBDIR}/requires/$origin/current_version
343         pkg=`pkg_info_qO "$origin" || :`
344         if [ -z "$pkg" -a -e "${DBDIR}/requires/$origin/initial_orig" ]
345         then
346                 origin_orig=`cat "${DBDIR}/requires/$origin/initial_orig"`
347                 pkg=`pkg_info_qO "$origin_orig" || :`
348         fi
349         echo -n "$pkg" > $savefile
350         cat "$savefile"
351 }
352
353 # ============= Get the current package name of a port =============
354 database_build_get_pkgname ()
355 {
356         local origin savefile
357         origin=$1
358         savefile=${DBDIR}/requires/$origin/current_version
359         if [ -e "$savefile" ]
360         then
361                 cat "$savefile"
362         else
363                 database_build_update_pkgname "$origin"
364         fi
365 }
366
367 # ============= Get the new package name of a port =============
368 database_build_get_new_pkgname ()
369 {
370         local origin savefile pkg
371         origin=$1
372         savefile=${DBDIR}/requires/$origin/new_version
373         if [ ! -e "$savefile" ]
374         then
375                 database_build_make "$origin" package-name \
376                         | tr -d '\n' > $savefile
377         fi
378         cat "$savefile"
379 }
380
381 # ============= Build the original message tag showing the version upgrade =============
382 database_build_create_pkgtag ()
383 {
384         local origin dbdir pkg_init pkg_new pkgtag
385         origin=$1
386         dbdir=${DBDIR}/requires/$origin
387         pkg_init=`database_build_get_pkgname "$origin"`
388         [ -n "$pkg_init" -a ! -e "$dbdir/installed_version" ] && \
389                 echo -n "$pkg_init" > $dbdir/installed_version
390         pkg_new=`database_build_get_new_pkgname "$origin"`
391         pkgtag=$pkg_init
392         [ -n "$pkgtag" ] || pkgtag=$pkg_new
393         if [ -z "$pkgtag" ]
394         then
395                 pkgtag='?'
396         
397         elif [ "x$pkg_init" != "x$pkg_new" ]
398         then
399                 if [ -n "$pkg_init" ]
400                 then
401                         pkgtag="$pkg_init => $pkg_new"
402                 else
403                         pkgtag="[new] $pkg_new"
404                 fi
405         fi
406         echo "$pkgtag" > $dbdir/pkgtag.orig
407         echo "$pkgtag" > $dbdir/pkgtag
408 }
409
410 # ============= Update the message tag showing the version upgrade =============
411 database_build_update_pkgtag ()
412 {
413         local origin pkg_init pkg_bak pkg_cur detail pkgtag
414         origin=$1
415         pkg_init=`cat "${DBDIR}/requires/$origin/installed_version" 2> /dev/null | tr '\n' ' ' | sed 's/ *$//'`
416         pkg_bak=`cat "${DBDIR}/requires/$origin/backedup_version" 2> /dev/null | tr '\n' ' ' | sed 's/ *$//'`
417         pkg_cur=`database_build_get_pkgname "$origin" | tr '\n' ' ' | sed 's/ *$//'`
418         detail=
419         if [ "x$pkg_init" != "x$pkg_cur" ]
420         then
421                 if [ -n "$pkg_cur" ]
422                 then
423                         detail=" [currently installed version: $pkg_cur]"
424                 elif [ -n "$pkg_bak" ]
425                 then
426                         detail=" [currently deinstalled, previously installed version: $pkg_bak]"
427                 else
428                         detail=" [currently deinstalled]"
429                 fi
430         fi
431         pkgtag=`cat "${DBDIR}/requires/$origin/pkgtag.orig"`
432         echo "$pkgtag$detail" > ${DBDIR}/requires/$origin/pkgtag
433 }
434
435 # ============= Check whether the currently installed package version is the latest =============
436 database_build_is_currentpkg_latest ()
437 {
438         local origin pkg_cur pkg_new
439         origin=$1
440         pkg_cur=`database_build_get_pkgname "$origin"`
441         pkg_new=`database_build_get_new_pkgname "$origin"`
442         [ "x$pkg_cur" = "x$pkg_new" ]
443 }
444
445 # ============= Recursively inspect dependencies of a port and build a node database of the information =============
446 database_build_inspect_dependencies ()
447 {
448         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
449         origin_orig=$1
450         origin_dependent=$2
451         [ -z "$origin_orig" ] && return
452         database_build_is_port_already_inspected_in_required_level "$origin_orig" "$origin_dependent" && return
453         origin_orig_regexp=`str_escape_regexp "$origin_orig"`
454         DEPTH_INDEX_orig=${DEPTH_INDEX}
455         DEPTH_INDEX="${DEPTH_INDEX}--"
456         message_echo "${DEPTH_INDEX} $origin_orig"
457         origin_id=`echo "$origin_orig" | tr / :`
458         database_build_setup_initial_node "$origin_orig"
459         database_build_setup_replace_node "$origin_orig"
460         if [ -e "${DBDIR}/replace/$origin_orig/origin" ]
461         then
462                 origin=`cat "${DBDIR}/replace/$origin_orig/origin"`
463         else
464                 origin=$origin_orig
465         fi
466         origin_regexp=`str_escape_regexp "$origin"`
467         inspected_level=
468         inspected_levels_compatible=
469         if [ -n "$origin" ]
470         then
471                 fileedit_rm_a_line "$origin" "${DBDIR}/obsolete_ports"
472                 dbpath=${DBDIR}/requires/$origin
473                 if [ ! -e "$dbpath/complete_as_node" ]
474                 then
475                         conf_updated=
476                         if grep -q -E -e "^$origin_orig_regexp$" -e "^$origin_regexp$" "${DBDIR}/to_be_reconf" 2> /dev/null
477                         then
478                                 message_echo "${DEPTH_INDEX}  ===> Reconfigured"
479                                 conf_updated=y
480                         fi
481                         rm -rf "$dbpath"
482                         mkdir -p "$dbpath"
483                         [ -n "$conf_updated" ] && touch "$dbpath/conf_updated"
484                         [ "x$origin_orig" = "x$origin" ] || echo "$origin_orig" > $dbpath/initial_orig
485                         [ -e "${DBDIR}/initial/$origin_orig/SUPPRESSED_SELF" ] && touch "$dbpath/SUPPRESSED_SELF"
486                         [ -e "${DBDIR}/initial/$origin_orig/SUPPRESSED_PKGNG" ] && touch "$dbpath/SUPPRESSED_PKGNG"
487                         if [ -d "${DBDIR}/conf/each_port/$origin" ]
488                         then
489                                 cp -R "${DBDIR}/conf/each_port/$origin/"* "$dbpath/" > /dev/null 2>&1 || :
490                         fi
491                         tmp_portsdb_work=${TMPDIR}/database_build_inspect_dependencies:portsdb_work
492                         [ -d "$tmp_portsdb_work" ] || mkdir "$tmp_portsdb_work"
493                         ( set -e
494                                 export PORT_DBDIR=$tmp_portsdb_work
495                                 database_build_make "$origin" showconfig > $dbpath/ports_options.default
496                         )
497                         if [ `wc -c < $dbpath/ports_options.default` -gt 0 ]
498                         then
499                                 if [ $opt_apply_default_config = yes ]
500                                 then
501                                         if ! pkgsys_is_dialog4ports_used
502                                         then
503                                                 printf '\t\n' | database_build_make "$origin" config-conditional > /dev/null
504                                         fi
505                                 else
506                                         database_build_make "$origin" config-conditional
507                                 fi
508                                 database_build_make "$origin" showconfig > $dbpath/ports_options.current
509                         else
510                                 cp /dev/null "$dbpath/ports_options.current"
511                         fi
512                         if [ ! -e "${DBDIR}/initial/$origin_orig/installed_version" ]
513                         then
514                                 cp "${DBDIR}/initial/$origin_orig/installed_version" "$dbpath" 2> /dev/null || :
515                         fi
516                         database_build_create_pkgtag "$origin"
517                         for tag in run build
518                         do
519                                 database_build_make "$origin" $tag-depends-list \
520                                         | sed -E "s/^`str_escape_regexp "${PORTSDIR}"`\///" \
521                                         > $dbpath/requirements.$tag.orig || :
522                                 sed -E -f "${DBDIR}/conf/REPLACE.sed_pattern" "$dbpath/requirements.$tag.orig" \
523                                         | grep -v '^$' > $dbpath/requirements.$tag.src || :
524                         done
525                         for stage in orig src
526                         do
527                                 sort -u "$dbpath/requirements.run.${stage}" "$dbpath/requirements.build.${stage}" \
528                                         > $dbpath/requirements.all.direct.${stage}
529                                 mv "$dbpath/requirements.build.${stage}" "$dbpath/requirements.build.direct.${stage}"
530                                 mv "$dbpath/requirements.run.${stage}" "$dbpath/requirements.run.direct.${stage}"
531                         done
532                         touch "$dbpath/complete_as_node"
533                         fileedit_rm_a_line "$origin_orig" "${DBDIR}/to_be_reconf"
534                         fileedit_rm_a_line "$origin" "${DBDIR}/to_be_reconf"
535                 else
536                         for level in direct full
537                         do
538                                 for tag in run build
539                                 do
540                                         rm -f "$dbpath/requirements.${tag}.${level}"
541                                 done
542                         done
543                         for origin_tmp in "$origin" "$origin_orig"
544                         do
545                                 for inspected_level_tmp in full direct node
546                                 do
547                                         fileedit_rm_a_line "$origin_tmp" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
548                                 done
549                         done
550                 fi
551                 inspected_level=`database_build_get_inspected_level "$origin" "$origin_dependent"`
552                 case $inspected_level in
553                 full)
554                         grep -v -E -f "${DBDIR}/installed_ports.grep_pattern" \
555                                 "$dbpath/requirements.all.direct.src" > ${TMPDIR}/missing.$origin_id || :
556                         inspected_levels_compatible='full direct node'
557                         ;;
558                 direct)
559                         grep -v -E -f "${DBDIR}/installed_ports.grep_pattern" \
560                                 "$dbpath/requirements.all.direct.src" > ${TMPDIR}/missing.$origin_id || :
561                         inspected_levels_compatible='direct node'
562                         ;;
563                 node)
564                         cp /dev/null "${TMPDIR}/missing.$origin_id"
565                         inspected_levels_compatible='node'
566                         ;;
567                 esac
568                 nlines=`wc -l < ${TMPDIR}/missing.$origin_id`
569                 iline=1
570                 while [ $iline -le $nlines ]
571                 do
572                         origin_dependency=`sed -n ${iline}p "${TMPDIR}/missing.$origin_id"`
573                         iline=$(($iline+1))
574                         grep -q -E '^'`str_escape_regexp "$origin_dependency"`'$' \
575                                 "${DBDIR}/ports.inspected.list" 2> /dev/null && \
576                                         continue
577                         database_build_inspect_dependencies "$origin_dependency" "$origin"
578                 done
579                 rm -f "${TMPDIR}/missing.$origin_id"
580                 dist_subdir_rpl=`database_query_get_makevar_val "$origin" DIST_SUBDIR | str_escape_replaceval_filter` || :
581                 [ -n "$dist_subdir_rpl" ] && dist_subdir_rpl="$dist_subdir_rpl\/"
582                 database_build_make "$origin" fetch-urlall-list \
583                         | sed -E "s/.*\/([^\/]+)$/$dist_subdir_rpl\1/" \
584                         | sort -u >> ${DBDIR}/distfiles.inspected
585         fi
586         if [ "x$origin_orig" != "x$origin" ]
587         then
588                 if [ -n "$origin" ]
589                 then
590                         for inspected_level_tmp in $inspected_levels_compatible
591                         do
592                                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
593                         done
594                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/ports.inspected.list"
595                         fileedit_add_a_line_if_new "$origin" "${DBDIR}/inspected_ports.update"
596                         fileedit_rm_a_line "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
597                 fi
598         fi
599         for inspected_level_tmp in $inspected_levels_compatible
600         do
601                 fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/ports.inspected.${inspected_level_tmp}.list"
602         done
603         fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/ports.inspected.list"
604         fileedit_add_a_line_if_new "$origin_orig" "${DBDIR}/inspected_ports.update"
605         fileedit_rm_a_line "$origin_orig" "${DBDIR}/stage.loop_list/ports_to_inspect.remain"
606         message_echo "${DEPTH_INDEX}  ===> ok"
607
608         DEPTH_INDEX=${DEPTH_INDEX_orig}
609 }
610
611 # ============= Build and get a list of the complete recursive dependencies of a port =============
612 database_build_get_complete_recursive_dependency ()
613 {
614         local table origin dbpath dstfile
615         table=$1
616         origin=$2
617         dbpath=${DBDIR}/requires/$origin
618         [ -e "$dbpath/$table.direct" ] || return 0
619         dstfile=$dbpath/$table.full
620         if [ ! -e "$dbpath/$table" -a ! -e "$dstfile" ]
621         then
622                 while read origin_requirement
623                 do
624                         echo "$origin_requirement"
625                         database_build_get_complete_recursive_dependency "$table" "$origin_requirement"
626                 done < $dbpath/$table.direct | sort -u > $dstfile.tmp
627                 mv "$dstfile.tmp" "$dstfile"
628         fi
629         cat "$dstfile"
630 }
631
632 # ============= Inspect the necessity of requirements of a necessary port even in case of skipping unchanged ports =============
633 # Here the "necessity" means that a port must be kept installed, newly installed or reinstalled for run- or build-time operations.
634 # In other words, "unnecessary" ports are what are not yet installed and not required by any "necessary" ports neither in run- or build-time.
635 database_build_inspect_necessity_for_only_new_upgrade ()
636 {
637         local origin level dbpath tmpfile
638         origin=$1
639         level=$2
640         dbpath=${DBDIR}/requires/$origin
641         [ -e "$dbpath/necessary_port.${level}" ] && return
642         tmpfile=${TMPDIR}/database_build_inspect_necessity_for_only_new_upgrade:`echo "$origin" | tr / :`
643         if database_query_does_a_port_need_update "$origin"
644         then
645                 sort -u "$dbpath/requirements.build.direct" "$dbpath/requirements.run.${level}" || :
646         else
647                 cat "$dbpath/requirements.run.${level}" || :
648         fi 2> /dev/null > $tmpfile
649         if [ `wc -l < $tmpfile` -gt 0 ]
650         then
651                 while read origin_requirement
652                 do
653                         database_build_inspect_necessity_for_only_new_upgrade "$origin_requirement" "$level"
654                 done < $tmpfile
655         fi
656         rm "$tmpfile"
657         touch "$dbpath/necessary_port.${level}"
658 }
659
660 # ============= Build complement relations to new dependents for targets recursively =============
661 database_build_complement_to_new_dependents_for_targets ()
662 {
663         local origin dbdir reqdir level
664         origin=$1
665         dbdir=${DBDIR}/targets/$origin
666         reqdir=${DBDIR}/requires/$origin
667         [ -d "$dbdir" ] || return 0
668         echo "$origin" >> ${DBDIR}/stage.loop_list/parse_target_attr_info
669         if [ -e "$dbdir/target_itself" ] && database_query_does_a_port_need_update "$origin"
670         then
671                 for level in direct full
672                 do
673                         cat "$reqdir/requirements.all.${level}" 2> /dev/null | while read origin_requirement
674                         do
675                                 fileedit_add_a_line_if_new "$origin" \
676                                         "${DBDIR}/targets/$origin_requirement/complement_for_new_dependents.${level}"
677                         done
678                 done
679                 cat "$reqdir/requirements.all.direct" "$reqdir/requirements.all.full" 2> /dev/null \
680                         | sort -u | while read origin_requirement
681                 do
682                         database_build_complement_to_new_dependents_for_targets "$origin_requirement"
683                 done
684         fi
685 }
686
687 # ============= Build target attribute files recursively =============
688 database_build_target_attributes ()
689 {
690         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
691         origin=$1
692         dbdir=${DBDIR}/targets/$origin
693         reqdir=${DBDIR}/requires/$origin
694         [ -d "$dbdir" ] || return 0
695         [ -e "$dbdir/COMPLETE_ATTRS" ] && return
696         _is_target=
697         [ -e "$dbdir/target_itself" ] && _is_target=y
698         for tag in all run build none
699         do
700                 for level in direct full
701                 do
702                         _is_relevant=${_is_target}
703                         _is_requires_requirements=
704                         _is_initial_requirements=
705                         _is_requires_dependents=
706                         _is_initial_dependents=
707                         _is_requires_requirements_complement=
708                         for database in requires initial
709                         do
710                                 for table in requirements dependents
711                                 do
712                                         if [ -e "$dbdir/target_${database}_${table}.${tag}.${level}" ]
713                                         then
714                                                 eval _is_${database}_${table}=y
715                                                 _is_relevant=y
716                                         fi
717                                 done
718                         done
719                         if [ -z "${_is_requires_requirements}" -a -e "$dbdir/complement_for_new_dependents.${level}" ]
720                         then
721                                 _is_requires_requirements_complement=y
722                                 _is_relevant=y
723                         fi
724                         [ -n "${_is_relevant}" ] && cat > $dbdir/attrs.${tag}.${level} << eof
725 _is_target=${_is_target}
726 _is_requires_requirements=${_is_requires_requirements}
727 _is_initial_requirements=${_is_initial_requirements}
728 _is_requires_dependents=${_is_requires_dependents}
729 _is_initial_dependents=${_is_initial_dependents}
730 _is_requires_requirements_complement=${_is_requires_requirements_complement}
731 eof
732                 done
733         done
734         touch "$dbdir/COMPLETE_ATTRS"
735 }
736
737 # ============= Order the ports considering dependencies =============
738 database_build_order_ports_considering_dependencies ()
739 {
740         touch "${DBDIR}/reinst_order.list.tmp"
741         cat > ${TMPDIR}/order_dependencies.awk << eof
742 BEGIN {
743         it = 0;
744         i = 0;
745 }
746 {
747         if (NF == 0)
748         {
749                 i = 0;
750         }
751         else
752         {
753                 if (i == 0)
754                 {
755                         target = \$0;
756                         sub (/\/requirements.all\.full$/, "", target);
757                         sub (/^\.\//, "", target);
758                         srcikey[it] = target;
759                         srckeyi[target] = it;
760                         it++;
761                 }
762                 else
763                 {
764                         src[it-1,i-1] = \$0;
765                         srcimax[it-1] = srcsize[it-1] = i;
766                 }
767                 i++;
768         }
769 }
770 END {
771         ntargets = it;
772         norder = 0;
773         order_str = "";
774         icycle = 0;
775         lf_order_str = "";
776         while (1)
777         {
778                 is_operated = 0;
779                 for (it = 0; it < ntargets; it++)
780                 {
781                         if (!(it in srcikey)) continue;
782                         if (srcsize[it] > 0) continue;
783                         is_operated = 1;
784                         target = srcikey[it];
785                         delete srcikey[it];
786                         order[norder++] = target;
787                         order_str = order_str lf_order_str;
788                         order_str = sprintf ("%s%s", order_str, target);
789                         lf_order_str = "\n";
790                         for (jt = 0; jt < ntargets; jt++)
791                         {
792                                 for (j = 0; j < srcimax[jt]; j++)
793                                 {
794                                         if ((jt,j) in src && src[jt,j] == target)
795                                         {
796                                                 delete src[jt,j];
797                                                 srcsize[jt]--;
798                                                 break;
799                                         }
800                                 }
801                         }
802                 }
803                 if (is_operated == 0) break;
804                 icycle++;
805         }
806         reinst_order_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/reinst_order.list.tmp");
807         print order_str > reinst_order_list;
808         unsatisfied = "";
809         for (it = 0; it < ntargets; it++)
810         {
811                 if (srcsize[it] == 0) continue;
812                 reqs = "";
813                 sp_reqs = "";
814                 for (i = 0; i < srcimax[it]; i++)
815                 {
816                         if ((it,i) in src)
817                         {
818                                 reqs = reqs sp_reqs src[it,i];
819                                 sp_reqs = ", ";
820                         }
821                 }
822                 unsatisfied = sprintf ("%s%s [%d] (%s)\n", unsatisfied, srcikey[it], srcsize[it], reqs);
823         }
824         if (unsatisfied != "")
825         {
826                 unsatisfied_list = sprintf ("%s%s", ENVIRON["DBDIR"], "/unsatisfied.list");
827                 print unsatisfied > unsatisfied_list;
828                 exit 1;
829         }
830 }
831 eof
832         (cd "${DBDIR}/requires" && \
833                 find . -depth 3 -name requirements.all.full -exec echo {} \; -exec cat {} \; -exec echo \;) | \
834                 env "DBDIR=${DBDIR}" awk -f "${TMPDIR}"/order_dependencies.awk || return
835         grep -v '^$' "${DBDIR}/reinst_order.list.tmp" > "${DBDIR}/reinst_order.list" || :
836 }
837
838 # ============= [Sub-function] Common operations for resetting configurations for a port =============
839 _database_build_reset_a_port_confdb ()
840 {
841         local origin origin_replace db
842         origin=$1
843         [ -d "${DBDIR}/initial/$origin" -o -d "${DBDIR}/replace/$origin" \
844                 -o -d "${DBDIR}/requires/$origin" -o -d "${DBDIR}/targets/$origin" ] || return 0
845         touch "${DBDIR}/inspected_ports_only_partially"
846         {
847                 echo "$origin"
848                 cat "${DBDIR}/replace/$origin/origin" 2> /dev/null || :
849                 for dbtag in initial requires
850                 do
851                         for tabel in requirements dependents
852                         do
853                                 cat "${DBDIR}/$dbtag/$origin/$tabel.all.full" 2> /dev/null || :
854                                 rm -f "${DBDIR}/$dbtag/$origin/$tabel.run.full" \
855                                         "${DBDIR}/$dbtag/$origin/$tabel.build.full" 2> /dev/null
856                         done
857                 done
858         } | sort -u >> ${DBDIR}/inspected_ports.update
859         for level in full direct node
860         do
861                 fileedit_rm_a_line "$origin" "${DBDIR}/ports.inspected.${level}.list"
862         done
863         fileedit_rm_a_line "$origin" "${DBDIR}/obsolete_ports"
864         fileedit_rm_a_line "$origin" "${DBDIR}/ports.inspected.list"
865         cat "${DBDIR}/replace/$origin/origin" 2> /dev/null || :
866 }
867
868 # ============= Remove configurations for a port permanently =============
869 database_build_forget ()
870 {
871         local origin origin_replace db
872         origin=$1
873         origin_replace=`_database_build_reset_a_port_confdb "$origin"`
874         fileedit_rm_a_line "$origin" "${DBDIR}/targets_specified_so_far"
875         [ -z "$origin_replace" ] || database_build_forget "$origin_replace"
876         for db in requires replace targets obsolete
877         do
878                 rm -rf "${DBDIR}/$db/$origin"
879         done
880 }
881
882 # ============= Patch to the temporary database so as to re-inspect and reinstall ports whose configurations were changed =============
883 database_build_patch_reconf ()
884 {
885         local origin origin_replace
886         origin=$1
887         origin_replace=`_database_build_reset_a_port_confdb "$origin"`
888         [ -d "${DBDIR}/initial/$origin" -o -d "${DBDIR}/requires/$origin" ] && \
889                 fileedit_add_a_line_if_new "$origin" "${DBDIR}/stage.loop_list/ports_to_inspect"
890         fileedit_add_a_line_if_new "$origin" "${DBDIR}/to_be_reconf"
891         [ -z "$origin_replace" ] || database_build_patch_reconf "$origin_replace"
892         for db in requires replace targets obsolete
893         do
894                 rm -rf "${DBDIR}/$db/$origin"
895         done
896 }
897
898 # ============= Post`processes after finishing to inspect dependencies =============
899 database_build_post_inspect_dependencies ()
900 {
901         local table
902         touch "${DBDIR}/obsolete_ports" "${DBDIR}/inspected_ports.update"
903         find "${DBDIR}/requires" -depth 2 -type d \
904                 | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/inspected_ports
905         find "${DBDIR}/initial" -depth 2 -type d \
906                 | sed -E 's|.*/([^/]+/[^/]+)$|\1|' > ${DBDIR}/inspected_ports.initial
907         sort -u "${DBDIR}/inspected_ports" "${DBDIR}/inspected_ports.initial" > ${DBDIR}/inspected_ports.all
908         str_escape_regexp_filter < ${DBDIR}/inspected_ports \
909                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.grep_pattern
910         str_escape_regexp_filter < ${DBDIR}/inspected_ports.initial \
911                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.initial.grep_pattern
912         str_escape_regexp_filter < ${DBDIR}/inspected_ports.all \
913                 | sed 's/^/^/; s/$/$/' > ${DBDIR}/inspected_ports.all.grep_pattern
914         cat "${DBDIR}/conf/HOLD_PORTS.grep_pattern" "${DBDIR}/need.grep_pattern" \
915                 2> /dev/null > ${TMPDIR}/INSPECT_ALL_DEPENDENCIES:obsolete_ports.exclude.grep_pattern || :
916         grep -v -E -f "${TMPDIR}/INSPECT_ALL_DEPENDENCIES:obsolete_ports.exclude.grep_pattern" \
917                 "${DBDIR}/obsolete_ports" > ${DBDIR}/obsolete_ports.can_be_deleted || :
918         cp /dev/null "${DBDIR}/REPLACE.complete_sed_pattern.tmp"
919         cp /dev/null "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp"
920         find "${DBDIR}/replace" -depth 3 -type f -name origin | while read nodepath
921         do
922                 origin_orig=`expr "$nodepath" : '.*/\([^/][^/]*/[^/][^/]*\)/origin$'`
923                 origin=`cat "$nodepath"`
924                 origin_orig_regexp=`str_escape_regexp "$origin_orig"`
925                 origin_orig_esc=`str_escape_replaceval "$origin_orig"`
926                 origin_regexp=`str_escape_regexp "$origin"`
927                 origin_esc=`str_escape_replaceval "$origin"`
928                 echo "s/^$origin_orig_regexp$/$origin_esc/" >> ${DBDIR}/REPLACE.complete_sed_pattern.tmp
929                 echo "s/^$origin_regexp$/$origin_orig_esc/" >> ${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp
930         done
931         mv "${DBDIR}/REPLACE.complete_sed_pattern.tmp" "${DBDIR}/REPLACE.complete_sed_pattern"
932         mv "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern.tmp" "${DBDIR}/REVERSE_REPLACE.complete_sed_pattern"
933         if [ `cat "${DBDIR}/inspected_ports.update" 2> /dev/null | wc -l` -gt 0 ]
934         then
935                 grep -E -f "${DBDIR}/inspected_ports.all.grep_pattern" "${DBDIR}/inspected_ports.update" \
936                         > ${DBDIR}/inspected_ports.update.tmp || :
937                 mv "${DBDIR}/inspected_ports.update.tmp" "${DBDIR}/inspected_ports.update"
938                 if [ $opt_only_target_scope = yes ]
939                 then
940                         touch "${DBDIR}/inspected_ports_only_partially"
941                 else
942                         rm -f "${DBDIR}/inspected_ports_only_partially"
943                 fi
944                 if program_chk_stage_loop_complete CONVERT_REQUIREMENTS_LIST
945                 then
946                         mv "${DBDIR}/inspected_ports.update" "${DBDIR}/stage.loop_list/convert_dependency_lists"
947                 else
948                         cat "${DBDIR}/inspected_ports.update" "${DBDIR}/stage.loop_list/convert_dependency_lists" \
949                                 2> /dev/null | sort -u > ${DBDIR}/stage.loop_list/convert_dependency_lists.tmp
950                         mv "${DBDIR}/stage.loop_list/convert_dependency_lists.tmp" \
951                                 "${DBDIR}/stage.loop_list/convert_dependency_lists"
952                         rm -f "${DBDIR}/inspected_ports.update"
953                 fi
954         else
955                 program_chk_stage_loop_complete CONVERT_REQUIREMENTS_LIST \
956                         && rm -f "${DBDIR}/stage.loop_list/convert_dependency_lists"
957         fi
958         {
959                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" "${DBDIR}/need.list" || :
960                 cat "${DBDIR}/need.list" || :
961         } 2> /dev/null | sort -u > ${DBDIR}/need.with_replaced.list
962         for table in requirements dependents itself
963         do
964                 [ -e "${DBDIR}/stage.loop_list/target_$table.specified" ] || continue
965                 sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern" \
966                         "${DBDIR}/stage.loop_list/target_$table.specified" \
967                         > ${DBDIR}/stage.loop_list/target_$table.replaced.specified
968         done    
969         cp /dev/null "${DBDIR}/update_dependencies"
970 }