feat: add native fnOS PostgreSQL shared service
This commit is contained in:
Executable
+180
@@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
VERSION=15.1.0
|
||||
PGVECTOR_VERSION=0.8.6
|
||||
PGVECTOR_PACKAGE_VERSION=0.8.6-1.pgdg12%2B1
|
||||
PGVECTOR_SHA256=b27ff894d1e2d23ebd7528fcb986923391977cbd5c5379ed74527875246854ca
|
||||
OUTPUT="${1:-$ROOT_DIR/artifacts/fnos/nxsir-postgresql-${VERSION}-x86_64.fpk}"
|
||||
DOTNET_BIN="${DOTNET:-dotnet}"
|
||||
NUGET_FEED="${POSTGRES_SERVICE_NUGET_FEED:-}"
|
||||
NUGET_PACKAGES="${NUGET_PACKAGES:-$ROOT_DIR/.cache/nuget-packages}"
|
||||
DOTNET_CLI_HOME="${DOTNET_CLI_HOME:-$ROOT_DIR/.cache/dotnet-cli-home}"
|
||||
BUILD_TMP_ROOT="${POSTGRES_SERVICE_BUILD_TMPDIR:-$ROOT_DIR/.cache/fnos-build-tmp}"
|
||||
|
||||
if [ -n "${FNPACK:-}" ]; then
|
||||
FNPACK_BIN="$FNPACK"
|
||||
elif [ -x "$ROOT_DIR/.tools/fnpack" ]; then
|
||||
FNPACK_BIN="$ROOT_DIR/.tools/fnpack"
|
||||
else
|
||||
FNPACK_BIN=fnpack
|
||||
fi
|
||||
FNPACK_BIN=$(command -v "$FNPACK_BIN") || {
|
||||
printf 'fnpack is required; install it from the fnOS developer portal or set FNPACK.\n' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
for command_name in npm apt-get curl dpkg-deb node sha256sum tar find realpath; do
|
||||
command -v "$command_name" >/dev/null 2>&1 || {
|
||||
printf 'required build command is missing: %s\n' "$command_name" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
DOTNET_BIN=$(command -v "$DOTNET_BIN") || { printf 'missing .NET SDK: %s\n' "$DOTNET_BIN" >&2; exit 1; }
|
||||
if [ -n "$NUGET_FEED" ] && [ ! -d "$NUGET_FEED" ]; then
|
||||
printf 'offline NuGet feed does not exist: %s\n' "$NUGET_FEED" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$BUILD_TMP_ROOT" "$(dirname -- "$OUTPUT")"
|
||||
WORK_DIR=$(mktemp -d "${BUILD_TMP_ROOT%/}/postgres-service-fnos-build.XXXXXX")
|
||||
trap 'rm -rf -- "$WORK_DIR"' EXIT
|
||||
STAGE="$WORK_DIR/stage"
|
||||
PACKED_ROOT="$WORK_DIR/packed"
|
||||
FNPACK_TMP_ROOT="$WORK_DIR/fnpack-tmp"
|
||||
RUNTIME_ROOT="$STAGE/app/runtime"
|
||||
EXTRACT_ROOT="$WORK_DIR/runtime-extract"
|
||||
mkdir -p "$STAGE/app/server/wwwroot" "$RUNTIME_ROOT" "$PACKED_ROOT" "$FNPACK_TMP_ROOT" "$EXTRACT_ROOT"
|
||||
cp -a "$ROOT_DIR/fnos-postgresql/." "$STAGE/"
|
||||
|
||||
printf 'Building PostgreSQL management frontend...\n'
|
||||
npm run build:postgres-admin --prefix "$ROOT_DIR/frontend"
|
||||
cp -a "$ROOT_DIR/frontend/dist-postgres/." "$STAGE/app/server/wwwroot/"
|
||||
|
||||
printf 'Publishing self-contained PostgreSQL management API...\n'
|
||||
export NUGET_PACKAGES DOTNET_CLI_HOME
|
||||
restore_args=(-r linux-x64 --source "https://api.nuget.org/v3/index.json" --disable-parallel)
|
||||
if [ -n "$NUGET_FEED" ]; then
|
||||
restore_args+=(--source "$NUGET_FEED")
|
||||
fi
|
||||
"$DOTNET_BIN" restore "$ROOT_DIR/src/PostgresService.WebApi/PostgresService.WebApi.csproj" "${restore_args[@]}"
|
||||
"$DOTNET_BIN" publish "$ROOT_DIR/src/PostgresService.WebApi/PostgresService.WebApi.csproj" \
|
||||
-c Release \
|
||||
-r linux-x64 \
|
||||
--self-contained true \
|
||||
--no-restore \
|
||||
-p:DebugType=None \
|
||||
-p:DebugSymbols=false \
|
||||
-p:PublishSingleFile=false \
|
||||
-p:PublishReadyToRun=false \
|
||||
-o "$STAGE/app/server" \
|
||||
/maxcpucount:1
|
||||
rm -f "$STAGE/app/server/"*.pdb
|
||||
|
||||
printf 'Downloading pinned Debian Bookworm PostgreSQL 15 runtime...\n'
|
||||
APT_ROOT="$WORK_DIR/apt"
|
||||
mkdir -p \
|
||||
"$APT_ROOT/etc/apt" \
|
||||
"$APT_ROOT/var/lib/apt/lists/partial" \
|
||||
"$APT_ROOT/var/lib/dpkg" \
|
||||
"$APT_ROOT/var/cache/apt/archives/partial"
|
||||
cp "$ROOT_DIR/scripts/fnos-bookworm.sources.list" "$APT_ROOT/etc/apt/sources.list"
|
||||
touch "$APT_ROOT/var/lib/dpkg/status"
|
||||
APT_OPTIONS=(
|
||||
-o "Dir::Etc::sourcelist=$APT_ROOT/etc/apt/sources.list"
|
||||
-o "Dir::Etc::sourceparts=-"
|
||||
-o "Dir::State::status=$APT_ROOT/var/lib/dpkg/status"
|
||||
-o "Dir::State::lists=$APT_ROOT/var/lib/apt/lists"
|
||||
-o "Dir::Cache=$APT_ROOT/var/cache/apt"
|
||||
-o "Dir::Cache::archives=$APT_ROOT/var/cache/apt/archives"
|
||||
-o "Debug::NoLocking=1"
|
||||
-o "APT::Architecture=amd64"
|
||||
-o "Acquire::Languages=none"
|
||||
)
|
||||
apt-get "${APT_OPTIONS[@]}" update
|
||||
apt-get "${APT_OPTIONS[@]}" --download-only --no-install-recommends --yes install \
|
||||
postgresql-15 postgresql-client-15
|
||||
|
||||
shopt -s nullglob
|
||||
runtime_packages=("$APT_ROOT"/var/cache/apt/archives/*.deb)
|
||||
test "${#runtime_packages[@]}" -gt 0 || { printf 'APT did not download PostgreSQL runtime packages\n' >&2; exit 1; }
|
||||
for package_file in "${runtime_packages[@]}"; do
|
||||
dpkg-deb -x "$package_file" "$EXTRACT_ROOT"
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
printf 'Downloading pinned pgvector %s extension...\n' "$PGVECTOR_VERSION"
|
||||
PGVECTOR_DEB="$WORK_DIR/postgresql-15-pgvector.deb"
|
||||
curl --fail --location --retry 3 \
|
||||
"https://apt.postgresql.org/pub/repos/apt/pool/main/p/pgvector/postgresql-15-pgvector_${PGVECTOR_PACKAGE_VERSION}_amd64.deb" \
|
||||
--output "$PGVECTOR_DEB"
|
||||
printf '%s %s\n' "$PGVECTOR_SHA256" "$PGVECTOR_DEB" | sha256sum --check --status
|
||||
test "$(dpkg-deb -f "$PGVECTOR_DEB" Package)" = "postgresql-15-pgvector"
|
||||
test "$(dpkg-deb -f "$PGVECTOR_DEB" Version)" = "${PGVECTOR_PACKAGE_VERSION//%2B/+}"
|
||||
dpkg-deb -x "$PGVECTOR_DEB" "$EXTRACT_ROOT"
|
||||
|
||||
printf 'Assembling relocatable PostgreSQL runtime...\n'
|
||||
cp -a "$EXTRACT_ROOT/." "$RUNTIME_ROOT/"
|
||||
rm -rf \
|
||||
"$RUNTIME_ROOT/usr/share/doc" \
|
||||
"$RUNTIME_ROOT/usr/share/man" \
|
||||
"$RUNTIME_ROOT/usr/share/locale" \
|
||||
"$RUNTIME_ROOT/var" \
|
||||
"$RUNTIME_ROOT/etc/init.d" \
|
||||
"$RUNTIME_ROOT/usr/sbin"
|
||||
|
||||
# fnOS provides the matching glibc and loader. Keep other Debian libraries but
|
||||
# never package a second libc implementation into the application runtime.
|
||||
find "$RUNTIME_ROOT" -type f \( \
|
||||
-name 'ld-linux-*.so.*' -o -name 'libc.so.*' -o -name 'libm.so.*' -o \
|
||||
-name 'libmvec.so.*' -o -name 'libpthread.so.*' -o -name 'libdl.so.*' -o \
|
||||
-name 'librt.so.*' -o -name 'libresolv.so.*' -o -name 'libutil.so.*' \
|
||||
\) -delete
|
||||
|
||||
# Official fnOS packages reject absolute links. Rewrite Debian links to remain
|
||||
# inside the staged runtime and fail if a link target was not packaged.
|
||||
while IFS= read -r -d '' link_path; do
|
||||
target=$(readlink -- "$link_path")
|
||||
case "$target" in
|
||||
/*)
|
||||
staged_target="$RUNTIME_ROOT$target"
|
||||
if [ ! -e "$staged_target" ]; then
|
||||
rm "$link_path"
|
||||
continue
|
||||
fi
|
||||
relative_target=$(realpath --relative-to="$(dirname -- "$link_path")" "$staged_target")
|
||||
rm "$link_path"
|
||||
ln -s "$relative_target" "$link_path"
|
||||
;;
|
||||
esac
|
||||
done < <(find "$RUNTIME_ROOT" -type l -print0)
|
||||
|
||||
for required_file in \
|
||||
"$RUNTIME_ROOT/usr/lib/postgresql/15/bin/postgres" \
|
||||
"$RUNTIME_ROOT/usr/lib/postgresql/15/bin/initdb" \
|
||||
"$RUNTIME_ROOT/usr/lib/postgresql/15/bin/pg_ctl" \
|
||||
"$RUNTIME_ROOT/usr/lib/postgresql/15/bin/pg_dump" \
|
||||
"$RUNTIME_ROOT/usr/lib/postgresql/15/lib/vector.so" \
|
||||
"$RUNTIME_ROOT/usr/share/postgresql/15/extension/vector.control"; do
|
||||
test -e "$required_file" || { printf 'runtime file is missing: %s\n' "$required_file" >&2; exit 1; }
|
||||
done
|
||||
|
||||
node "$ROOT_DIR/scripts/generate-fnos-icons.mjs" "$STAGE" "$STAGE/app/ui/images"
|
||||
chmod 0755 "$STAGE/cmd/"*
|
||||
|
||||
printf 'Packing PostgreSQL service with official fnOS fnpack...\n'
|
||||
(
|
||||
cd "$PACKED_ROOT"
|
||||
TMPDIR="$FNPACK_TMP_ROOT" "$FNPACK_BIN" build --directory "$STAGE"
|
||||
)
|
||||
built_package=$(find "$PACKED_ROOT" -maxdepth 1 -type f -name '*.fpk' -print -quit)
|
||||
test -n "$built_package" || { printf 'fnpack did not create an FPK\n' >&2; exit 1; }
|
||||
mv "$built_package" "$OUTPUT"
|
||||
(
|
||||
cd "$(dirname -- "$OUTPUT")"
|
||||
sha256sum "$(basename -- "$OUTPUT")" >"$(basename -- "$OUTPUT").sha256"
|
||||
)
|
||||
|
||||
"$ROOT_DIR/scripts/verify-fnos-package.sh" "$OUTPUT"
|
||||
printf 'Built %s\n' "$OUTPUT"
|
||||
Reference in New Issue
Block a user