OSDN Git Service

75fde3a03d66adddfccd55ab198fcac62aec096a
[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                 cp "${DBDIR}/stage.loop_list/ports_to_delete" "${DBDIR}/stage.loop_list/command_packupgrade_delete" 2> /dev/null
277                 dstdir=${DBDIR}/command_packupgrade
278                 rm -rf "$dstdir" "$dstdir.tar.gz"
279                 mkdir -p "$dstdir"
280                 install -d "$dstdir/etc"
281                 touch "$dstdir/etc/created_packages.lst"
282                 pkg_get_pkgs_timestamps > $dstdir/etc/final_pkgs_snapshot.csv
283                 message_echo
284         }
285         program_exec_and_record_completion COMMAND_PACKUPGRADE_PREPARE
286 }
287
288 # ============= Stage of creating the manifest of deletion in operation of packupgrade create command =============
289 command_pkgs_packupgrade_create__manifest_delete ()
290 {
291         local PROGRAM_DEPENDS
292         PROGRAM_DEPENDS='COMMAND_PACKUPGRADE_PREPARE'
293         _program_exec_restartable_loop_operation__routine ()
294         {
295                 local origin
296                 origin=$1
297                 printf '%s\t%s\t%s\n' delete "$origin" NA >> ${DBDIR}/command_packupgrade/etc/manifest.lst.delete
298         }
299         _program_exec_and_record_completion__operation ()
300         {
301                 message_section_title "Create manifest of deletion"
302                 program_exec_restartable_loop_operation command_packupgrade_delete
303                 message_echo
304         }
305         program_exec_and_record_completion COMMAND_PACKUPGRADE_MANIFEST_DELETE
306 }
307
308 # ============= Stage of creating the manifest of reinstallation in operation of packupgrade create command =============
309 command_pkgs_packupgrade_create__manifest_reinst ()
310 {
311         local PROGRAM_DEPENDS
312         PROGRAM_DEPENDS=COMMAND_PACKUPGRADE_PREPARE
313         _program_exec_restartable_loop_operation__routine ()
314         {
315                 local origin dstdir tmp_manifest dbdir_new pkgname pkgarc timestamp_inst timestamp_arc origin_old
316                 origin=$1
317                 dstdir=${DBDIR}/command_packupgrade
318                 tmp_manifest=${TMPDIR}/packupgrade::manifest
319                 rm -rf "$tmp_manifest"
320                 dbdir_new=${DBDIR}/requires/$origin
321                 pkgname=`pkgsys_get_installed_pkg_from_origin "$origin"`
322                 [ -n "$pkgname" ] || return 0
323                 if ! grep -Fxq "$pkgname" "$dstdir/etc/created_packages.lst" 2> /dev/null
324                 then
325                         if pkg_info_e "$pkgname"
326                         then
327                                 if pkgarc=`pkgsys_pkgname_to_pkgarc "${PACKAGESDIR}" "$pkgname"`
328                                 then
329                                         timestamp_inst=`pkg_get_pkg_timestamp "$pkgname" 2> /dev/null` || :
330                                         timestamp_arc=`ls -lD %s "$pkgarc" 2> /dev/null | sed -E 's/[[:space:]]+/ /g' | cut -w -f 6 | grep -v '^$'` || :
331                                 else
332                                         timestamp_inst=1
333                                         timestamp_arc=0
334                                 fi
335                                 if [ -z "$timestamp_inst" -o -z "$timestamp_arc" -o "$timestamp_arc" -lt "$timestamp_inst" ]
336                                 then
337                                         if ! ( cd ${PACKAGESDIR}; pkg_create_b "$pkgname" | message_cat )
338                                         then
339                                                 message_echo "ERROR: Failed to create package [$pkgname for $origin]." >&2
340                                                 exit 1
341                                         fi
342                                 fi
343                         elif grep -Fxq "$origin" ${DBDIR}/success.run.full.list
344                         then
345                                 message_echo "ERROR: Necessary package is missing [$origin]." >&2
346                                 exit 1
347                         fi
348                         fileedit_add_a_line_if_new "$pkgname" "$dstdir/etc/created_packages.lst"
349                 fi
350                 if pkgsys_is_necessary_pkgtool "$origin"
351                 then
352                         pkg_patterns=`pkgsys_get_conflicting_pkgs_patterns install "$origin" | tr '\n' '|'`
353                         printf '%s\t%s\t%s\n' addtool "$pkgname" "$origin|$pkg_patterns" >> $tmp_manifest
354                 else
355                         if [ -e "${DBDIR}/moved_from/$origin/initial_orig" ]
356                         then
357                                 while read origin_old
358                                 do
359                                         printf '%s\t%s\t%s\n' delete "$origin_old" NA
360                                 done < ${DBDIR}/moved_from/$origin/initial_orig >> $tmp_manifest
361                         fi
362                         printf '%s\t%s\t%s\n' delete "$origin" NA >> $tmp_manifest
363                         pkgsys_get_conflicting_pkgs_patterns install "$origin" | while read pkg_pattern
364                         do
365                                 printf '%s\t%s\t%s\n' delete_pattern "$pkg_pattern" NA >> $tmp_manifest
366                         done
367                         printf '%s\t%s\t%s\n' add "$pkgname" NA >> $tmp_manifest
368                 fi
369                 cat "$tmp_manifest" >> $dstdir/etc/manifest.lst.update
370         }
371         _program_exec_and_record_completion__operation ()
372         {
373                 local PACKAGESDIR
374                 message_section_title "Creating manifest of (re)installation and package archives..."
375                 PACKAGESDIR=${PACKAGES}/${PKGREPOSITORYSUBDIR}
376                 mkdir -p "${PACKAGESDIR}"
377                 PACKAGESDIR=`realpath "${PACKAGESDIR}"`
378                 program_exec_restartable_loop_operation command_packupgrade_pack
379                 message_echo
380         }
381         program_exec_and_record_completion COMMAND_PACKUPGRADE_MANIFEST_REINST
382 }
383
384 # ============= Stage of packing in operation of packupgrade create command =============
385 command_pkgs_packupgrade_create__pack ()
386 {
387         local PROGRAM_DEPENDS
388         PROGRAM_DEPENDS='COMMAND_PACKUPGRADE_MANIFEST_DELETE'
389         _program_exec_and_record_completion__operation ()
390         {
391                 local dstdir
392                 message_section_title "Packing for the upgrade at the target systems"
393                 dstdir=${DBDIR}/command_packupgrade
394                 cat "$dstdir/etc/manifest.lst.delete" "$dstdir/etc/manifest.lst.update" > $dstdir/etc/manifest.lst
395                 install -m 444 "${DBDIR}"/WITH_PKGNG "${DBDIR}"/conf/complete_setup.sh "${DBDIR}"/conf/setenv.sh "$dstdir/etc"
396                 install "${SHAREDIR}/bin/${APPNAME}-upgrade" "$dstdir"
397                 install -d "$dstdir/lib/upgrade" "$dstdir/man/man8"
398                 ( cd "${LIBDIR}" && find . upgrade -depth 1 -type f ) | while read filepath
399                 do
400                         install -m 444 "${LIBDIR}/$filepath" "$dstdir/lib/$filepath"
401                 done
402                 install -m 444 "${MYPREFIX}/man/man8/${PROGRAM}-upgrade.8.gz" "$dstdir/man/man8"
403                 tar czf "$dstdir.tar.gz" -C "$dstdir" .
404                 touch "$dstdir/complete"
405         }
406         program_exec_and_record_completion COMMAND_PACKUPGRADE_PACK
407 }
408
409 # ============= Operation of packupgrade create command =============
410 command_pkgs_packupgrade_create ()
411 {
412         if ! program_chk_stage_complete ALL_COMPLETE
413         then
414                 message_echo "ERROR: The reinstallation of ports must be completed before using this command." >&2
415                 exit 1
416         fi
417         # Preparation
418         command_pkgs_packupgrade_create__prepare
419         # Create manifest of deletion
420         command_pkgs_packupgrade_create__manifest_delete
421         # Create manifest of (re)installation and package archives
422         command_pkgs_packupgrade_create__manifest_reinst
423         # Packing for the upgrade at the target systems
424         command_pkgs_packupgrade_create__pack
425 }
426
427 # ============= Operation of packupgrade crop command =============
428 command_pkgs_packupgrade_crop ()
429 {
430         local dstdir
431         if ! program_chk_stage_complete ALL_COMPLETE
432         then
433                 message_echo "ERROR: The reinstallation of ports must be completed before using this command." >&2
434                 exit 1
435         fi
436         dstdir=${DBDIR}/command_packupgrade
437         if [ ! -e "$dstdir/complete" ]
438         then
439                 message_echo "ERROR: The execution of \"packupgrade create\" command must be completed before using this command." >&2
440                 exit 1
441         fi
442         cp "$dstdir.tar.gz" "${COMMAND_PACKUPGRADE_SAVEPATH}"
443         message_echo "INFO: The cropped archive is saved as [${COMMAND_PACKUPGRADE_SAVEPATH}]."
444         message_echo
445 }
446
447 # ============= Operation of make command =============
448 command_pkgs_make_ports ()
449 {
450         glob=$1
451         shift || :
452         origins=`pkgsys_eval_ports_glob "$glob"`
453         [ -n "$origins" ] || message_echo "WARNING: No matching port for the glob pattern $glob" >&2
454         echo "$origins" | while read origin
455         do
456                 message_echo "========== [$origin] =========="
457                 reinstall_make_individual "$origin" "$@"
458                 errno=$?
459                 message_echo
460                 [ $errno -eq 0 ] || exit $errno
461         done
462 }