home *** CD-ROM | disk | FTP | other *** search
- #!/bin/sh
- #+++
- # RCS $Id: gzip_package.sh,v 2.7 1998/03/04 19:53:50 tom Exp $
- # title: gzip_package
- # abstract: convert NS Installer.app package to use gzipped archive.
- # author: T.R.Hageman <tom@basil.icce.rug.nl>
- # created: September 1994
- # modified: (see RCS Log at end)
- # copyleft:
- #
- # Copyright (C) 1994--1998 Tom R. Hageman.
- #
- # This is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This software is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this software; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- #
- # description:
- #
- #---
-
- Revision=; Date=
- Clean() { expr "$1" : ':* *\(.*[^ $]\) *$*'; }
-
- Revision=`Clean "$Revision: 2.7 $"`
- Date=`Clean "$Date: 1998/03/04 19:53:50 $"`
-
- prog=`basename $0`
-
- USAGE="Usage: $prog [options] package...
- -d --debug Debug mode (don't remove tmp files.)
- -i --info Show package's compression status.
- -k --keep Keep original package around.
- -q --quiet Shut up completely.
- -s --save=* How much gzip should save at least (in kbytes, or \`nn%').
- -u --unzip Expand gzip'ed package archive to normal (compressed).
- -v --verbose Talkative mode.
- -h --help Show help text.
- -V --version Show version."
-
- tar=gnutar
-
- verbose=
- debug=
- keep=
- quiet=
- unzip=
- info=
- minsavings="5%"
-
- # Determine default action from program name, a la gzip <-> gunzip.
- case "$prog" in #(
- gunzip*) unzip=yes
- esac
-
- StdErr() { echo "$@" >&2; }
-
- # Handle options.
- while true; do
- {
- case "$1" in #((((((((((
- -V | --version | --versio | --versi | --vers | --ver | --ve | --v )
- echo $prog Version $Revision of $Date.
- exit 0
- ;;
- -d | --debug | --debu | --deb | --de | --d )
- debug=yes
- # set -x
- shift
- ;;
- -i | --info | --inf | --in | --i )
- info=yes
- shift
- ;;
- -k | --keep | --kee | --ke | --k )
- keep=yes
- shift
- ;;
- -q | --quiet | --quie | --qui | --qu | --q )
- quiet=yes
- verbose=
- shift
- ;;
- -s=* | --save=* | --sav=* | --sa=* | --s=* )
- minsavings=`expr "$1" : '[^=]*=\([0-9][0-9]*%*\)`
- [ "$minsavings" ] ||
- {
- Stderr "$prog: value for \`$1' should be number or percentage."
- exit 2
- }
- shift
- ;;
- -s | --save | --sav | --sa | --s )
- minsavings=`expr "$2" : '\([0-9[0-9]*%*\)'`
- [ "$minsavings" ] ||
- {
- Stderr "$prog: value for \`$1 $2' should be number or percentage."
- exit 2
- }
- shift
- shift
- ;;
- -u | --unzip |--unzi | --unz | --un | --u )
- unzip=yes
- shift
- ;;
- -v | --verbose | --verbos | --verbo | --verb )
- verbose=yes
- quiet=
- # set -v
- shift
- ;;
- -h | --help | --hel | --he | --h )
- echo "$USAGE"
- exit 0
- ;;
- -- ) # option delimiter.
- shift
- break
- ;;
- -* )
- StdErr "$prog: invalid option \`$1'"
- StdErr "$USAGE"
- exit 2
- ;;
- "" )
- case "$#" in #(
- 0) StdErr "$USAGE"
- exit 2
- esac
- # silently ignore empty argument.
- shift
- ;;
- * )
- break
- ;;
- esac
- }
- done
-
- status=0
- tmpprefix="##$prog##"
-
- # Error handling.
-
- # Unfortunately `continue' does not seem to work from within a shell function,
- # So don't forget to add it explicitly after each occurrence of BailOut.
- BailOut() { [ "$1" -gt "$status" ] && status=$1; [ "$debug" ] || eval "$onexit"; onexit=; }
-
- Error() {
- StdErr "$prog:" "$@"
- BailOut 1
- }
-
-
- # Support function to yield free space (in kbytes) available in dir.
- DiskFreeSpace() { # $1: <in-directory>
- # Available Capacity
- df "$1" | sed -n 's|^.* \([0-9][0-9]*\) *[0-9][0-9]% .*|\1|p'
- }
-
- # Support function to yield size of package.
- DirUsage() { # $1 <in-directory>
- du -s -l "$1" | sed 's:^\([0-9][0-9]*\).*:\1:'
- }
-
- # Safely remove directory recursively, but only if we own it.
- WipeDir() { # $1: <directory>
- chmod -R u+w "$1" >/dev/null 2>&1 && rm -rf "$1"
- }
-
- # Function to replace target package with newly-built one.
- ReplaceTarget() {
- if [ "$inplace" ]; then
- {
- # in-place is relatively simple.
- backup="$pkgdir~"
- WipeDir "$backup"
- mv "$pkgdir" "$backup" 2>/dev/null ||
- { Error "Cannot move original package to \`$backup'"; return; }
-
- onexit='mv "$backup" "$pkgdir" 2>/dev/null ||
- Stderr "(original package is now named \`$backup'\'')
- '"$onexit"
-
- mv "$builddir" "$pkgdir" 2>/dev/null ||
- { Error "Cannot move new package to \`$pkgdir'"; return; }
-
- onexit=
-
- [ "$keep" ] || onexit='WipeDir "$backup"'
- }
- else
- {
- # Not in-place; either because there was not enough space on the disk,
- # or because the directory in which the package resides is not
- # writeable. Anyway, it's a lot harder.
-
- # Make backup of package in $HOME.
- suffix=
- while [ "$suffix" != "~~~~~~~~" ]
- do
- backup="$HOME/$pkgname.pkg~$suffix"
- WipeDir "$backup"
- [ ! -d "$backup" -a ! -f "$backup" ] && break
- suffix="$suffix~"
- done
- mkdir "$backup" 2>/dev/null ||
- { Error "Cannot create backup package \`$backup'"; return; }
- ( cd "$pkgdir" && $tar -cf - . ) 2>/dev/null |
- ( cd "$backup" && $tar -xpf - ) 2>/dev/null ||
- { Error "copy to backup package \`$backup' failed."; return; }
-
- onexit='{ WipeDir "$pkgdir/."
- ( cd "$backup" && $tar -cf - . ) 2>/dev/null |
- ( cd "$pkgdir" && $tar -xpf - ) 2>/dev/null
- } || Stderr "(original package is now in \`$backup'\'')
- '"$onexit"
-
- WipeDir "$pkgdir/."
- ( cd "$builddir" && $tar -cf - . ) 2>/dev/null |
- ( cd "$pkgdir" && $tar -xpf - ) 2>/dev/null ||
- { Error "Cannot copy new package to \`$pkgdir'"; return; }
-
- onexit=
- [ "$keep" ] || onexit='WipeDir "$backup"'
- WipeDir "$builddir"
- }
- fi
- }
-
- # Catch signals.
- onexit=
- trap '[ "$debug" ] || eval "$onexit"; trap 0; exit $status' 0
- trap 'StdErr "***signalled***"; status=2; exit $status' 1 2 3 15
-
-
- for arg in "$@"; do
-
- # Strip off trailing slashes.
- pkgdir=`expr "$arg" : '\(.*[^/]\)/*'`
- shift
-
- if [ -d "$pkgdir.pkg" ]; then
- {
- pkgdir="$pkgdir.pkg"
- }
- elif [ ! -d "$pkgdir" ]; then
- {
- [ -f "$pkgdir" ] || Error "package \`$pkgdir' does not exist."
- Error "\`$pkgdir' is not a directory."
- continue
- }
- fi
-
- # More sanity checks.
- [ "$info" ] || [ -w "$pkgdir" ] || { Error "package \`$pkgdir' is read-only."; continue; }
-
- # Get the root of the package, sans .pkg extension.
- pkgname=`basename "$pkgdir" .pkg`
-
- packagesize=`DirUsage "$pkgdir"`
-
- # Load size definitions in *.sizes into shell variables.
- CompressedSize=`sed -n 's/^CompressedSize \(.*\)/\1/p' "$pkgdir/$pkgname.sizes"`
-
- # Check if this is already gzipped.
- if [ -f "$pkgdir/$pkgname.tar.gz" -a -h "$pkgdir/$pkgname.tar.Z" ]
- then
- realCompressedSize=`sed -n 's/^realCompressedSize \(.*\)/\1/p' "$pkgdir/$pkgname.sizes"`
- expands=`expr $realCompressedSize - $CompressedSize`
- sizeneeded=`expr $packagesize + $expands`
- if [ "$info" ]
- then
- mesg=
- [ "$verbose" ] && mesg=" [${packagesize} kbytes, saves ${expands} (`expr $expands \* 100 / $sizeneeded`%)]"
- echo "$pkgdir: gzipped$mesg"
- BailOut 0; continue
- else
- [ "$unzip" ] || {
- [ "$quiet" ] || StdErr "$prog: \`$pkgdir' is already gzipped; unchanged"
- BailOut 0; continue
- }
- fi
- else
- if [ "$info" ]
- then
- if [ -f "$pkgdir/$pkgname.tar.Z" ]
- then
- mesg=compressed
- [ "$verbose" ] && mesg="$mesg [${packagesize} kbytes]"
- else
- mesg=installed
- [ "$verbose" ] && mesg="$mesg [at "`cat "$pkgdir/$pkgname.location"`"]"
- fi
- echo "$pkgdir: $mesg"
- BailOut 0; continue
- else
- [ "$unzip" ] && {
- [ "$quiet" ] || StdErr "$prog: \`$pkgdir' is already gunzipped; unchanged"
- BailOut 0; continue
- }
- fi
- sizeneeded=$packagesize
- fi
-
- # Get the directory in which the package resides.
- unset parentdir
- [ "${parentdir=`expr \"$pkgdir\" : '\(.*\)/[^/][^/]*'`}" ] || parentdir="."
-
- [ "$quiet" -o "$verbose" ] || echo -n "$pkgdir: "
-
-
- # We need a temporary work directory which will contain the updated package.
- # See where we can create it.
-
- inplace=
- # overestimate size about 10 percent to be on the safe side...
- [ `expr $sizeneeded \* 11 / 10` -le `DiskFreeSpace "$parentdir"` ] &&
- {
- inplace=yes
- builddir="$parentdir/$tmpprefix$$"
- mkdir "$builddir" 2>/dev/null || inplace=
- # If this fails, this is probably due to parent-dir being write-protected,
- # so build the new package in /tmp instead
- }
- [ "$inplace" ] ||
- {
- builddir="/tmp/$tmpprefix$$"
- mkdir "$builddir" 2>/dev/null ||
- { Error "Cannot create build-directory for \`$pkgdir'."; continue; }
- }
-
- # Cleanup.
- onexit="WipeDir \"$builddir\""
-
-
- # Transfer the contents of the original package, except the archive
- ( cd "$pkgdir" && $tar -cf - `ls -A | fgrep -v "\
- $pkgname.tar.Z
- $pkgname.tar.gz"` ) 2>/dev/null |
- ( cd "$builddir" && $tar -xpf - ) 2>/dev/null ||
- { Error "copy to build-directory of \`$pkgdir' failed."; continue; }
-
- if [ "$unzip" ]
- then
- # Handle gzipped -> compressed package
-
- # Remove the symbolic .Z link and other junk stuff.
- rm -f $builddir/$pkgname.tar.Z $builddir/funzip
-
- # Restore original values in *.sizes
- sed 's/^\(CompressedSize\).*/\1 '"$realCompressedSize"'/
- /^realCompressedSize/d' "$builddir/$pkgname.sizes" >"$builddir/real_sizes"
-
- # Move the real scripts back.
- for i in pre_install post_install sizes; do
- {
- rm -f "$builddir/$pkgname.$i"
- [ -f "$builddir/real_$i" ] &&
- {
- mv "$builddir/real_$i" "$builddir/$pkgname.$i" 2>/dev/null ||
- { Error "Cannot move $i script for \`$pkgdir'."; continue 2; }
- }
- }
- done
-
- # Now re-expand the contents of the package using compress.
- gunzip < "$pkgdir/$pkgname.tar.gz" | compress > "$builddir/$pkgname.tar.Z" ||
- { Error "Cannot re-gunzip contents of \`$pkgdir'."; continue; }
-
- [ "$quiet" ] ||
- {
- [ "$verbose" ] && echo -n "$pkgdir: "
- echo "expands $expands kbytes (`expr $expands \* 100 / $packagesize`%)"
- }
-
- # Now, finally, replace the target package with the compressed one.
- ReplaceTarget
-
- BailOut 0; continue
- fi
-
- # Handle compressed -> gzipped package
-
- # Now recompress the contents of the package using gzip.
- gunzip < "$pkgdir/$pkgname.tar.Z" | gzip -9 > "$builddir/$pkgname.tar.gz" ||
- { Error "Cannot re-gzip contents of \`$pkgdir'."; continue; }
-
- # Copy a tiny ungzipper (funzip [m68k]) to the new package,
- # for NS < 3.1 compatibility.
- (cd $builddir; sed -n '/^begin .* funzip/,/^end/p' | uudecode) <"$0" ||
- { Error "Cannot add funzip to \`$pkgdir'."; continue; }
-
- # Create a symbolic link to a temporary location for the original contents.
- ln -s "/tmp/$tmpprefix$pkgname.tar.Z" "$builddir/$pkgname.tar.Z" ||
- { Error "cannot create symbolic link for \`$pkgname.tar.Z"; continue; }
-
-
- # Now add a pre_install script to unpack the .gz archive to the temp. location,
- # and a post_install script to do the necessary cleanup.
-
- # Move the real scripts out of the way.
- for i in pre_install post_install sizes; do
- {
- [ -f "$builddir/$pkgname.$i" ] &&
- {
- mv "$builddir/$pkgname.$i" "$builddir/real_$i" 2>/dev/null ||
- { Error "Cannot move $i script for \`$pkgdir'."; continue 2; }
- }
- }
- done
-
- # Now create replacement scripts.
-
- SUBSTS='1i\
- #!/bin/sh\
- # AUTOMATICALLY GENERATED BY '"$prog $Revision of $Date"'.\
- \
- d="$1"\
- n=`basename "$d" .pkg`\
- p="$d/$n"\
- t="/tmp/'"$tmpprefix"'$n.tar.Z"
- '
- #NO#/^[ ]*#/d'
- #NO## (Remove comment lines to keep the installed scripts lean.)
-
- sed "$SUBSTS" >"$builddir/$pkgname.pre_install" <<\!!!pre
- r="$d/real_pre_install"
- E=echo
- B='[ -f "$r" ] && exec "$r" "$@"; $E OK.'
-
- # Bail out if there is no gzipped archive. (assume regular package)
- [ -f "$p.tar.gz" ] || eval "$B"
-
- # Make sure symlink to work file is in place.
- [ -h "$p.tar.Z" ] || {
- # No link. Bail out if looks like regular package after all.
- [ -f "$p.tar.Z" ] && eval "$B"
- # Last-ditch effort: try to create link.
- ln -s "$t" "$p.tar.Z" || { $E FAILED.; exit 1; }
- }
- # Execute real pre_install script, if it exists, first.
- [ -r "$r" ] && { "$r" "$@" || exit 1; } || $E
-
- # Remove work file for good measure.
- rm -f "$t"
-
- $E -n " Gunzipping package ... "
- # Try resident gunzip first; if this fails try ungzipper in package.
- for u in gunzip "$d/funzip" "$d/gunzip";do
- e=`("$u" <"$p.tar.gz" | compress -f >"$p.tar.Z")2>&1`
- [ -z "$e" ] && break
- done
- [ -z "$e" ] || { $E "FAILED -- $e."; exit 1; }
-
- $E OK.
- !!!pre
-
- sed "$SUBSTS" >"$builddir/$pkgname.post_install" <<\!!!post
-
- # Determine working directory used by Installer.
- # (Its contents are copied to /NextLibrary/Receipts)
- wd=`echo "$0"|sed 's:[^/]*$::;s://*$::'`
- case "$wd" in #((
- /tmp/*|/private/tmp/*) ;;
- *) wd=/tmp
- esac
- wp="$wd/$n"
-
- # Go cleanup the temporary compressed archive.
- rm -f "$t"
-
- size=`sed -n 's/^realCompressedSize \(.*\)/\1/p' "$wp.sizes" 2>/dev/null`
- [ -n "$size" ] && {
- rm -f "$wp.sizes"
-
- # Restore original values in *.sizes
- sed 's/^\(CompressedSize\).*/\1 '"$size"'/
- /^realCompressedSize/d' "$p.sizes" >"$wp.sizes"
- }
-
- # Replace gzip_package pre_ and post_install with the real scripts.
- for i in pre_install post_install
- do
- rm -f "$wp.$i"
- [ -f "$d/real_$i" ] && cp -p "$d/real_$i" "$wp.$i"
- done
-
- # Now continue with the real post_install script if there is any.
- [ -f "$wp.post_install" ] && exec "$wp.post_install" "$@"
-
- echo OK.
- !!!post
-
- chmod 555 "$builddir/$pkgname.pre_install" "$builddir/$pkgname.post_install"
-
- # We're finished building the gzipped package.
-
- # Check if it's worth replacing the original package with it.
- gzpackagesize=`DirUsage "$builddir"`
-
- case "$minsavings" in #(((
- [0-9]% | [1-9][0-9]% )
- i=`expr $minsavings : '\(.*\)%'`
- scaledpackagesize=`expr \( 100 - $i \) \* $packagesize / 100`
- ;;
- 0 | "" )
- scaledpackagesize=$packagesize
- ;;
- * )
- scaledpackagesize=`expr $packagesize - $minsavings`
- esac
-
- saves=`expr $packagesize - $gzpackagesize`
- case "$saves" in #((
- -*)
- expands=`expr "$saves" : "-\(.*\)"`
- mesg="would expand $expands kbytes (`expr $expands \* 100 / $packagesize`%)"
- ;;
- *)
- mesg=" $saves kbytes (`expr $saves \* 100 / $packagesize`%)"
- if [ $gzpackagesize -lt $scaledpackagesize ]; then
- mesg="saves $mesg"
- else
- mesg="would save $mesg, if not for --save=$minsavings"
- fi
- esac
-
- [ "$quiet" ] ||
- {
- [ "$verbose" ] && echo -n "$pkgdir: "
- echo "$mesg"
- }
-
- [ $gzpackagesize -lt $scaledpackagesize ] ||
- { BailOut 0; continue; }
-
- # Update *.sizes, store original CompressedSize with key `realCompressedSize'
- sed 's/^\(CompressedSize\).*/\1 '`expr $CompressedSize - $saves`'/
- $a\
- realCompressedSize '$CompressedSize \
- "$builddir/real_sizes" >"$builddir/$pkgname.sizes"
- rm -f $builddir/real_sizes
-
- # Now, finally, replace the target package with the gzipped one.
- ReplaceTarget
-
- BailOut 0
-
- done
-
- exit $status
-
- #======================================================================
- # $Log: gzip_package.sh,v $
- # Revision 2.7 1998/03/04 19:53:50 tom
- # (pre_install): bugfix: redirect stderr from gunzip shell into error string
- # so retrying funzip works.
- #
- # Revision 2.6 1997/11/09 13:35:11 tom
- # post_install template: avoid spurious warnings when invoked from outside
- # Installer.app.
- #
- # Revision 2.5 1996/12/21 14:15:52 tom
- # (WipeDir): new function; use it instead of rm -rf.
- # (BailOut): set status from argument first, to avoid collision with WipeDir in onexit.
- # (ReplaceTarget): add -p to extracting tar; errors to /dev/null.
- # - some comment fixes; remove obsolete debugging comments.
- #
- # Revision 2.4 1996/11/15 22:19:15 tom
- # (diskFreeSpace): yet another NFS-mount fix.
- #
- # Revision 2.3 1996/02/28 20:29:45 tom
- # (SUBSTS): add trailing newline to make it work with GNU sed v?.??
- # [as reported by Gregor Hoffleit <flight@mathi.uni-heidelberg.de>]
- #
- # Revision 2.2 1995/12/15 14:32:51 tom
- # Added -i, --info option and functionality;
- # Fixed bug that crashed gzip_package when the package it worked on
- # was located on an NFS-mounted volume.
- #
- # Revision 2.1 1995/07/31 12:14:59 tom
- # Fix bug in package expansion message.
- #
- # Revision 2.0 1995/07/16 12:01:36 tom
- # (options): added -h --help; allow multiple package arguments;
- # (pre_install): improved error detection, preserve comments;
- # (post_install): preserve comments.
- #
- # Revision 1.7 1995/03/31 15:11:21 tom
- # First public release.
- #
- # Revision 1.6 1995/01/19 23:10:58 tom
- # fix bug in funzip uuextraction.
- #
- # Revision 1.5 1995/01/01 15:07:24 tom
- # rename to gzip_package.sh; extract funzip from uuencoded version appended
- # to the final gzip_package script.
- #
- # Revision 1.4 1994/12/30 20:09:39 tom
- # fix typos: s/strip gunzip/strip funzip/; s/work_prefix/workprefix/.
- #
- # Revision 1.3 1994/12/23 14:18:01 tom
- # (USAGE): add -u --unzip option, determine its default value from $0;
- # (ReplaceTarget): new function, handles final update of target package;
- # adjust *.sizes table to reflect new archive size, store original size with
- # realCompressedSize key; NEW: handle uncompression;
- # (proto post_install): carefully restore original package state, i.e., replace
- # gzip_package generated *_install scripts with the real ones (if any) in the
- # work directory, also restore *.sizes table to its original pre-gzip_packaged
- # state.
- #
- # Revision 1.2 1994/09/23 10:09:05 tom
- # hammer out the bugs in installer script prototypes.
- #
- # Revision 1.1 1994/09/23 08:07:43 tom
- # Initial revision
- #
- #======================================================================
-