tazpkg view modules/install @ rev 929

modules/install and modules/remove: auto-update /ets/filesystems for the FS Kernel modules
author Aleksej Bobylev <al.bobylev@gmail.com>
date Sun Jan 01 23:01:52 2017 +0200 (2017-01-01)
parents 9a88902937e5
children 5dd363e1726e
line source
1 #!/bin/sh
2 # TazPkg - Tiny autonomous zone packages manager, hg.slitaz.org/tazpkg
3 # install - TazPkg module
4 # Install packages
7 # Connect function libraries
8 . /lib/libtaz.sh
9 . /usr/lib/slitaz/libpkg.sh
12 # Get TazPkg working environment
13 . @@MODULES@@/getenv
14 # $CACHE_DIR will change, it based on unchanged value of $SAVE_CACHE_DIR
15 SAVE_CACHE_DIR="$CACHE_DIR"
18 . @@MODULES@@/find-depends
23 # Log TazPkg activity
25 log_pkg() {
26 debug "\nlog_pkg('$1')\n PACKAGE='$PACKAGE'\n VERSION='$VERSION'\n EXTRAVERSION='$EXTRAVERSION'"
28 local extra
30 [ "$1" == 'Installed' ] && \
31 extra=" - $(fgrep " $PACKAGE-$VERSION" "$PKGS_DB/installed.$SUM" | awk '{print $1}')"
32 debug " extra='$extra'"
34 [ -w "$LOG" ] &&
35 echo "$(date +'%F %T') - $1 - $PACKAGE ($VERSION$EXTRAVERSION)$extra" >> $LOG
36 }
39 # get an already installed package from packages.equiv
41 equivalent_pkg() {
42 # input: $1 = package name (like "nano")
43 local i rep rules rule out
45 rules=$(for rep in $PRIORITY; do
46 grep -hs "^$1=" "$rep/packages.equiv"
47 done | sed "s|^$1=||")
48 debug " >rules='$rules'"
50 for rule in $rules; do
51 debug " >rule='$rule'"
52 case $rule in
53 *:*)
54 debug '-- x:x'
55 # format 'alternative:newname'
56 # if alternative is installed then substitute newname
57 out="${rule#*:}"
58 awk -F$'\t' -vp="${rule%:*}" '$1==p{exit 1}' "$PKGS_DB/installed.info" || break
59 debug '-- x:x /'
60 ;;
61 *)
62 debug '-- x'
63 # unconditional substitution
64 out="$rule"
65 awk -F$'\t' -vp="$rule" '$1==p{exit 1}' "$PKGS_DB/installed.info" || break
66 debug '-- x /'
67 ;;
68 esac
69 unset out
70 done
71 debug '--'
72 # if not found in packages.equiv then no substitution
73 echo "${out:-$1}"
74 }
77 # Check and install all missing deps.
78 # Auto install or ask user then install all missing deps from local dir, CD-ROM,
79 # media or from the mirror.
81 install_all_deps() {
82 # input: $1 = package file to check/install missing dependencies
83 # ROOT READY
84 # dep: equivalent_pkg.
86 debug "\ninstall_all_deps('$1')"
88 local TMP_DIR DEPENDS num missing_packages equiv pkg answer dir found pkgfile
90 # Check for missing deps listed in a receipt packages.
92 # Get the receipt's variable DEPENDS
93 DEPENDS=$(
94 TMP_DIR=$(mktemp -d); cd "$TMP_DIR"
95 cpio --quiet -i receipt >/dev/null 2>&1
96 . receipt; echo $DEPENDS
97 rm -rf "$TMP_DIR"
98 ) < "$1"
100 unset num missing_packages
101 for depend in $DEPENDS; do
102 debug " depend='$depend'"
103 equiv=$(equivalent_pkg $depend)
104 debug " equiv='$equiv'\n"
105 if [ ! -d "$INSTALLED/$equiv" ]; then
106 missing_packages="$missing_packages $equiv"
107 num=$((num+1))
108 elif [ ! -f "$INSTALLED/$equiv/receipt" ]; then
109 [ -z "$quiet" ] && _ 'WARNING! Dependency loop between "%s" and "%s".' "$PACKAGE" "$equiv"
110 fi
111 done
113 # Nothing to install, exit function
114 [ -z "$num" ] && return
117 title "$(_ 'Tracking dependencies for package "%s"' "$PACKAGE")"
119 # Individual messages for each missing package
120 [ -z "$quiet" ] && \
121 for pkg in $missing_packages; do
122 _ 'Missing package "%s"' "$pkg"
123 done
125 footer "$(_p \
126 '%s missing package to install.' \
127 '%s missing packages to install.' "$num" \
128 "$num")"
131 if [ "$AUTO_INSTALL_DEPS" == 'yes' ] || [ -n "$quiet" ]; then
132 # Quietly not display anything. Assume 'yes' unless '--noconfirm' is provided
133 answer=0
134 [ -n "$noconfirm" ] && answer=1
135 else
136 # Display question; wait for answer or print auto-answer
137 newline
138 confirm "$(_ 'Install all missing dependencies? (y/N)')"
139 answer=$?
140 newline
141 fi
142 debug " answer='$answer'"
144 dir="$(dirname "$1")"
145 debug " dir='$dir'"
147 # We can install packages from /home/boot/packages at a boot time
148 # Also we can prefer local packages over mirrored/cached using '--local' option
149 [ "$dir" == '/home/boot/packages' ] && local='yes'
150 debug " local='$local'"
152 # "--nodeps" option prevents to install dependencies
153 if [ "$answer" -eq 0 -a -z "$nodeps" ]; then
154 debug " let's install missing packages"
155 for pkg in $missing_packages; do
156 debug " pkg='$pkg'"
157 if [ ! -d "$INSTALLED/$pkg" ]; then
158 # Package not installed
160 found='0'
161 # Prefer local packages
162 if [ -n "$local" ]; then
163 [ -z "$quiet" ] && _ 'Checking if package "%s" exists in local list...' "$pkg"
164 # Find local package
165 tempd="$(mktemp -d)"; cd "$tempd"
166 for pkgfile in $dir/$pkg-*.tazpkg; do
167 [ -e "$pkgfile" ] || continue
168 # Extract receipt from each matched package
169 cpio -F "$pkgfile" -i receipt >/dev/null 2>&1
170 name=$(. receipt; echo $PACKAGE)
171 rm receipt
172 if [ "$name" == "$pkg" ]; then
173 found='1'
174 # Install the first matched package: normally there is only one package
175 # with the $PACKAGE matched in the receipt
176 tazpkg install "$pkgfile"
177 fi
178 done
179 rm -r "$tempd"
180 fi
181 debug " found='$found'"
183 # Install package from the mirror
184 [ "$found" -eq 0 ] && tazpkg get-install "$pkg"
185 fi
186 done
187 else
188 # Answered 'No' to install dependencies, or '--nodeps' option given
189 newline
190 _ 'Leaving dependencies for package "%s" unresolved.' "$PACKAGE"
191 _ 'The package will be installed but will probably not work.'
192 newline
193 fi
194 }
197 # Extract a package with cpio and gzip/lzma.
199 extract_package() {
200 # input: $1 - path to package to be extracted; package should be in the current dir
201 # ROOT INDEPENDENT
202 action 'Extracting package...'
204 # Extract "outer layer": cpio; remove the original package file
205 cpio -idm --quiet < "$1" && rm -f "$1"
207 # "Inner layer" may vary
208 if [ -f fs.cpio.lzma ]; then
209 # "Plain" cpio.lzma
210 unlzma < fs.cpio.lzma | cpio -idm --quiet && rm fs.cpio.lzma
211 elif [ -f fs.cpio.gz ]; then
212 # "Fast" cpio.gz (used to pack-then-install process in most of get-packages)
213 zcat fs.cpio.gz | cpio -idm --quiet && rm fs.cpio.gz
214 fi
216 status
217 }
220 # Print short package description
222 print_short_description() {
223 # TODO: undigest repo support? priority...
224 # ROOT READY
225 local short_desc=''
227 # Try to find localized short description
228 for LC in $LANG ${LANG%_*}; do
229 [ -e "$PKGS_DB/packages-desc.$LC" ] &&
230 short_desc=$(awk -F$'\t' -vp="$1" '$1==p{print $2; exit}' "$PKGS_DB/packages-desc.$LC")
231 done
233 # Try to find short description for mirrored package
234 [ -z "$short_desc" -a -s "$PKGS_DB/packages.info" ] &&
235 short_desc=$(awk -F$'\t' -vp="$1" '$1==p{print $4; exit}' "$PKGS_DB/packages.info")
237 [ -z "$short_desc" ] && short_desc="$SHORT_DESC"
239 longline "$short_desc"
240 }
243 grepesc() {
244 sed 's/\[/\\[/g'
245 }
250 #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*
252 # Block of receipt function callers
253 # Why? "Bad" receipt sourcing can redefine some vital TazPkg variables.
254 # Few receipts function should be patched now.
256 # Input: $1 = path to the receipt to be processed
258 # Pre-install commands
259 call_pre_install() {
260 local tmp
261 if grep -q '^pre_install()' "$1"; then
262 action 'Execute pre-install commands...'
263 tmp="$(mktemp)"
264 cp "$1" "$tmp"
265 sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
266 ( . "$tmp"; pre_install "$root" )
267 status
268 rm "$tmp"
269 fi
271 }
272 # Post-install commands
273 call_post_install() {
274 local tmp
275 if grep -q '^post_install()' "$1"; then
276 action 'Execute post-install commands...'
277 tmp="$(mktemp)"
278 cp "$1" "$tmp"
279 sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
280 ( . "$tmp"; post_install "$root" )
281 status
282 rm "$tmp"
283 fi
284 }
287 #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*
290 # This function installs a package in the rootfs.
292 install_package() {
293 # input: $1 = path to package to be installed
294 # dep: install_all_deps, print_short_description, extract_package, grepesc.
296 debug "\ninstall_package('$1')"
297 local dir
299 PACKAGE_FILE="$1"
300 TMP_DIR="$(mktemp -d)"
302 # Get receipt's variables and functions
303 { cd "$TMP_DIR"; cpio --quiet -i receipt >/dev/null 2>&1; } < "$PACKAGE_FILE"
304 # Why next code? "Bad" receipt sourcing can redefine some vital TazPkg variables.
305 (
306 . "$TMP_DIR/receipt"
307 cat > "$TMP_DIR/receipt.var" <<EOT
308 PACKAGE="$PACKAGE"
309 VERSION="$VERSION"
310 EXTRAVERSION="$EXTRAVERSION"
311 CATEGORY="$CATEGORY"
312 SHORT_DESC="$SHORT_DESC"
313 WEB_SITE="$WEB_SITE"
314 TAGS="$TAGS"
315 DEPENDS="$DEPENDS"
316 CONFIG_FILES="$CONFIG_FILES"
317 PACKED_SIZE="$PACKED_SIZE"
318 UNPACKED_SIZE="$UNPACKED_SIZE"
319 EOT
320 rm "$TMP_DIR/receipt"
321 )
322 . "$TMP_DIR/receipt.var"
325 # Make sure folder exists on new installs or upgrades
326 mkdir -p "$INSTALLED/$PACKAGE"
328 # Keep "modifiers" and "files.list" on upgrade
329 find "$INSTALLED/$PACKAGE" -type f \( ! -name modifiers ! -name files.list \) -delete
331 # Update "installed.md5"
332 # TODO: discontinue using 'installed.md5'
333 touch "$PKGS_DB/installed.$SUM"
334 sed -i "/ $(basename "$PACKAGE_FILE")$/d" "$PKGS_DB/installed.$SUM" 2>/dev/null
335 cd "$(dirname "$PACKAGE_FILE")"
336 $CHECKSUM "$(basename "$PACKAGE_FILE")" >> "$PKGS_DB/installed.$SUM"
338 # Resolve package dependencies before package installation
339 install_all_deps "$PACKAGE_FILE"
342 # TODO: why this list-processed in the $PKGS_DB?
343 #[ -n "$INSTALL_LIST" ] && echo "$PACKAGE_FILE" >> "$PKGS_DB/$INSTALL_LIST-processed"
345 if [ -n "$sequence" ]; then
346 title 'Installation of package "%s" (%s)' "$PACKAGE" "$sequence"
347 else
348 title 'Installation of package "%s"' "$PACKAGE"
349 fi
351 if [ -z "$quiet" ]; then
352 print_short_description "$PACKAGE"
353 separator '-'
354 fi
356 action 'Copying package...'
357 cp "$PACKAGE_FILE" "$TMP_DIR"
358 status
360 cd "$TMP_DIR"
361 extract_package "$(basename "$PACKAGE_FILE")"
363 # Include temporary receipt to get the right variables
364 . "$TMP_DIR/receipt.var"
366 cd "$INSTALLED"
369 # Get files to remove if upgrading
370 # IFS here modified temporarily for processing filenames with spaces
371 IFS=$'\n'
372 if [ -f "$PACKAGE/files.list" ]; then
373 while read file; do
374 grep -q "^$(echo "$file" | grepesc)$" "$TMP_DIR/files.list" && continue
375 for i in $(cat "$PACKAGE/modifiers" 2>/dev/null;
376 fgrep -sl "$PACKAGE" */modifiers | cut -d/ -f1); do
377 grep -qs "^$(echo "$file" | grepesc)$" "$i/files.list" && continue 2
378 done
379 echo "$file"
380 done < "$PACKAGE/files.list" > "$TMP_DIR/files2remove.list"
381 fi
382 unset IFS
385 # Remember modified packages
386 action 'Remember modified packages...'
387 {
388 check=false
389 # TODO: why '[' the special?
390 # FIXME: we have files with spaces in our packages!
391 for i in $(fgrep -v [ $TMP_DIR/files.list); do
392 [ -e "$root$i" ] || continue
393 [ -d "$root$i" ] && continue
394 echo "- $i"
395 check=true
396 done ;
397 $check && \
398 for i in *; do
399 [ "$i" == "$PACKAGE" ] && continue
400 [ -s "$i/files.list" ] || continue
401 awk "{ printf \"$i %s\\n\",\$1 }" < "$i/files.list"
402 done;
403 } | awk '
404 {
405 if ($1 == "-" || file[$2] != "") {
406 file[$2] = file[$2] " " $1
407 if ($1 != "-") {
408 if (pkg[$1] == "") all = all " " $1
409 pkg[$1] = pkg[$1] " " $2
410 }
411 }
412 }
413 END {
414 for (i = split(all, p, " "); i > 0; i--)
415 for (j = split(pkg[p[i]], f, " "); j > 0; j--)
416 printf "%s %s\n",p[i],f[j];
417 }
418 ' | while read dir file; do
419 if grep -qs "^$dir$" "$PACKAGE/modifiers"; then
420 # Do not overload an overloaded file !
421 rm "$TMP_DIR/$file" 2>/dev/null
422 continue
423 fi
424 grep -qs "^$PACKAGE$" "$dir/modifiers" && continue
425 if [ -s "$dir/volatile.cpio.gz" ]; then
426 # We can modify backed up files without notice
427 zcat "$dir/volatile.cpio.gz" | cpio -t --quiet | \
428 grep -q "^${file#/}$" && continue
429 fi
430 echo "$PACKAGE" >> "$dir/modifiers"
431 done
432 status
435 cd "$TMP_DIR"
436 # Copy receipt, etc.
437 for file in receipt files.list description.txt $CHECKSUM; do
438 [ -f "$file" ] && cp "$file" "$INSTALLED/$PACKAGE"
439 done
442 # Pre-install commands
443 call_pre_install "$INSTALLED/$PACKAGE/receipt"
446 if [ -n "$CONFIG_FILES" ]; then
447 # Save "official" configuration files
448 action 'Saving configuration files...'
449 debug "\n"
451 cd fs
452 local config_file
453 for config_file in $CONFIG_FILES; do
454 debug " config_file: '$config_file'"
455 find ${config_file#/} -type f 2>/dev/null
456 done | cpio -o -H newc --quiet | gzip -9 > "$INSTALLED/$PACKAGE/volatile.cpio.gz"
457 cd ..
459 if [ -z "$newconf" ]; then
460 debug " no '--newconf': clean official config files"
461 # Keep user configuration files: remove "official" from fs tree
462 for config_file in $CONFIG_FILES; do
463 for config_file_official in $(find "fs$config_file" ! -type d 2>/dev/null | sed 's|^fs||'); do
464 if [ -e "$root$config_file_official" ]; then
465 debug " official '$config_file_official' will be skipped"
466 rm "fs$config_file_official"
467 else
468 debug " official '$config_file_official' will be written"
469 fi
470 done
471 done
472 fi
473 # always '[ Done ]' status, unless '--newconf' is passed or not
474 :; status
475 fi
478 if [ -n "$(ls fs/* 2>/dev/null)" ]; then
479 action 'Installing package...'
481 debug '\n resolving destination links in source'
482 IFS=$'\n'
483 for dir in $(find fs -type d | sed 's|^fs||;/^$/d'); do
484 if ldir=$(readlink -n $root$dir); then
485 debug " * mv 'fs$dir'\n -> 'fs${dir%/*}/$ldir'"
486 mkdir -p "fs${dir%/*}/${ldir%/*}"
487 mv "fs$dir" "fs${dir%/*}/$ldir"
488 fi
489 done
490 unset IFS
492 debug ' copying folders and files to destination'
493 cp -af fs/* "$root/"
494 status
495 fi
498 if [ -s files2remove.list ]; then
499 action 'Removing old files...'
500 while read file; do
501 dir="$root$file"
502 # Remove specified file
503 rm -f "$dir"
504 # Recursive remove non-empty up-dirs
505 while [ "$dir" != "$root/" ]; do
506 dir=$(dirname "$dir")
507 rmdir "$dir" 2>/dev/null || break
508 done
509 done < files2remove.list
510 :; status
511 fi
514 # Remove the temporary random directory.
515 action "Removing all tmp files..."
516 cd ..; rm -rf "$TMP_DIR"
517 status
520 # Post install commands
521 call_post_install "$INSTALLED/$PACKAGE/receipt"
526 # Update system databases
527 # Updating DBs is important process, so not to hide such errors (localized):
528 # chroot: can't execute '/usr/bin/***': No such file or directory
530 local fl="$INSTALLED/$PACKAGE/files.list" upd=0 udesk umime uicon uschm ukrnl ukrnlfs
532 fgrep /usr/share/applications/ "$fl" | fgrep -q .desktop && udesk='yes'
533 fgrep -q /usr/share/mime "$fl" && umime='yes'
534 fgrep -q /usr/share/icon/hicolor "$fl" && uicon='yes'
535 fgrep /usr/share/glib-2.0/schemas "$fl" | fgrep -q .xml && uschm='yes'
536 fgrep /usr/lib/gdk-pixbuf "$fl" | fgrep -q .so && upixb='yes'
537 if fgrep -q /lib/modules "$fl"; then
538 ukrnl='yes'
539 if fgrep -q /kernel/fs/ "$fl"; then
540 ukrnlfs='yes'
541 fi
542 fi
544 if [ -n "$udesk$umime$uicon$uschm$upixb$ukrnl" ]; then
545 action 'Update system databases...'
546 upd=1
547 fi
549 # package 'desktop-file-utils'
550 [ -n "$udesk" ] && chroot "$root/" /usr/bin/update-desktop-database /usr/share/applications 2>/dev/null
551 # package 'shared-mime-info'
552 [ -n "$umime" ] && chroot "$root/" /usr/bin/update-mime-database /usr/share/mime
553 # packages 'gtk+', 'gtk+3'
554 [ -n "$uicon" ] && chroot "$root/" /usr/bin/gtk-update-icon-cache /usr/share/icons/hicolor
555 # package 'glib'
556 # hide messages like next because they are unresolved (we may to patch glib to hide them, almost the same)
557 # warning: Schema '*' has path '*'. Paths starting with '/apps/', '/desktop/' or '/system/' are deprecated.
558 [ -n "$uschm" ] && chroot "$root/" /usr/bin/glib-compile-schemas /usr/share/glib-2.0/schemas 2>&1 | fgrep -v '/apps/'
559 # package 'gdk-pixbuf'
560 [ -n "$upixb" ] && chroot "$root/" /usr/bin/gdk-pixbuf-query-loaders --update-cache
562 if [ -n "$ukrnlfs" ]; then
563 for i in $(awk -F/ '{if($6=="fs" && $8~$7)print $7}' "$fl" | sort -u); do
564 touch "$root/etc/filesystems"
565 grep "^$i\$" "$root/etc/filesystems" || echo "$i" >> "$root/etc/filesystems"
566 done
567 fi
568 # packages 'busybox', 'kmod', 'depmod'
569 [ -n "$ukrnl" ] && grep '/lib/modules' "$fl" | cut -d'/' -f4 | uniq | xargs chroot "$root/" /sbin/depmod -a
571 [ "$upd" -eq 1 ] && status
576 # Update installed.info
577 SIZES=$(echo $PACKED_SIZE $UNPACKED_SIZE | sed 's|\.0||g')
578 # Remove newlines from some receipts
579 DEPENDS=$(echo $DEPENDS)
580 PKG_SUM="$(fgrep " $PACKAGE-$VERSION$EXTRAVERSION.tazpkg" "$PKGS_DB/installed.$SUM" | cut -d' ' -f1)"
581 ii="$PKGS_DB/installed.info"
582 # Remove old entry
583 sed -i "/^$PACKAGE /d" "$ii"
584 cat >> "$ii" <<EOT
585 $PACKAGE $VERSION$EXTRAVERSION $CATEGORY $SHORT_DESC $WEB_SITE $TAGS $SIZES $DEPENDS $PKG_SUM
586 EOT
587 #awk -F$'\t' -vp="$PACKAGE" '$1==p' "$PKGS_DB/packages.info" > $ii
588 TEMP_FILE="$(mktemp)"
589 sort "$ii" > "$TEMP_FILE"; mv -f "$TEMP_FILE" "$ii"; chmod a+r "$ii"; unset ii
591 cd "$CUR_DIR"
592 footer "$(_ 'Package "%s" (%s) is installed.' "$PACKAGE" "$VERSION$EXTRAVERSION")"
594 # Log this activity
595 log_pkg Installed
597 # Remove package from upgrade list
598 [ -s "$UP_LIST" ] && sed -i "/^$PACKAGE\$/d" "$UP_LIST"
599 }
604 #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*
607 PACKAGE=$(
608 tmp_dir=$(mktemp -d); cd "$tmp_dir"
609 cpio --quiet -i receipt >/dev/null 2>&1
610 . receipt; echo $PACKAGE
611 rm -rf "$tmp_dir"
612 ) < "$1"
614 if grep -qs "^$PACKAGE$" "$BLOCKED"; then
615 _ 'Package "%s" blocked.' "$PACKAGE"
616 exit 1
617 fi
619 if [ -z "$forced" ]; then
620 # Check if a package is already installed
621 debug "\ncheck for installed package '$PACKAGE'"
623 awk -F$'\t' -vpv="$PACKAGE" '$1==pv { exit 1 }' "$PKGS_DB/installed.info"
625 if [ "$?" -eq 1 ]; then
626 if [ -z "$quiet" ]; then
627 newline
628 _ '"%s" package is already installed.' "$(colorize 34 "$PACKAGE")"
629 longline "$(_ 'You can use the --forced option to force installation.')"
630 newline
631 fi
632 exit 1
633 fi
634 fi
636 install_package "$(realpath "$1")"