| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- #!/usr/bin/env bash
- sharxz(){
- TAR_OPTIONS=()
- CHDIR=""
- CMD=""
- ARGS=()
- OUTPUT="-"
- DEBUG=false
- PARSE=false
- ADD_PARSER=false
- KEEP=false
- INTERACTIVE=false
- INSTALL_DIR=""
- while getopts ":dikpPI:T:o:C:x:" opt; do
- case $opt in
- d )
- DEBUG=true
- ;;
- i )
- INTERACTIVE=true
- ;;
- k )
- KEEP=true
- ;;
- p )
- PARSE=true
- ;;
- P )
- ADD_PARSER=true
- ;;
- I )
- INSTALL_DIR="$OPTARG"
- ;;
- T )
- TAR_OPTIONS+=( $OPTARG )
- ;;
- o )
- OUTPUT="$OPTARG"
- ;;
- C )
- CHDIR="$OPTARG"
- ;;
- x )
- CMD="$OPTARG"
- ;;
- \? ) cat 1>&2 <<'USAGEEOF'
- Usage: sharxz [-dikp] [-I INSTALL_DIR] [-T TAR_OPTIONS] [-C CHRDIR] [-x CMD] INFILE
- -d DEGUG
- -i Interactive mode
- -k Keep Install Directory after exit
- -p Parse .sharxz contents (env, excluded)
- -P Add Parser to sharxz (for unpack settings, pass args after --)
- -T Options passed on to "tar c $TAR_OPTIONS"
- -I Preset Install Directory
- -C change directory to CHDIR, defaults to parent of INFILE
- -X execute CMD instead of INFILE after unpacking
- INFILE file to be executed on unpack.
- USAGEEOF
- exit 1
- ;;
- : )
- echo "Invalid option: $OPTARG requires an argument" 1>&2
- exit 1
- ;;
- esac
- done
- shift $((OPTIND -1))
- INFILE=$1
- shift 1
- [ "$1" == "--" ] && shift 1 && ARGS+=( "$@" ) && shift $#
- [ ! -z "$1" ] && OUTPUT="$1" && shift 1
- ARGS+=( "$@" ) && shift $#
- [ "$OUTPUT" == "-" ] && OUTPUT="/dev/stdout"
- [ "$CHDIR" == "" ] && [ -d "$INFILE" ] &&
- CHDIR="$INFILE"
- [ "$CHDIR" == "" ] &&
- CHDIR="$(dirname $INFILE)"
- [ ! -f "$INFILE" ] && [ ! -d "$CHDIR" ] &&
- echo "Error: INFILE: $INFILE is not a file, and CHDIR: $CHDIR is not a directory" 1>&2 && exit 1
- [ -z "$CMD" ] && [ ! -f "$INFILE" ] &&
- echo "Error: $INFILE is not a file, and no CMD was given" 1>&2 && exit 1
- [ -z "$CMD" ] &&
- CMD="./$(realpath "--relative-to=$CHDIR" "$INFILE")"
- $DEBUG && echo "CMD: $CMD" 1>&2
- {
- MYPWD="$PWD"
- cd "$CHDIR"
- $DEBUG && du -sh . 1>&2
- $PARSE && parse_options
- print_shar "$INFILE"
- cd "$MYPWD"
- } > "$OUTPUT"
- [[ "$OUTPUT" == "~/dev" ]] || chmod +x "$OUTPUT"
- }
- parse_options(){
- [ -f .sharxz/env ] && source .sharxz/env
- [ -f .sharxz/exclude ] && while read -r line; do
- local OPTION="$(trim "$line")"
- [ -z "$OPTION" ] && continue
- [[ $OPTION == \#* ]] && continue
- $DEBUG && echo "Excluding: $line" 1>&2
- TAR_OPTIONS+=( "--exclude=$OPTION" )
- done < .sharxz/exclude
- }
- print_shar(){
- printf "#!/usr/bin/env bash\n\nset -e\n"
- printf "DEBUG=$DEBUG\n"
- printf "KEEP=$KEEP\n"
- printf "INTERACTIVE=$INTERACTIVE\n"
- printf "INSTALL_DIR=\"$INSTALL_DIR\"\n\n"
- $ADD_PARSER && printf -- "$SHARPARSER\n"
- printf -- "$PREPSHAR\n\n"
- printf -- "$UNSHAR\n\n"
- $DEBUG && pwd 1>&2
- $DEBUG && set -x
- tar -c ${TAR_OPTIONS[@]} .| xz -c -3 -T 0 | base64 -w 0
- $DEBUG && set +x
- printf -- "\n$SETUPSHAR\n"
- printf -- "$CMD ${ARGS[@]}"' "$@"'"\n"
- printf -- "\n$CLEANUPSHAR\n"
- }
- trim() {
- local var="$*"
- # remove leading whitespace characters
- var="${var#"${var%%[![:space:]]*}"}"
- # remove trailing whitespace characters
- var="${var%"${var##*[![:space:]]}"}"
- printf '%s' "$var"
- }
- read -r -d '' SHARPARSER <<'SHARPARSEREOF'
- while getopts ":diI:-" opt; do
- case $opt in
- d )
- DEBUG=true
- ;;
- i )
- INTERACTIVE=true
- ;;
- I )
- INSTALL_DIR="$OPTARG"
- ;;
- - )
- break
- ;;
- \? ) cat 1>&2 <<'USAGEEOF'
- Usage: <sharxz> [-di] [-I INSTALL_DIR]
- -d DEGUG
- -i Interactive mode
- -I Preset Install Directory
- -- stop parsing and pass remaining arguments
- USAGEEOF
- exit 1
- ;;
- : )
- echo "Invalid option: $OPTARG requires an argument" 1>&2
- exit 1
- ;;
- esac
- done
- shift $((OPTIND -1))
- SHARPARSEREOF
- read -r -d '' PREPSHAR <<'PREPSHAREOF'
- REQUIREMENTS=(
- "xz"
- "tar"
- "base64"
- "mkfifo"
- "mktemp"
- )
- for REQ in "${REQUIREMENTS[@]}"; do
- [ -x "$(which $REQ 2> /dev/null)" ] || { echo "This sharxz needs $REQ in PATH." 1>&2 && exit 1; }
- done
- $DEBUG && set -x
- cleanup(){
- EXITCODE=$?
- rm -f "$FIFO_NAME"
- $KEEP || rm -r "$INSTALL_DIR"
- exit $EXITCODE
- }
- FIFO_NAME=$(mktemp -u).fifo
- mkfifo "$FIFO_NAME"
- [ -z "$INSTALL_DIR" ] && INSTALL_DIR="$(mktemp -d)"
- $INTERACTIVE && echo "INSTALL_DIR: [ $INSTALL_DIR ]" && read INSTALL_DIR
- [ -z "$INSTALL_DIR" ] && exit 1
- [ -d "$INSTALL_DIR" ] || mkdir -p "$INSTALL_DIR" || exit 1
- trap cleanup EXIT
- PREPSHAREOF
- read -r -d '' UNSHAR <<'UNSHAREOF'
- cat "$FIFO_NAME"|base64 -d |xz -d -T 0 |tar -xC "$INSTALL_DIR" &
- cat <<PAYLOADEOF > "$FIFO_NAME"
- UNSHAREOF
- read -r -d '' SETUPSHAR <<'SETUPSHAREOF'
- PAYLOADEOF
- wait
- rm "$FIFO_NAME"
- cd "$INSTALL_DIR"
- set +e
- $DEBUG && pwd 1>&2
- SETUPSHAREOF
- read -r -d '' CLEANUPSHAR <<'CLEANUPSHAREOF'
- CLEANUPSHAREOF
- [[ "${BASH_SOURCE[0]}" != "${0}" ]] && export -f sharxz || sharxz "$@"
|