pkgsrc/mk/extract/extract

367 lines
9.5 KiB
Bash
Executable file

#!/bin/sh
#
# $NetBSD: extract,v 1.21 2022/01/06 10:30:50 schmonz Exp $
#
# Copyright (c) 2006 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Johnny C. Lam.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
######################################################################
#
# NAME
# extract -- extract distfile, regardless of format
#
# SYNOPSIS
# extract [options] distfile [file ...]
#
# DESCRIPTION
# extract will unpack the contents of the named distfile into the
# current working directory. If any optional files are specified then
# only they will be extracted from the distfile, provided that the
# underlying tool supports this ability. If the distfile's file
# extension doesn't match any known archive format's, then the
# distfile is simply copied into the current working directory. If
# "-" is given as the distfile, then standard input is used as the
# contents of the archive, provided that the underlying tool supports
# this ability.
#
# OPTIONS
# -c format Force interpretation of the distfile's compression
# format to be the specified format. Valid formats
# are: gzip, bzip, compress, and none.
#
# -d dir Extract the files into the specified dir instead
# of the current working directory. If the directory
# doesn't exist, then it is created along with any
# intermediate directories using the current umask.
#
# -f format Force interpretation of the distfile's archive
# format to be the specified format.
#
# -t tarprog This specifies the tool to use to extract tar/ustar
# archives, and may be either "tar" or "pax", or the
# full path to the program.
#
# -X excludefile excludefile is a list of file patterns to exclude
# from extraction. If the -X option is specified
# then any optional files listed on the command line
# are ignored.
#
# -x This causes the optional files listed on the
# command line to be excluded from extraction,
# provided the underlying tool supports this
# ability.
#
# ENVIRONMENT
# EXTRACT_OPTS_BIN
# EXTRACT_OPTS_LHA
# EXTRACT_OPTS_PAX
# EXTRACT_OPTS_RAR
# EXTRACT_OPTS_RPM
# EXTRACT_OPTS_TAR
# EXTRACT_OPTS_ZIP
# EXTRACT_OPTS_ZSTD
# EXTRACT_OPTS_ZOO
# These variables set additional arguments passed to the
# underlying extraction tool to unpack their respective
# archive formats.
#
######################################################################
set -e # exit on errors
set -u # treat undefined variables as errors
: ${BZCAT:=bzcat}
: ${CAT:=cat}
: ${CP:=cp}
: ${ECHO:=echo}
: ${GEM:="gem unpack"}
: ${GZCAT:="gzip -cd"}
: ${LHA:=lha}
: ${LZCAT:="lzip -cd"}
: ${MKDIR:=mkdir}
: ${PAX:=pax}
: ${RM:=rm}
: ${RPM2PKG:=rpm2pkg}
: ${SH:=sh}
: ${TAR:=tar}
: ${TEST:=test}
: ${UNRAR:=unrar}
: ${UNZIP_CMD:=unzip}
: ${UNZOO:=unzoo}
: ${P7ZA:="7za x"}
: ${P7ZA_SO:="7za x -so"}
: ${ZSTD:="zstd"}
: ${TMPDIR:=/tmp}
self="${0##*/}"
usage() {
${ECHO} 1>&2 "usage: $self [-c format] [-d dir] [-f format] [-t tarprog] [-X excludefile | -x] distfile [file ...]"
}
exclude=no
exclude_file=
exclude_flag=
extract_dir=.
extract_using=tar
format=
cformat=
# Process optional arguments
while ${TEST} $# -gt 0; do
case "$1" in
-c) cformat="$2"; shift 2 ;;
-d) extract_dir="$2"; shift 2 ;;
-f) format="$2"; shift 2 ;;
-t) extract_using="$2"; shift 2 ;;
-X) exclude_file="$2"; shift 2 ;;
-x) exclude=yes; shift ;;
--) shift; break ;;
-?*) ${ECHO} 1>&2 "$self: unknown option -- ${1#-}"
usage
exit 1
;;
*) break ;;
esac
done
case "$extract_using" in
/*tar|/*pax) tarprog="$extract_using" ;;
*tar) tarprog="${TAR}" ;;
*pax) tarprog="${PAX}" ;;
*) tarprog="${TAR}" ;;
esac
if ${TEST} -n "$exclude_file" -a ! -f "$exclude_file"; then
${ECHO} 1>&2 "$self: exclude file missing: $exclude_file"
exit 1
fi
# Process required arguments
${TEST} $# -gt 0 || { usage; exit 1; }
distfile="$1"; shift
# Make distfile an absolute path, because we will change the current
# directory soon.
case "$distfile" in
/*) ;;
*) distfile=`exec pwd`/"$distfile"
;;
esac
# Derive the compression format of the archive based on the file extension.
case "$distfile" in
*.gz|*.tgz|*.z|*.crate) _cformat=gzip ;;
*.7z) _cformat=7z ;;
*.bz2|*.tbz|*.tbz2|*.bz) _cformat=bzip ;;
*.lz) _cformat=lzip ;;
*.lzma) _cformat=lzma ;;
*.xz|*.txz) _cformat=xz ;;
*.Z) _cformat=compress ;;
*) _cformat=none ;;
esac
${TEST} -n "$cformat" || cformat="$_cformat"
# Derive the command to decompress the file and write the contents to
# stdout, based on the file extension.
#
case "$cformat" in
gzip|compress) decompress_cat="${GZCAT}" ;;
7z) decompress_cat="${P7ZA_SO}" ;;
bzip) decompress_cat="${BZCAT}" ;;
lzip) decompress_cat="${LZCAT}" ;;
lzma) decompress_cat="${XZCAT}" ;;
xz) decompress_cat="${XZCAT}" ;;
none) decompress_cat="${CAT}" ;;
*) decompress_cat="${CAT}" ;;
esac
# Derive the format of the archive based on the file extension.
case "$distfile" in
*.tar.gz|*.tgz|*-tar.gz|*_tar.gz|*.tar.bz2|*.txz|*.tbz|*.tbz2|*.tar.lz|*.tar.lzma|*.tar.xz|*.tar.Z|*.tar.z|*.tar|*.tar.bz|*.tar.7z|*.tar.zst|*.crate)
_format=tar ;;
*.cpio|*.cpio.gz|*.cpio.bz2)
_format=cpio ;;
*.shar.gz|*.shar.bz2|*.shar.Z|*.shar|*.shr.gz|*.shr.bz2|*.shr.Z|*.shr)
_format=shar ;;
*.zip|*.ZIP) _format=zip ;;
*.lha|*.lzh) _format=lha ;;
*.Z|*.bz2|*.gz|*.z)
_format=compressed ;;
*.zoo) _format=zoo ;;
*.rar) _format=rar ;;
*.rpm) _format=rpm ;;
*.bin|*.sh) _format=jre-bin ;;
*.gem) _format=gem ;;
*.7z) _format=7z ;;
*.zst) _format=zstd ;;
*) _format=none ;;
esac
${TEST} -n "$format" || format="$_format"
case "$format" in
tar|shar) ;;
*) if ${TEST} "$distfile" = "-"; then
${ECHO} 1>&2 "$self: archive format cannot be given on standard input -- $format"
exit 1
fi
;;
esac
${TEST} -d "$extract_dir" || ${MKDIR} -p "$extract_dir"
cd "$extract_dir"
# Use the correct tool and extraction procedure to perform the extraction
# based on the archive format.
#
case "$format" in
tar)
case "$extract_using" in
*pax)
: ${EXTRACT_OPTS_PAX=}
case "$extract_using" in
/*) paxprog="$extract_using" ;;
*) paxprog="${PAX}" ;;
esac
if ${TEST} -n "$exclude_file"; then
exclude=yes
set -- dummy `${CAT} "$exclude_file"`; shift
fi
${TEST} "$exclude" = no || exclude_flag="-c"
$decompress_cat "$distfile" |
$paxprog ${EXTRACT_OPTS_PAX} $exclude_flag -O -r ${1+"$@"}
;;
*tar)
: ${EXTRACT_OPTS_TAR=}
case "$extract_using" in
/*) tarprog="$extract_using" ;;
*) tarprog="${TAR}" ;;
esac
tmpfile=
if ${TEST} "$exclude" = "yes"; then
tmpfile="${TMPDIR}/$self.$$"
${RM} -f "$tmpfile"
trap "\${RM} -f \"\$tmpfile\"" 0
for i in ${1+"$@"}; do
${ECHO} "$i" >> "$tmpfile"
done
exclude_file="$tmpfile"
fi
if ${TEST} -n "$exclude_file"; then
exclude_flag="-X $exclude_file"
set -- dummy; shift
fi
$decompress_cat "$distfile" |
$tarprog ${EXTRACT_OPTS_TAR} $exclude_flag -xf - ${1+"$@"}
;;
*)
${ECHO} 1>&2 "$self: unknown tar program: $extract_using"
exit 1
esac
;;
cpio)
: ${EXTRACT_OPTS_PAX=}
if ${TEST} -n "$exclude_file"; then
exclude=yes
set -- dummy `${CAT} "$exclude_file"`; shift
fi
${TEST} "$exclude" = no || exclude_flag="-c"
$decompress_cat "$distfile" |
${PAX} ${EXTRACT_OPTS_PAX} $exclude_flag -r ${1+"$@"}
;;
shar)
$decompress_cat "$distfile" | ${SH}
;;
zip)
: ${EXTRACT_OPTS_ZIP=-aqo}
${TEST} "$exclude" = "no" || exclude_flag="-x"
if ${TEST} -n "$exclude_file"; then
set -- dummy `${CAT} "$exclude_file"`; shift
fi
${UNZIP_CMD} ${EXTRACT_OPTS_ZIP} "$distfile" $exclude_flag ${1+"$@"}
;;
lha)
: ${EXTRACT_OPTS_LHA=q}
${LHA} x${EXTRACT_OPTS_LHA} "$distfile" ${1+"$@"}
;;
compressed)
target="${distfile##*/}"; target="${target%.*}"
$decompress_cat "$distfile" > "$target"
;;
zoo)
: ${EXTRACT_OPTS_ZOO=}
${UNZOO} -x ${EXTRACT_OPTS_ZOO} "$distfile" ${1+"$@"}
;;
rar)
: ${EXTRACT_OPTS_RAR=-inul}
${UNRAR} x ${EXTRACT_OPTS_RAR} "$distfile" ${1+"$@"}
;;
rpm)
: ${EXTRACT_OPTS_RPM=}
${RPM2PKG} -d . ${EXTRACT_OPTS_RPM} "$distfile" ${1+"$@"}
;;
jre-bin)
: ${EXTRACT_OPTS_BIN=}
${ECHO} yes | "$distfile" ${EXTRACT_OPTS_BIN} >/dev/null
;;
gem)
${GEM} "$distfile"
;;
7z)
${P7ZA} "$distfile"
;;
zst)
: ${EXTRACT_OPTS_ZSTD=}
${ZSTD} -d ${EXTRACT_OPTS_ZSTD} "$distfile" ${1+"$@"}
;;
none)
# By default, copy the distfile over to the current working directory.
${CP} "$distfile" .
;;
*)
${ECHO} 1>&2 "$self: archive format not recognized -- $format"
exit 1
;;
esac
exit 0