This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] jar shell script (was Re: Patch: Remove fastjar)


Paolo Bonzini wrote:
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.

Or more like this, for which I tested creation and not only extraction...


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 () {
  if test -z "$JARTMP"; then
    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"'
  fi
}

# 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 () {
  change=false
  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 "$file"; then
	      ln "$file" "$JARTMP"/files/"$file" || cp "$file" "$JARTMP"/files/"$file"
	    elif test -d "$file"; then
	      $mkdir_p "$JARTMP"/files/"$file"
	    else
	      error "$arg": Invalid file type.
	    fi
	  done
	elif test -e "$arg"; then
	  error "$arg": Invalid file type.
	else
	  error "$arg": File not found.
	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
    test "$jarfile" = "$tmp_jarfile" || 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
test -z "$JARTMP" || rm -rf "$JARTMP"
exit $EXITCODE

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]