Files

220 lines
6.0 KiB
Bash
Raw Permalink Normal View History

2026-09-23 17:19:50 +02:00
#!/usr/bin/env bash
set -Eeuo pipefail
die() {
printf 'ERROR: %s\n' "$*" >&2
exit 1
}
2026-10-11 16:45:57 +02:00
show_help() {
local script_name="$1"
local description="$2"
printf '%s\n' "$description"
printf 'Usage: %s -v|--version <postgresql-version>\n' "$script_name"
printf ' %s <postgresql-version>\n' "$script_name"
printf ' %s --help | -h\n' "$script_name"
}
parse_postgresql_version() {
local version=""
local positional_seen=0
while (($#)); do
case "$1" in
-v|--version)
(($# >= 2)) || die "$1 requires a PostgreSQL version"
[[ -n "$2" ]] || die "PostgreSQL version must not be empty"
[[ -z "$version" ]] || die "PostgreSQL version was specified more than once"
version="$2"
shift 2
;;
--version=*)
[[ -n "${1#*=}" ]] || die "PostgreSQL version must not be empty"
[[ -z "$version" ]] || die "PostgreSQL version was specified more than once"
version="${1#*=}"
shift
;;
-*)
die "unknown option: $1"
;;
*)
(( positional_seen == 0 )) || die "unexpected argument: $1"
[[ -z "$version" ]] || die "PostgreSQL version was specified more than once"
version="$1"
positional_seen=1
shift
;;
esac
done
[[ -n "$version" ]] || die "PostgreSQL version is required"
validate_postgresql_version "$version"
printf '%s\n' "$version"
}
2026-09-23 17:19:50 +02:00
require_tools() {
local tool
for tool in "$@"; do
command -v "$tool" >/dev/null || die "$tool is required"
done
}
validate_postgresql_version() {
local version="$1"
[[ "$version" =~ ^[0-9]+\.[0-9]+([.][0-9]+)?$ ]] ||
die "invalid PostgreSQL version: $version"
}
latest_tag() {
local repository="$1"
local tag
tag="$(
curl -fsSL "https://api.github.com/repos/$repository/releases/latest" |
sed -nE 's/^[[:space:]]*"tag_name":[[:space:]]*"([^"]+)".*/\1/p' |
head -n 1 || true
)"
if [[ -n "$tag" ]]; then
printf '%s\n' "$tag"
return
fi
curl -fsSL "https://api.github.com/repos/$repository/tags?per_page=1" |
sed -nE 's/^[[:space:]]*"name":[[:space:]]*"([^"]+)".*/\1/p' |
head -n 1 || true
}
latest_pgaudit_tag() {
local repository="$1"
local major="$2"
local tag
tag="$(
curl -fsSL "https://api.github.com/repos/$repository/tags?per_page=100" |
sed -nE 's/^[[:space:]]*"name":[[:space:]]*"([^"]+)".*/\1/p' |
grep -E "^${major//./\\.}\." |
head -n 1 || true
)"
printf '%s\n' "${tag:-$(latest_tag "$repository")}"
}
2026-10-20 11:20:10 +02:00
latest_pg_hint_plan_tag() {
local repository="$1"
local major="$2"
local tag
tag="$(
curl -fsSL "https://api.github.com/repos/$repository/tags?per_page=100" |
sed -nE 's/^[[:space:]]*"name":[[:space:]]*"([^"]+)".*/\1/p' |
grep -E "^REL${major}_" |
head -n 1 || true
)"
printf '%s\n' "${tag:-$(latest_tag "$repository")}"
}
2026-09-23 17:19:50 +02:00
reset_staging_dir() {
local staging_dir="$1"
[[ "$staging_dir" != "/" ]] || die "STAGING_DIR must not be the filesystem root"
rm -rf -- "$staging_dir"
mkdir -p "$staging_dir"
}
2026-10-11 16:45:57 +02:00
copy_install_source() {
local source_directory="$1"
local prefix="$2"
local source_name="$3"
local complete_version
complete_version="$(basename -- "$prefix")"
local sources_directory="$SCRIPT_DIR/sources/$complete_version"
local destination="$sources_directory/$source_name"
mkdir -p "$sources_directory"
rm -rf -- "$destination"
cp -a -- "$source_directory" "$destination"
printf '%s\n' "$destination"
}
write_install_recipe() {
local source_directory="$1"
local postgresql_version="$2"
local prefix="$3"
local configure_options="${4:-}"
local recipe="$source_directory/install_$postgresql_version.sh"
{
printf '#!/usr/bin/env bash\n\nset -Eeuo pipefail\n\n'
printf 'SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"\n'
printf 'readonly PREFIX=%q\n' "$prefix"
printf 'readonly POSTGRES_VERSION=%q\n' "$postgresql_version"
printf 'readonly POSTGRES_CONFIGURE_OPTIONS=%q\n' "$configure_options"
cat <<'RECIPE_HEADER'
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
printf 'Re-run the saved installation steps for PostgreSQL %s.\n' "$POSTGRES_VERSION"
printf 'Usage: %s\n' "$0"
printf ' %s --help | -h\n' "$0"
exit 0
fi
[[ $# -eq 0 ]] || {
printf 'Usage: %s [--help|-h]\n' "$0" >&2
exit 2
}
readonly PG_CONFIG="$PREFIX/bin/pg_config"
readonly JOBS="${JOBS:-$(nproc)}"
RECIPE_HEADER
cat
} > "$recipe"
chmod +x "$recipe"
printf 'Saved installation recipe: %s\n' "$recipe"
}
2026-10-25 22:20:39 +01:00
record_source_download() {
local product="$1"
local source_url="$2"
local git_tag="${3:-}"
[[ -n "${SOURCE_MANIFEST:-}" ]] || return 0
printf '%s\t%s\t%s\n' "$product" "$source_url" "$git_tag" >> "$SOURCE_MANIFEST"
}
2026-09-23 17:19:50 +02:00
require_postgresql_installation() {
local prefix="$1"
local pg_config="$prefix/bin/pg_config"
[[ "$prefix" != "/" ]] || die "PREFIX must not be the filesystem root"
[[ -x "$pg_config" ]] || die "PostgreSQL is not installed at $prefix"
}
download_source() {
local staging_dir="$1"
local repository="$2"
local tag="$3"
local archive_name="$4"
local source_dir="$5"
local archive="$staging_dir/$archive_name"
2026-10-25 22:20:39 +01:00
local source_url
source_url="$(github_source_url "$repository" "$tag")"
2026-09-23 17:19:50 +02:00
curl -fL --retry 3 --retry-delay 2 \
-o "$archive" \
2026-10-25 22:20:39 +01:00
"$source_url"
2026-09-23 17:19:50 +02:00
tar -xzf "$archive" -C "$staging_dir"
[[ -d "$source_dir" ]] || die "source directory was not created: $source_dir"
}
2026-10-11 16:45:57 +02:00
2026-10-25 22:20:39 +01:00
github_source_url() {
local repository="$1"
local tag="$2"
printf 'https://github.com/%s/archive/refs/tags/%s.tar.gz\n' "$repository" "$tag"
}
2026-10-11 16:45:57 +02:00
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
printf 'Shared helper functions used by PostgreSQL component installers.\n'
printf 'This file is sourced by the install scripts and does not install a component.\n'
exit 0
fi
printf 'This helper is not an installer; run a component installer with <postgresql-version>.\n' >&2
printf 'Usage: %s --help | -h\n' "$0" >&2
exit 2
fi