This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC] jar shell script (was Re: Patch: Remove fastjar)
I agree that using zip, or even better zlib's minizip (zlib is built for
the host), can be a very good solution for bootstrapping. Another
possibility would be to write "jar" as a shell script wrapper around zip
or minizip. I'm sure that's possible.
Like this (mostly untested) script.
Paolo
#! /bin/sh
# Copyright (C) 2006 Free Software Foundation
# Written by Paolo Bonzini.
#
# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
: ${ZIP=zip}
: ${UNZIP=unzip}
progname="$0"
# Emit a usage message and exit with error status 1
usage () {
cat >&2 <<EOF
Usage: $0 {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C dir] files ...
Options:
-c create new archive
-t list table of contents for archive
-x extract named (or all) files from archive
-u update existing archive
-v generate verbose output on standard output
-f specify archive file name
-m include manifest information from specified manifest file
-0 store only; use no ZIP compression
-M do not create a manifest file for the entries
-i generate index information for the specified jar files
-C change to the specified directory and include the following file
If any file is a directory then it is processed recursively.
The manifest file name and the archive file name needs to be specified
in the same order the 'm' and 'f' flags are specified.
Example 1: to archive two class files into an archive called classes.jar:
jar cvf classes.jar Foo.class Bar.class
Example 2: use an existing manifest file 'mymanifest' and archive all the
files in the foo/ directory into 'classes.jar':
jar cvfm classes.jar mymanifest -C foo/ .
EOF
exit 1
}
# Emit an error message and exit with error status 1
error () {
echo "$progname: $*" >&2
exit 1
}
# Make a temporary directory and store its name in the JARTMP variable.
make_tmp () {
JARTMPSUFF=$$
test -z "$RANDOM" && RANDOM=7654
while :; do
JARTMP=/tmp/tmp-jar.$JARTMPSUFF
$mkdir_p $JARTMP 2>&1 && break
JARTMPSUFF=`expr \( $JARTMPSUFF + $RANDOM \) % 32768`
done
trap 'rm -rf "$JARTMP"'
}
# Usage: make_manifest destfile kind [source-manifest]
# Create a manifest file and store it in destfile. KIND can be auto or user,
# in which case SOURCE-MANIFEST must be specified as well.
make_manifest () {
$mkdir_p `dirname "$1"`
case $2 in
auto)
cat > "$1" <<\EOF
Manifest-Version: 1.0
Created-By: @VERSION@
EOF
;;
user)
cp "$3" "$1"
;;
esac
}
# Usage: set_var var [value]
# Exit with an error if set_var was already called for the same VAR. Else
# set the variable VAR to the value VALUE (or the empty value if no parameter
# is given).
set_var () {
if eval test x\$set_$1 = xset; then
error Incompatible or repeated options.
else
eval $1='"$2"'
eval set_$1=set
fi
}
# Process the arguments, including -C options, and copy the whole tree
# to $JARTMP/files so that zip can be invoked later from there.
make_files () {
for arg
do
if $change; then
change=false
cd "$arg" || exit 1
continue
fi
case "$arg" in
-C)
change=:
;;
-C*)
cd "`expr $arg : '-C\(.*\)' `"
;;
*)
if test -f "$arg"; then
$mkdir_p $JARTMP/files/`dirname "$arg"`
ln "$arg" $JARTMP/files/"$arg" || cp "$arg" $JARTMP/files/"$arg"
elif test -d "$arg"; then
find "$arg" | while read file; do
if test -f "$arg"; then
ln "$arg" $JARTMP/files/"$arg" || cp "$arg" $JARTMP/files/"$arg"
elif test -d "$file"; then
$mkdir_p $JARTMP/files/"$file"
else
error "$arg": Invalid file type.
fi
done
else
error "$arg": Invalid file type.
fi
;;
esac
done
}
# Same as "jar tf $1".
jar_list () {
$UNZIP -l "$1" | \
sed '1,/^ ----/d;/^ ----/,$d;s/^ *[0-9]* ..-..-.. ..:.. //'
}
# Same as "jar tvf $1".
jar_list_verbose () {
$UNZIP -l "$1" | \
awk 'BEGIN { yes = 0 }
/^ ----/ { yes = !yes; next }
yes {
size=$1
split ($2, d, "-")
split ($3, t, ":")
d[3] += (d[3] < 80) ? 2000 : 1900
timestamp=d[3] " " d[2] " " d[1] " " t[1] " " t[2] " 00"
gsub (/^ *[0-9]* ..-..-.. ..:.. /, "")
printf "%6d %s %s\n", size, strftime ("%+", mktime (timestamp)), $0
}'
}
# mkdir -p emulation based on the mkinstalldirs script.
mkdir_p ()
{
for file
do
case $file in
/*) pathcomp=/ ;;
*) pathcomp= ;;
esac
oIFS=$IFS
IFS=/
set fnord $file
shift
IFS=$oIFS
for d
do
test "x$d" = x && continue
pathcomp=$pathcomp$d
case $pathcomp in
-*) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
fi
pathcomp=$pathcomp/
done
done
}
# Detect mkdir -p
# On NextStep and OpenStep, the `mkdir' command does not
# recognize any option. It will interpret all options as
# directories to create, and then abort because `.' already
# exists.
if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
mkdir_p='mkdir -p'
else
mkdir_p='mkdir_p'
test -d ./-p && rmdir ./-p
test -d ./--version && rmdir ./--version
fi
# Process the first command line option.
case "$1" in
-*) commands=`echo X"$1" | sed 's/^X-//' ` ;;
*) commands="$1"
esac
shift
mode=unknown
cur_dir=.
jarfile=
manifest_kind=auto
store=
verbose=false
outredirect=:
while test -n "$commands"; do
command=`expr "$commands" : '\(.\)'`
commands=`expr "$commands" : '.\(.*\)'`
case "$command" in
c)
set_var mode create
;;
t)
set_var mode list
;;
x)
set_var mode extract
;;
u)
set_var mode update
;;
f)
test $# = 0 && usage
# Multiple -f options are accepted by Sun's JAR tool.
jarfile="$1"
shift
;;
m)
test $# = 0 && usage
test "$manifest_kind" = auto && manifest_kind=user
# Multiple -f options are accepted by Sun's JAR tool.
manifest_file="$1"
shift
;;
0)
store=-0
;;
v)
verbose=:
;;
M)
manifest_kind=none
;;
i)
set_var mode index
;;
C)
test $# = 0 && usage
cur_dir="$1"
shift
;;
*)
usage ;;
esac
done
case "$jarfile" in
"")
make_tmp
$mkdir_p $JARTMP/out
jarfile=$JARTMP/out/tmp-stdin.jar
out_redirect='exec >&2'
case $mode in
update|extract|list) cat > $JARTMP/out/tmp-stdin.jar ;;
esac
;;
*/*)
dir=`dirname "$jarfile"`
jarfile=`cd $dir && pwd`/`basename "$jarfile"`
;;
*)
dir=`pwd`
jarfile=`pwd`/`basename "$jarfile"`
;;
esac
# Perform a -C option if given right away.
cd "$cur_dir"
case $mode in
unknown)
usage
;;
extract)
make_tmp
jar_list "$jarfile" > $JARTMP/list
test "$#" = 0 && cp $JARTMP/list $JARTMP/chosen
for arg
do
$skip && skip=false && continue
case "$arg" in
-C) skip=: ;;
-C*) ;;
*)
escaped=`echo "$arg" | sed -n 's/[][.^$\*]/\\&/' `
grep -e "^list/" >> $JARTMP/chosen
grep -e "^list$" >> $JARTMP/chosen
esac
done
if $verbose; then
sort < $JARTMP/chosen | uniq | xargs $UNZIP -o "$jarfile" | \
sed -ne 's/^ creating/ created/p' -e 's/^ inflating/extracted/p'
else
sort < $JARTMP/chosen | uniq | xargs $UNZIP -o "$jarfile" > /dev/null
fi
;;
create)
make_tmp
$mkdir_p $JARTMP/out
$mkdir_p $JARTMP/files
tmp_jarfile=$JARTMP/out/`basename "$jarfile"`
make_files "$@"
if test $manifest_kind != none; then
make_manifest $JARTMP/files/META-INF/MANIFEST.MF $manifest_kind $manifest_file
fi
if $verbose; then
(eval $out_redirect; cd $JARTMP/files && $ZIP -rv "$tmp_jarfile" $store .)
else
(cd $JARTMP/files && $ZIP -r "$tmp_jarfile" $store . > /dev/null)
fi
mv "$tmp_jarfile" "$jarfile"
;;
update)
make_tmp
$mkdir_p $JARTMP/files
make_files "$@"
case $manifest_kind in
none)
$verbose && (eval $out_redirect; echo removing manifest)
$ZIP -d "$jarfile" META-INF/MANIFEST.MF > /dev/null
;;
*)
make_manifest $JARTMP/files/META-INF/MANIFEST.MF $manifest_kind $manifest_file
;;
esac
if $verbose; then
(eval $out_redirect; cd $JARTMP/files && $ZIP -urv "$jarfile" $store .)
else
(cd $JARTMP/files && $ZIP -ur "$jarfile" $store . > /dev/null)
fi
;;
list)
if $verbose; then
jar_list_verbose "$jarfile"
else
jar_list "$jarfile"
fi ;;
index)
;;
esac
EXITCODE=$?
if test $EXITCODE = 0 && \
test -n $JARTMP && test "$jarfile" = $JARTMP/out/tmp-stdin.jar; then
case $mode in
create|update) cat $JARTMP/out/tmp-stdin.jar ;;
esac
fi
exit $EXITCODE