176 lines
5.3 KiB
Bash
Executable File
176 lines
5.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
OUT=${1:-$ROOT/dist/csr-intake-x86_64.run}
|
|
GUI="$ROOT/gui/target/release/intake-gui"
|
|
SCANNER="$ROOT/scanner/target/release/pc-intake"
|
|
MANIFEST="$ROOT/build/release.json"
|
|
BUNDLE_CONFIG=${CSR_BUNDLE_CONFIG_DIR:-$ROOT/.bundle-secrets}
|
|
|
|
for file in "$GUI" "$SCANNER" "$MANIFEST"; do
|
|
[[ -f $file ]] || {
|
|
echo 'Release files are missing. Run bash scripts/build-release.sh first.' >&2
|
|
exit 2
|
|
}
|
|
done
|
|
|
|
BUILD_ID=$(python3 "$ROOT/scripts/release-manifest.py" --source-id)
|
|
GUI_VERSION=$("$GUI" --version)
|
|
grep -qF "$BUILD_ID" <<< "$GUI_VERSION" || {
|
|
echo 'Release binaries are stale. Run bash scripts/build-release.sh first.' >&2
|
|
exit 2
|
|
}
|
|
VERSION=$(sed -E 's/^CS-R Intake ([^ ]+).*/\1/' <<< "$GUI_VERSION")
|
|
|
|
TMP=$(mktemp -d)
|
|
cleanup() {
|
|
find "$TMP" -depth -delete 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
mkdir -p "$TMP/app" "$(dirname "$OUT")"
|
|
install -m755 "$GUI" "$TMP/app/intake-gui"
|
|
install -m755 "$SCANNER" "$TMP/app/pc-intake"
|
|
install -m644 "$MANIFEST" "$TMP/app/release.json"
|
|
python3 "$ROOT/scripts/release-manifest.py" --verify-release "$TMP/app"
|
|
|
|
contains_credentials=0
|
|
if [[ -f $BUNDLE_CONFIG/inventory-api-key && -f $BUNDLE_CONFIG/inventory-server.crt ]]; then
|
|
key=$(tr -d '\r\n' < "$BUNDLE_CONFIG/inventory-api-key")
|
|
[[ -n $key && $key != *[[:space:]]* ]] || {
|
|
echo 'Bundled inventory API key is empty or malformed.' >&2
|
|
exit 2
|
|
}
|
|
openssl x509 -in "$BUNDLE_CONFIG/inventory-server.crt" -noout -checkend 0 >/dev/null || {
|
|
echo 'Bundled inventory certificate is invalid or expired.' >&2
|
|
exit 2
|
|
}
|
|
mkdir -m700 "$TMP/app/default-config"
|
|
install -m600 "$BUNDLE_CONFIG/inventory-api-key" "$TMP/app/default-config/inventory-api-key"
|
|
install -m600 "$BUNDLE_CONFIG/inventory-server.crt" "$TMP/app/default-config/inventory-server.crt"
|
|
printf '%s\n' '{"url":"https://192.168.178.17"}' > "$TMP/app/default-config/inventory.json"
|
|
chmod 600 "$TMP/app/default-config/inventory.json"
|
|
contains_credentials=1
|
|
elif [[ -e $BUNDLE_CONFIG/inventory-api-key || -e $BUNDLE_CONFIG/inventory-server.crt ]]; then
|
|
echo 'Both inventory-api-key and inventory-server.crt are required for bundled configuration.' >&2
|
|
exit 2
|
|
fi
|
|
(
|
|
cd "$TMP/app"
|
|
find . -type f ! -name SHA256SUMS -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
|
|
)
|
|
tar -C "$TMP/app" -czf "$TMP/payload.tar.gz" .
|
|
|
|
cat > "$TMP/launcher" <<EOF
|
|
#!/bin/sh
|
|
set -eu
|
|
BUILD_ID='$BUILD_ID'
|
|
VERSION='$VERSION'
|
|
PAYLOAD_LINE=__PAYLOAD_LINE__
|
|
|
|
cache_root=\${XDG_CACHE_HOME:-\${HOME:-\$PWD}/.cache}/csr-intake
|
|
app_dir=\$cache_root/\$BUILD_ID
|
|
|
|
extract_bundle() {
|
|
bundle_valid() {
|
|
[ -x "\$app_dir/intake-gui" ] && [ -x "\$app_dir/pc-intake" ] &&
|
|
(cd "\$app_dir" && sha256sum -c SHA256SUMS >/dev/null 2>&1)
|
|
}
|
|
if ! bundle_valid; then
|
|
if [ -e "\$app_dir" ]; then
|
|
find "\$app_dir" -depth -delete 2>/dev/null || true
|
|
fi
|
|
temp_dir=\$cache_root/.extract-\$BUILD_ID-\$\$
|
|
mkdir -p "\$temp_dir"
|
|
trap 'find "\$temp_dir" -depth -delete 2>/dev/null || true' EXIT HUP INT TERM
|
|
tail -n +"\$PAYLOAD_LINE" "\$0" | gzip -dc | tar -xf - -C "\$temp_dir"
|
|
(cd "\$temp_dir" && sha256sum -c SHA256SUMS >/dev/null)
|
|
mkdir -p "\$cache_root"
|
|
if ! mv -T "\$temp_dir" "\$app_dir" 2>/dev/null; then
|
|
find "\$temp_dir" -depth -delete 2>/dev/null || true
|
|
fi
|
|
trap - EXIT HUP INT TERM
|
|
fi
|
|
bundle_valid
|
|
}
|
|
|
|
case \${1:-} in
|
|
--version)
|
|
printf 'CS-R Intake %s · %s\n' "\$VERSION" "\$BUILD_ID"
|
|
exit 0
|
|
;;
|
|
--check-bundle)
|
|
extract_bundle
|
|
printf 'Standalone bundle verified: %s\n' "\$BUILD_ID"
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
extract_bundle
|
|
data_dir=\${XDG_DATA_HOME:-\${HOME:-\$PWD}/.local/share}/csr-intake
|
|
expect_data=0
|
|
has_data=0
|
|
for argument in "\$@"; do
|
|
if [ "\$expect_data" -eq 1 ]; then
|
|
data_dir=\$argument
|
|
expect_data=0
|
|
elif [ "\$argument" = '--data' ]; then
|
|
has_data=1
|
|
expect_data=1
|
|
fi
|
|
done
|
|
[ "\$expect_data" -eq 0 ] || {
|
|
echo 'Missing directory after --data.' >&2
|
|
exit 2
|
|
}
|
|
|
|
if [ -d "\$app_dir/default-config" ]; then
|
|
config_dir=\$data_dir/config
|
|
mkdir -p "\$config_dir"
|
|
chmod 700 "\$config_dir"
|
|
for name in inventory.json inventory-api-key inventory-server.crt; do
|
|
target=\$config_dir/\$name
|
|
if [ ! -e "\$target" ]; then
|
|
install -m600 "\$app_dir/default-config/\$name" "\$target"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
workshop_config=\$data_dir/config/workshop.json
|
|
if [ -f "\$workshop_config" ]; then
|
|
keyboard_layout=\$(python3 - "\$workshop_config" <<'PY' 2>/dev/null || true
|
|
import json
|
|
import sys
|
|
layout = json.load(open(sys.argv[1], encoding='utf-8')).get('keyboard_layout', '')
|
|
if layout in ('de', 'us'):
|
|
print(layout)
|
|
PY
|
|
)
|
|
if [ -n "\$keyboard_layout" ]; then
|
|
export XKB_DEFAULT_LAYOUT=\$keyboard_layout
|
|
fi
|
|
fi
|
|
|
|
export CSR_SCANNER="\$app_dir/pc-intake"
|
|
if [ "\$has_data" -eq 1 ]; then
|
|
exec "\$app_dir/intake-gui" "\$@"
|
|
fi
|
|
exec "\$app_dir/intake-gui" "\$@" --data "\$data_dir"
|
|
EOF
|
|
|
|
payload_line=$(( $(wc -l < "$TMP/launcher") + 1 ))
|
|
sed -i "s/__PAYLOAD_LINE__/$payload_line/" "$TMP/launcher"
|
|
cat "$TMP/launcher" "$TMP/payload.tar.gz" > "$OUT"
|
|
if [[ $contains_credentials -eq 1 ]]; then
|
|
chmod 700 "$OUT"
|
|
else
|
|
chmod 755 "$OUT"
|
|
fi
|
|
"$OUT" --check-bundle
|
|
if [[ $contains_credentials -eq 1 ]]; then
|
|
echo "Standalone executable created with inventory configuration: $OUT"
|
|
else
|
|
echo "Standalone executable created: $OUT"
|
|
fi
|