Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a pre-extract script (issue #242) #325

Merged
merged 4 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ makeself.sh [args] archive_dir file_name label startup_script [script_args]
* **`--follow`** : Follow the symbolic links inside of the archive directory, i.e. store the files that are being pointed to instead of the links themselves.
* **`--append`** _(new in 2.1.x)_: Append data to an existing archive, instead of creating a new one. In this mode, the settings from the original archive are reused (compression type, label, embedded script), and thus don't need to be specified again on the command line.
* **`--header`** : Makeself uses a separate file to store the header stub, called `makeself-header.sh`. By default, it is assumed that it is stored in the same location as makeself.sh. This option can be used to specify its actual location if it is stored someplace else.
* **`--preextract`** : Specify a pre-extraction script. The script is executed with the same environment and initial `script_args` as `startup_script`.
* **`--cleanup`** : Specify a script that is run when execution is interrupted or finishes successfully. The script is executed with the same environment and initial `script_args` as `startup_script`.
* **`--copy`** : Upon extraction, the archive will first extract itself to a temporary directory. The main application of this is to allow self-contained installers stored in a Makeself archive on a CD, when the installer program will later need to unmount the CD and allow a new one to be inserted. This prevents "Filesystem busy" errors for installers that span multiple CDs.
* **`--nox11`** : Disable the automatic spawning of a new terminal in X11.
Expand Down
40 changes: 39 additions & 1 deletion makeself-header.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ scriptargs="$SCRIPTARGS"
cleanup_script="${CLEANUP_SCRIPT}"
licensetxt="$LICENSE"
helpheader="${HELPHEADER}"
preextract="${PREEXTRACT_ENCODED}"
targetdir="$archdirname"
filesizes="$filesizes"
totalsize="$totalsize"
Expand Down Expand Up @@ -164,7 +165,8 @@ Makeself version $MS_VERSION
\$0 --lsm Print embedded lsm entry (or no LSM)
\$0 --list Print the list of files in the archive
\$0 --check Checks integrity of the archive
\$0 --verify-sig key Verify signature agains a provided key id
\$0 --verify-sig key Verify signature against a provided key id
\$0 --show-preextract Print pre-extraction script

2) Running \$0 :
\$0 [options] [--] [additional arguments to embedded script]
Expand Down Expand Up @@ -305,6 +307,31 @@ MS_Check()
fi
}

MS_Preextract()
{
if test -z "\$preextract"; then
return
elif test x"\$verbose" = xy; then
MS_Printf "About to run pre-extraction script ... Proceed ? [Y/n] "
read yn
if test x"\$yn" = xn; then
eval \$finish; exit 1
fi
fi

prescript=\`mktemp "\$tmpdir/XXXXXX"\`
echo "\$preextract" | base64 -d > "\$prescript"
chmod a+x "\$prescript"

(cd "\$tmpdir"; eval "\"\$prescript\" \$scriptargs \"\\\$@\""); res=\$?

rm -f "\$prescript"
if test \$res -ne 0; then
echo "Pre-extraction script returned an error code (\$res)" >&2
eval \$finish; exit 1
fi
}

MS_Decompress()
{
if test x"\$decrypt_cmd" != x""; then
Expand Down Expand Up @@ -456,13 +483,22 @@ EOLSM
shift 2 || { MS_Help; exit 1; }
MS_Verify_Sig "\$0"
;;
--show-preextract)
if test -z "\$preextract"; then
echo "Pre-extraction script is not provided." >&2
exit 1
fi
echo "\$preextract" | base64 -d
exit 0
;;
--confirm)
verbose=y
shift
;;
--noexec)
script=""
cleanup_script=""
preextract=""
shift
;;
--noexec-cleanup)
Expand Down Expand Up @@ -623,6 +659,8 @@ if test x"\$SETUP_NOCHECK" != x1; then
fi
offset=\`head -n "\$skip" "\$0" | wc -c | sed "s/ //g"\`

MS_Preextract "\$@"

if test x"\$verbose" = xy; then
MS_Printf "About to extract $USIZE KB in \$tmpdir ... Proceed ? [Y/n] "
read yn
Expand Down
3 changes: 3 additions & 0 deletions makeself.1
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ Specify location of the header script.
.B --help-header file
Add a header to the archive's help output.
.TP
.B --preextract file
Specify a pre-extraction script.
.TP
.B --cleanup file
Specify a cleanup script that executes on interrupt and when finished successfully.
.TP
Expand Down
7 changes: 7 additions & 0 deletions makeself.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ MS_Usage()
echo " --nocrc : Don't calculate a CRC for archive"
echo " --sha256 : Compute a SHA256 checksum for the archive"
echo " --header file : Specify location of the header script"
echo " --preextract file : Specify a pre-extraction script"
echo " --cleanup file : Specify a cleanup script that executes on interrupt and when finished successfully."
echo " --follow : Follow the symlinks in the archive"
echo " --noprogress : Do not show the progress during the decompression"
Expand Down Expand Up @@ -311,6 +312,12 @@ do
HEADER="$2"
shift 2 || { MS_Usage; exit 1; }
;;
--preextract)
preextract_file="$2"
shift 2 || { MS_Usage; exit 1; }
test -r "$preextract_file" || { echo "Unable to open pre-extraction script: $preextract_file" >&2; exit 1; }
PREEXTRACT_ENCODED=`base64 "$preextract_file"`
;;
--cleanup)
CLEANUP_SCRIPT="$2"
shift 2 || { MS_Usage; exit 1; }
Expand Down
98 changes: 98 additions & 0 deletions test/preextracttest
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash
set -eu
THIS="$(readlink -f "$0")"
THISDIR="$(dirname "${THIS}")"
SUT="$(dirname "${THISDIR}")/makeself.sh"

setUp() {
temp=$(mktemp -d -t XXXXX)
pushd "${temp}"
mkdir src
echo "echo This is a test" > src/startup.sh
chmod a+x src/startup.sh
}

tearDown() {
popd
rm -rf "${temp}"
}

testPreextractOpts() {
echo 'echo A complex pre-extraction script.
sleep 99 &
cat a.txt 2>/dev/null || cat b.txt && cat c.txt
echo "$$ Some\toutput\n\a\b\0777 $var1 ${var2} `cat var3.txt` $(env)" > text.txt
' > preextract.sh

${SUT} --nox11 --preextract preextract.sh src src.sh alabel ./startup.sh
assertEquals 0 $?

./src.sh --show-preextract > show-preextract.out
assertEquals 0 $?

diff preextract.sh show-preextract.out
assertEquals 0 $?
}

testWithNoPreextractOpts() {
${SUT} src src.sh alabel ./startup.sh
assertEquals 0 $?

./src.sh --show-preextract
assertEquals 1 $?
}

testPreextractRun() {
echo 'echo Validating provided options...' > preextract.sh
${SUT} --nox11 --preextract preextract.sh src src.sh alabel ./startup.sh
assertEquals 0 $?

./src.sh
assertEquals 0 $?

./src.sh | grep -qF 'Validating provided options...'
assertEquals 0 $?
}

testPreextractNoexec() {
echo 'exit 2' > preextract.sh
${SUT} --preextract preextract.sh src src.sh alabel ./startup.sh
assertEquals 0 $?

./src.sh
assertEquals 1 $?

./src.sh --noexec
assertEquals 0 $?
}

testPreextractArgs() {
echo 'echo $*' > preextract.sh
${SUT} --nox11 --preextract preextract.sh src src.sh alabel ./startup.sh --logdir /var/log
assertEquals 0 $?

test_cmd='./src.sh -- --env dev'

eval "${test_cmd}"
assertEquals 0 $?

eval "${test_cmd}" | grep -qF -- '--logdir /var/log --env dev'
assertEquals 0 $?
}

testPreextractEnvPassing() {
# imitate user input
echo 'echo "export INSTALLATION_DIR=/usr/bin" > preextract.env' > preextract.sh
echo '. ./preextract.env; echo $INSTALLATION_DIR' > src/startup.sh
${SUT} --nox11 --preextract preextract.sh src src.sh alabel ./startup.sh
assertEquals 0 $?

./src.sh
assertEquals 0 $?

./src.sh | grep -qF '/usr/bin'
assertEquals 0 $?
}

# Load and run shUnit2.
source "./shunit2/shunit2"