Skip to content
Open
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 nix/ext/hypopg.nix
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/index_advisor.nix
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pkgs.buildEnv {
];

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg-safeupdate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg_cron/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ buildEnv {
};

passthru = {
perVersion = lib.mapAttrs (name: value: build name value) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit switch-ext-version latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg_net.nix
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg_partman.nix
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit switch-ext-version libName latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg_repack.nix
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pg_tle.nix
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgaudit.nix
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgmq/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ buildEnv {
pathsToLink = [ "/share/postgresql/extension" ];

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgroonga/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgrouting/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgsodium.nix
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgsql-http.nix
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/pgvector.nix
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/plv8/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/postgis.nix
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ in
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
1 change: 1 addition & 0 deletions nix/ext/vault.nix
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pkgs.buildEnv {
'';

passthru = {
perVersion = lib.mapAttrs (name: value: build name value.hash) versionsToUse;
versions = versionsBuilt;
numberOfVersions = numberOfVersionsBuilt;
inherit pname latestOnly;
Expand Down
2 changes: 1 addition & 1 deletion nix/packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
imports = [
./postgres.nix
./site-env.nix
./extension-catalog.nix
];

perSystem =
{
inputs',
Expand Down
183 changes: 183 additions & 0 deletions nix/packages/extension-catalog.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Multi version extension catalog and update tools.
{
perSystem =
{
pkgs,
lib,
self',
...
}:
let
# Mirror a per-version package, adding unversioned control/library names
# only where missing — packages that already ship generic names (e.g.
# postgis and its `-3` convention) pass through untouched.
mkGenericVersion =
leanPkg:
pkgs.runCommand "${leanPkg.pname}-${leanPkg.version}-generic" { } ''
set -euo pipefail
shopt -s nullglob
mkdir -p "$out/lib" "$out/share/postgresql/extension"
ext="$out/share/postgresql/extension"

for f in ${leanPkg}/lib/*; do ln -s "$f" "$out/lib/$(basename "$f")"; done
for f in ${leanPkg}/share/postgresql/extension/*; do ln -s "$f" "$ext/$(basename "$f")"; done

# <name>.control with default_version, from <name>--<version>.control
for cf in "$ext"/*--*.control; do
b=$(basename "$cf")
n="''${b%%--*}"
v="''${b#*--}"; v="''${v%.control}"
[ -e "$ext/$n.control" ] && continue
{ echo "default_version = '$v'"; cat "$cf"; } > "$ext/$n.control"
done

# <base>.so -> <base>-<version>.so
for f in "$out"/lib/*-[0-9]*; do
b=$(basename "$f")
suffix=".''${b##*.}"
core="''${b%.*}"
base="''${core%-[0-9]*}"
[ "$base" != "$core" ] || continue
gen="$base$suffix"
[ -e "$out/lib/$gen" ] || ln -sfn "$b" "$out/lib/$gen"
done

# Sanity check. No generic control is fine only for preload-only
# modules (e.g. pg-safeupdate), which still ship a library.
generic=0
for c in "$ext"/*.control; do
case "$(basename "$c")" in
*--*) ;;
*) generic=$((generic + 1)) ;;
esac
done
libs=$(ls -A "$out/lib" 2>/dev/null | wc -l)
if [ "$generic" -eq 0 ] && [ "$libs" -eq 0 ]; then
echo "extension-catalog: empty wrapper for ${leanPkg.pname} (no control, no lib)" >&2
exit 1
fi
'';

wrappersFor =
extsSet:
lib.mapAttrs (_: drv: lib.mapAttrs (_: mkGenericVersion) drv.perVersion) (
lib.filterAttrs (_: drv: lib.isDerivation drv && drv ? perVersion) extsSet
);

# Make catalog json from a set of wrappers: { <ext>: { <version>: <path> } }
# Keyed on each wrapper's actual default_version, not the nix attr name,
# which can differ (pgsql-http "1.5.0" builds extversion "1.5").
mkCatalogFile =
wrappers:
pkgs.runCommand "pg-extensions-catalog"
{
paths = map toString (lib.concatMap lib.attrValues (lib.attrValues wrappers));
nativeBuildInputs = [ pkgs.jq ];
# Without this the literal wrapper paths in the JSON would pull
# every wrapper's closure into the catalog's runtime closure.
__structuredAttrs = true;
unsafeDiscardReferences.out = true;
}
''
set -euo pipefail
obj='{}'
for path in "''${paths[@]}"; do
for ctrl in "$path"/share/postgresql/extension/*.control; do
base=$(basename "$ctrl")
case "$base" in *--*) continue ;; esac
name="''${base%.control}"
ver=$(sed -n "s/^default_version = '\(.*\)'.*/\1/p" "$ctrl" | head -1)
[ -n "$ver" ] || { echo "no default_version in $ctrl" >&2; exit 1; }
obj=$(printf '%s' "$obj" | jq --arg e "$name" --arg v "$ver" --arg p "$path" '.[$e][$v] = $p')
done
done
mkdir -p "$out/share"
printf '%s\n' "$obj" | jq -S . > "$out/share/pg-extensions-catalog.json"
'';

script =
name: text:
pkgs.writeShellApplication {
inherit name text;
runtimeInputs = [
pkgs.coreutils
pkgs.jq
];
};

# Multi version extensions as attrsets: { <major> = { <ext> = { <version> = drv; }; }; }
perMajor = lib.genAttrs [ "15" "17" "orioledb-17" ] (
major: wrappersFor self'.legacyPackages."psql_${major}".exts
);

# Catalog json plus bin/site-extensions-{resolve,update} that use it by default.
catalogs = lib.mapAttrs' (
major: wrappers:
lib.nameValuePair "site-extensions-catalog-${major}" (
pkgs.runCommand "site-extensions-catalog" { nativeBuildInputs = [ pkgs.makeWrapper ]; } ''
mkdir -p "$out/share" "$out/bin"
ln -s ${mkCatalogFile wrappers}/share/pg-extensions-catalog.json "$out/share/"
makeWrapper ${self'.packages.site-extensions-resolve}/bin/site-extensions-resolve \
"$out/bin/site-extensions-resolve" \
--set PG_EXTENSIONS_CATALOG "$out/share/pg-extensions-catalog.json"
makeWrapper ${self'.packages.site-extensions-update}/bin/site-extensions-update \
"$out/bin/site-extensions-update" \
--set PG_EXTENSIONS_CATALOG "$out/share/pg-extensions-catalog.json"
''
)
) perMajor;

versions = lib.mapAttrs' (
major: wrappers:
lib.nameValuePair "site-extensions-versions-${major}" (
lib.recurseIntoAttrs (lib.mapAttrs (_: lib.recurseIntoAttrs) wrappers)
)
) perMajor;
in
{
packages = catalogs // {
# Takes store paths as args and substitutes from binary cache, with retry.
download-nix-store-paths = script "download-nix-store-paths" ''
for path in "$@"; do
for attempt in 1 2 3; do
timeout -k 10s 120s nix-store -r "$path" >/dev/null && continue 2
echo "WARNING: attempt $attempt failed for $path" >&2
done
echo "ERROR: failed to realize $path" >&2
exit 1
done
'';

# Takes manifest json as argument. Format: {<ext>: <version>}.
# Prints nix-store paths of the resolved extensions, one per line.
# Does not download or install.
site-extensions-resolve = script "site-extensions-resolve" ''
: "''${PG_EXTENSIONS_CATALOG:?PG_EXTENSIONS_CATALOG must point at a pg-extensions-catalog.json}"
manifest="''${1:?Usage: $0 path-to/pg-extensions.json}"
jq -r 'to_entries[] | "\(.key)=\(.value)"' "$manifest" | while IFS='=' read -r name version; do
[ -n "$name" ] || continue
jq -er --arg n "$name" --arg v "$version" \
'.[$n][$v] // error("\($n)=\($v) not in catalog")' "$PG_EXTENSIONS_CATALOG"
done | sort -u
'';

# Takes manifest json as argument.
# Downloads paths and installs them as an env into the profile, replacing all existing ones.
site-extensions-update = pkgs.writeShellApplication {
name = "site-extensions-update";
runtimeInputs = [
self'.packages.site-extensions-resolve
self'.packages.download-nix-store-paths
];
text = ''
manifest="''${1:-/etc/adminapi/pg-extensions.json}"
profile="''${PROFILE:-/nix/var/nix/profiles/site-extensions}"
mapfile -t paths < <(site-extensions-resolve "$manifest")
download-nix-store-paths "''${paths[@]}"
nix-env --profile "$profile" --install "''${paths[@]}" --remove-all
'';
};
};
legacyPackages = catalogs // versions;
};
}
Loading