OSDN Git Service

[NEW] show heritage command is added. The database records ports which have not eithe...
[portsreinstall/current.git] / lib / libcommand_pkgs.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Commands of ports/packages operations -
5 # Copyright (C) 2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Operation of reconf/rmconf command =============
10 command_pkgs_port_option_conf ()
11 {
12         local make_target origin
13         case $COMMAND_MODE in
14         reconf )
15                 message_echo "Reconfigure the specified port options."
16                 make_target=config
17                 ;;
18         rmconf )
19                 message_echo "The specified port options are reset to the default."
20                 make_target=rmconfig
21                 ;;
22         esac
23         message_echo "Affected parts of the temporary database are reset automatically."
24         for origin in `pkgsys_eval_ports_glob "$@"`
25         do
26                 message_echo "Re-configure $origin:"
27                 database_build_make "$origin" $make_target
28                 database_build_patch_reconf "$origin"
29         done
30         program_deregister_stage_complete PREPARE_FOR_INSPECT_ALL_DEPENDENCIES
31         program_deregister_stage_complete ALL_COMPLETE
32 }
33
34 # ============= Operation of escape command =============
35 command_pkgs_escape ()
36 {
37         local origin pkg backup_pkg
38         message_echo "Backing up and deleting the following packages for a temporary escape:"
39         message_echo
40         for origin in `pkgsys_eval_ports_glob "$@"`
41         do
42                 pkgsys_register_evaluated_globs add "${DBDIR}/taboo.list" "$origin"
43                 message_echo "  Registered $origin as taboo."
44                 pkg=`pkgsys_get_installed_pkg_from_origin "$origin"`
45                 [ -n "$pkg" ] || continue
46                 if backup_pkg=`pkgsys_get_backup_pkg "$origin"`
47                 then
48                         message_echo "INFO: A backup package for $pkg ($origin) already exists as $backup_pkg."
49                 elif backup_pkg=`pkgsys_create_backup_pkg "$pkg" "${DBDIR}/backup_packages"`
50                 then
51                         message_echo "  Backed up $pkg ($origin) into $backup_pkg"
52                 else
53                         message_echo "ERROR: Failed to back up $pkg ($origin)." >&2
54                         message_echo >&2
55                         continue
56                 fi
57                 pkg_delete_f "$pkg" || \
58                 {
59                         message_echo "ERROR: Failed to deinstall $pkg ($origin)." >&2
60                         message_echo >&2
61                 }
62                 message_echo "  Deinstalled $pkg ($origin)."
63                 message_echo
64         done
65         fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" > ${DBDIR}/taboo.all.list
66 }
67
68 # ============= Operation of restore command =============
69 command_pkgs_restore ()
70 {
71         local tmp_done_orig origin pkg exists_old_origins origin_orig pkg_orig origin_replace pkg_replace backup_pkg
72         message_echo "Restoring the following temporary escaped packages:"
73         message_echo
74         tmp_done_orig=${TMPDIR}/command_pkgs_restore::restore::done_orig
75         cp /dev/null "$tmp_done_orig"
76         for origin in `pkgsys_eval_ports_glob "$@"`
77         do
78                 pkgsys_register_evaluated_globs remove "${DBDIR}/taboo.list" "$origin"
79                 message_echo "  Deregistered $origin from taboo."
80                 grep -Fx -q "$origin" "$tmp_done_orig" 2> /dev/null || :
81                 if pkgsys_exists_from_orig "$origin"
82                 then
83                         pkg=`pkgsys_get_installed_pkg_from_origin "$origin"`
84                         message_echo "WARNING: $pkg ($origin) is already installed." >&2
85                         message_echo >&2
86                         continue
87                 fi
88                 exists_old_origins=no
89                 for origin_orig in `database_query_initial_orgins "$origin"`
90                 do
91                         if [ "x$origin_orig" = "x$origin" ] && pkgsys_exists_from_orig "$origin_orig"
92                         then
93                                 pkg_orig=`pkgsys_get_installed_pkg_from_origin "$origin_orig"`
94                                 message_echo "WARNING: An original version of $origin ($pkg_orig, $origin_orig) is already installed." >&2
95                                 message_echo >&2
96                                 exists_old_origins=yes
97                         fi
98                 done
99                 [ $exists_old_origins = yes ] && continue
100                 origin_replace=`echo "$origin" \
101                         | sed -E -f "${DBDIR}/REPLACE.complete_sed_pattern"`
102                 if [ "x$origin_replace" != "x$origin" ]
103                 then
104                         if pkgsys_exists_from_orig "$origin_replace"
105                         then
106                                 pkg_replace=`pkgsys_get_installed_pkg_from_origin "$origin_replace"`
107                                 message_echo "WARNING: A replacement of $origin ($pkg_replace, $origin_replace) is already installed." >&2
108                                 message_echo >&2
109                                 continue
110                         fi
111                         if backup_pkg=`pkgsys_get_backup_pkg "$origin_replace" 2> /dev/null`
112                         then
113                                 message_echo "INFO: $origin is replaced with $origin_replace ($pkg_replace)."
114                                 echo "$origin_replace" >> $tmp_done_orig
115                                 origin=$origin_replace
116                         fi
117                 else
118                         backup_pkg=
119                 fi
120                 if [ -z "$backup_pkg" ] && ! backup_pkg=`pkgsys_get_backup_pkg "$origin" 2> /dev/null`
121                 then
122                         message_echo "ERROR: Backup for $origin is not found." >&2
123                         message_echo >&2
124                         continue
125                 fi
126                 pkg=`pkgsys_pkgarc_to_pkgname "$backup_pkg"`
127                 if reinstall_chk_forbidden_conflicts "$pkg"
128                 then
129                         message_echo "WARNING: $pkg ($origin) is skipped because it conflicts with installed packages." >&2
130                         message_echo >&2
131                         continue
132                 fi
133                 if ! pkg_add_fF "$backup_pkg"
134                 then
135                         message_echo "ERROR: Failed to restore $pkg ($origin)." >&2
136                         message_echo >&2
137                 fi
138                 message_echo "  Restored $pkg ($origin)."
139                 message_echo
140         done
141         fileedit_combine_lists "${DBDIR}/conf/TABOO:PORTS.parsed" "${DBDIR}/taboo.list" > ${DBDIR}/taboo.all.list
142 }
143
144 # ============= Operation of pkgsanity command =============
145 command_pkgs_pkgsanity ()
146 {
147         local tmp_list nlines iline pkg origin port_path is_reinstall_encouraged
148         tmp_list=${TMPDIR}/command_pkgs_pkgsanity:list
149         if [ $# -eq 0 ]
150         then
151                 message_echo "Sanity check of the installed files for each package:"
152                 message_echo
153                 pkg_info_Ea > $tmp_list.pkgs
154                 pkg_info_all_flavored_origins > $tmp_list.orgs
155         else
156                 message_echo "Examining the installed files for each specified package:"
157                 message_echo
158                 pkgsys_eval_ports_glob "$@" > $tmp_list.orgs
159                 while read origin
160                 do
161                         pkgsys_get_installed_pkg_from_origin "$origin"
162                 done < $tmp_list.orgs | grep -v '^[[:space:]]*$' > $tmp_list.pkgs || {
163                         message_echo "WARNING: No such globs match any installed package." >&2
164                         temp_terminate_process () { :; }
165                         exit 1
166                 }
167         fi
168         message_echo "<< Phase 1: Check and fix duplicated packages registrations for the same port origin >>"
169         message_echo
170         while read origin
171         do
172                 [ `pkgsys_get_installed_pkg_from_origin "$origin" | wc -l` -gt 1 ] || continue
173                 pkgsys_get_installed_pkg_from_origin "$origin" | while read pkg
174                 do
175                         echo "$((0+`pkg_check_sanity \"$pkg\" | wc -l`))" "$pkg"
176                 done | sort -g > $tmp_list.pkgs_for_an_org
177                 pkg_valid=`head -n 1 "$tmp_list.pkgs_for_an_org" | cut -d ' ' -f 2`
178                 message_echo "Port [$origin] has multiply registered packages."
179                 message_echo "The valid one will be [$pkg_valid]."
180                 message_echo "Invalid one(s) will be as follows and to be deleted:"
181                 sed 1d "$tmp_list.pkgs_for_an_org" | cut -d ' ' -f 2 > $tmp_list.pkgs_for_an_org_msg
182                 message_cat "$tmp_list.pkgs_for_an_org_msg"
183                 errout=/dev/stderr
184                 [ $opt_batch_mode = yes ] && errout=/dev/null
185                 if backup_pkg=`pkgsys_create_backup_pkg "$pkg_valid" "${DBDIR}/backup_packages"`
186                 message_echo
187                 then
188                         pkg_delete_f `cat "$tmp_list.pkgs_for_an_org"` 2> $errout || {
189                                 message_echo "WARNING: Deletion of the broken packages may not be fully successful, but continuing anyway." >&2
190                                 message_echo >&2
191                         }
192                         pkg_add_fF "$backup_pkg" || {
193                                 message_echo "WARNING: Reinstallation of the most valid package failed, but continuing anyway." >&2
194                                 message_echo >&2
195                         }
196                 else
197                         message_echo "WARNING: Backup of the most valid package failed, but continuing anyway." >&2
198                         pkg_delete_f `cat "$tmp_list.pkgs_for_an_org"` 2> $errout || {
199                                 message_echo "WARNING: Deletion of the broken packages may not be fully successful, but continuing anyway." >&2
200                                 message_echo >&2
201                         }
202                 fi
203         done < $tmp_list.orgs
204         
205         message_echo "<< Phase 2: Check and mark broken packages for reinstallation >>"
206         message_echo
207         nlines=`wc -l < $tmp_list.pkgs`
208         iline=1
209         while [ $iline -le $nlines ]
210         do
211                 pkg=`sed -n ${iline}p "$tmp_list.pkgs"`
212                 iline=$((${iline}+1))
213                 origin=`pkg_info_flavored_origin "$pkg"`
214                 [ -n "$origin" ] || continue
215                 grep -q -Fx "$origin" "${DBDIR}/damaged_package" 2>/dev/null && continue
216                 pkgsys_sanitychk_pkgcontents "$pkg" is_reinstall_encouraged && continue
217                 port_path=`pkgsys_get_portpath_from_origin "$origin"`
218                 if [ ! -d "$port_path" ]
219                 then
220                         message_echo "WARNING: $pkg ($origin) is obsolete." >&2
221                         message_echo >&2
222                         continue
223                 fi
224                 if [ $is_reinstall_encouraged = no ]
225                 then
226                         if [ $opt_batch_mode = no ]
227                         then
228                                 message_echo "Do you want to reinstall it? (y/[n])"
229                                 message_query_yn_default_no || continue
230                         fi
231                 else
232                         if [ $opt_batch_mode = no ]
233                         then
234                                 message_echo "Do you want to reinstall it? ([y]/n)"
235                                 message_query_yn_default_yes || continue
236                         fi
237                         database_record_reconf_recover_sanity "$origin"
238                 fi
239         done
240 }
241
242 # ============= Operation of packupgrade command =============
243 command_pkgs_packupgrade ()
244 {
245         case ${COMMAND_OPERATION} in
246         clean )
247                 command_pkgs_packupgrade_clean
248                 ;;
249         create )
250                 command_pkgs_packupgrade_create
251                 ;;
252         crop )
253                 command_pkgs_packupgrade_crop
254                 ;;
255         esac
256 }
257
258 # ============= Operation of packupgrade clean command =============
259 command_pkgs_packupgrade_clean ()
260 {
261         program_deregister_stage_complete COMMAND_PACKUPGRADE_PREPARE
262         rm -rf "${DBDIR}/command_packupgrade"
263 }
264
265 # ============= Stage of preparation in operation of packupgrade create command =============
266 command_pkgs_packupgrade_create__prepare ()
267 {
268         local PROGRAM_DEPENDS
269         PROGRAM_DEPENDS=
270         _program_exec_and_record_completion__operation ()
271         {
272                 local dstdir
273                 message_section_title "Preparation"
274                 mkdir -p "${PACKAGES}/${PKGREPOSITORYSUBDIR}"
275                 cp "${DBDIR}/reinst_order.list" "${DBDIR}/stage.loop_list/command_packupgrade_pack"
276                 dstdir=${DBDIR}/command_packupgrade
277                 rm -rf "$dstdir" "$dstdir.tar.gz"
278                 mkdir -p "$dstdir"
279                 install -d "$dstdir/etc"
280                 touch "$dstdir/etc/created_packages.lst"
281                 pkg_get_pkgs_timestamps > $dstdir/etc/final_pkgs_snapshot.csv
282                 message_echo
283         }
284         program_exec_and_record_completion COMMAND_PACKUPGRADE_PREPARE
285 }
286
287 # ============= Stage of creating the manifest of reinstallation in operation of packupgrade create command =============
288 command_pkgs_packupgrade_create__manifest_reinst ()
289 {
290         local PROGRAM_DEPENDS
291         PROGRAM_DEPENDS=COMMAND_PACKUPGRADE_PREPARE
292         _program_exec_restartable_loop_operation__routine ()
293         {
294                 local origin dstdir tmp_manifest dbdir_new pkgname pkgarc timestamp_inst timestamp_arc origin_old
295                 origin=$1
296                 dstdir=${DBDIR}/command_packupgrade
297                 tmp_manifest=${TMPDIR}/packupgrade::manifest
298                 rm -rf "$tmp_manifest"
299                 dbdir_new=${DBDIR}/requires/$origin
300                 pkgname=`pkgsys_get_installed_pkg_from_origin "$origin"`
301                 [ -n "$pkgname" ] || return 0
302                 if ! grep -Fxq "$pkgname" "$dstdir/etc/created_packages.lst" 2> /dev/null
303                 then
304                         if pkg_info_e "$pkgname"
305                         then
306                                 pkgarc=`pkgsys_pkgname_to_pkgarc "${PACKAGESDIR}" "$pkgname"`
307                                 timestamp_inst=`pkg_get_pkg_timestamp "$pkgname" 2> /dev/null` || :
308                                 timestamp_arc=`ls -lD %s "$pkgarc" 2> /dev/null | sed -E 's/[[:space:]]+/ /g' | cut -w -f 6 | grep -v '^$'` || :
309                                 if [ -z "$timestamp_inst" -o -z "$timestamp_arc" -o "$timestamp_arc" -lt "$timestamp_inst" ]
310                                 then
311                                         if ! ( cd ${PACKAGESDIR}; pkg_create_b "$pkgname" | message_cat )
312                                         then
313                                                 message_echo "ERROR: Failed to create package [$pkgname for $origin]." >&2
314                                                 exit 1
315                                         fi
316                                 fi
317                         elif grep -Fxq "$origin" ${DBDIR}/success.run.full.list
318                         then
319                                 message_echo "ERROR: Necessary package is missing [$origin]." >&2
320                                 exit 1
321                         fi
322                         fileedit_add_a_line_if_new "$pkgname" "$dstdir/etc/created_packages.lst"
323                 fi
324                 if pkgsys_is_necessary_pkgtool "$origin"
325                 then
326                         pkg_patterns=`pkgsys_get_conflicting_pkgs_patterns install "$origin" | tr '\n' '|'`
327                         printf '%s\t%s\t%s\n' addtool "$pkgname" "$origin|$pkg_patterns" >> $tmp_manifest
328                 else
329                         if [ -e "${DBDIR}/moved_from/$origin/initial_orig" ]
330                         then
331                                 while read origin_old
332                                 do
333                                         printf '%s\t%s\t%s\n' delete "$pkgname" "$origin_old" 
334                                 done < ${DBDIR}/moved_from/$origin/initial_orig >> $tmp_manifest
335                         fi
336                         printf '%s\t%s\t%s\n' delete "$pkgname" "$origin" >> $tmp_manifest
337                         pkgsys_get_conflicting_pkgs_patterns install "$origin" | while read pkg_pattern
338                         do
339                                 printf '%s\t%s\t%s\n' delete_pattern "$pkgname" "$pkg_pattern" >> $tmp_manifest
340                         done
341                         printf '%s\t%s\t%s\n' add "$pkgname" null >> $tmp_manifest
342                 fi
343                 cat "$tmp_manifest" >> $dstdir/etc/manifest.lst
344         }
345         _program_exec_and_record_completion__operation ()
346         {
347                 local PACKAGESDIR
348                 message_section_title "Creating manifest of (re)installation and package archives..."
349                 PACKAGESDIR=`realpath "${PACKAGES}/${PKGREPOSITORYSUBDIR}"`
350                 program_exec_restartable_loop_operation command_packupgrade_pack
351                 cp "${DBDIR}/stage.loop_list/ports_to_delete" "${DBDIR}/stage.loop_list/command_packupgrade_delete"
352                 message_echo
353         }
354         program_exec_and_record_completion COMMAND_PACKUPGRADE_MANIFEST_REINST
355 }
356
357 # ============= Stage of creating the manifest of deletion in operation of packupgrade create command =============
358 command_pkgs_packupgrade_create__manifest_delete ()
359 {
360         local PROGRAM_DEPENDS
361         PROGRAM_DEPENDS='COMMAND_PACKUPGRADE_MANIFEST_REINST'
362         _program_exec_restartable_loop_operation__routine ()
363         {
364                 local origin
365                 origin=$1
366                 printf '%s\t%s\t%s\n' delete "$pkgname" "$origin" >> ${DBDIR}/command_packupgrade/etc/manifest.lst
367         }
368         _program_exec_and_record_completion__operation ()
369         {
370                 message_section_title "Create manifest of deletion"
371                 program_exec_restartable_loop_operation command_packupgrade_delete
372                 message_echo
373         }
374         program_exec_and_record_completion COMMAND_PACKUPGRADE_MANIFEST_DELETE
375 }
376
377 # ============= Stage of packing in operation of packupgrade create command =============
378 command_pkgs_packupgrade_create__pack ()
379 {
380         local PROGRAM_DEPENDS
381         PROGRAM_DEPENDS='COMMAND_PACKUPGRADE_MANIFEST_DELETE'
382         _program_exec_and_record_completion__operation ()
383         {
384                 local dstdir
385                 message_section_title "Packing for the upgrade at the target systems"
386                 dstdir=${DBDIR}/command_packupgrade
387                 install -m 444 "${DBDIR}"/WITH_PKGNG "${DBDIR}"/conf/complete_setup.sh "${DBDIR}"/conf/setenv.sh "$dstdir/etc"
388                 install "${SHAREDIR}/bin/${APPNAME}-upgrade" "$dstdir"
389                 install -d "$dstdir/lib/upgrade" "$dstdir/man/man8"
390                 ( cd "${LIBDIR}" && find . upgrade -depth 1 -type f ) | while read filepath
391                 do
392                         install -m 444 "${LIBDIR}/$filepath" "$dstdir/lib/$filepath"
393                 done
394                 install -m 444 "${MYPREFIX}/man/man8/${PROGRAM}-upgrade.8.gz" "$dstdir/man/man8"
395                 tar czf "$dstdir.tar.gz" -C "$dstdir" .
396                 touch "$dstdir/complete"
397                 message_echo
398         }
399         program_exec_and_record_completion COMMAND_PACKUPGRADE_PACK
400 }
401
402 # ============= Operation of packupgrade create command =============
403 command_pkgs_packupgrade_create ()
404 {
405         if ! program_chk_stage_complete ALL_COMPLETE
406         then
407                 message_echo "ERROR: The reinstallation of ports must be completed before using this command." >&2
408                 exit 1
409         fi
410         # Preparation
411         command_pkgs_packupgrade_create__prepare
412         # Create manifest of (re)installation and package archives
413         command_pkgs_packupgrade_create__manifest_reinst
414         # Create manifest of deletion
415         command_pkgs_packupgrade_create__manifest_delete
416         # Packing for the upgrade at the target systems
417         command_pkgs_packupgrade_create__pack
418 }
419
420 # ============= Operation of packupgrade crop command =============
421 command_pkgs_packupgrade_crop ()
422 {
423         local dstdir
424         if ! program_chk_stage_complete ALL_COMPLETE
425         then
426                 message_echo "ERROR: The reinstallation of ports must be completed before using this command." >&2
427                 exit 1
428         fi
429         dstdir=${DBDIR}/command_packupgrade
430         if [ ! -e "$dstdir/complete" ]
431         then
432                 message_echo "ERROR: The execution of \"packupgrade create\" command must be completed before using this command." >&2
433                 exit 1
434         fi
435         cp "$dstdir.tar.gz" "${COMMAND_PACKUPGRADE_SAVEPATH}"
436         message_echo "INFO: The cropped archive is saved as [${COMMAND_PACKUPGRADE_SAVEPATH}]."
437 }
438
439 # ============= Operation of make command =============
440 command_pkgs_make_ports ()
441 {
442         glob=$1
443         shift || :
444         origins=`pkgsys_eval_ports_glob "$glob"`
445         [ -n "$origins" ] || message_echo "WARNING: No matching port for the glob pattern $glob" >&2
446         echo "$origins" | while read origin
447         do
448                 message_echo "========== [$origin] =========="
449                 reinstall_make_individual "$origin" "$@"
450                 errno=$?
451                 message_echo
452                 [ $errno -eq 0 ] || exit $errno
453         done
454 }