This is gzip_package.sh in view mode; [Download] [Up]
#!/bin/sh
#+++
# RCS $Id: gzip_package.sh,v 2.5 1996/12/21 14:15:52 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--1996 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.5 $"`
Date=`Clean "$Date: 1996/12/21 14:15:52 $"`
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"`
[ -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"`
[ -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.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
#
#======================================================================
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.