Skip to content

Commit 5e8a6b6

Browse files
jfrochesamrose
authored andcommitted
feat: refactor pg_cron to use buildEnv
Fix upgrade nixos tests that was broken. Move overlays and switch-ext-version script to package.
1 parent 5fde725 commit 5e8a6b6

File tree

6 files changed

+202
-126
lines changed

6 files changed

+202
-126
lines changed

nix/ext/pg_cron/default.nix

Lines changed: 52 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
stdenv,
44
fetchFromGitHub,
55
postgresql,
6+
buildEnv,
7+
makeWrapper,
8+
switch-ext-version,
69
}:
7-
810
let
911
pname = "pg_cron";
1012
allVersions = (builtins.fromJSON (builtins.readFile ../versions.json)).${pname};
@@ -32,14 +34,6 @@ let
3234

3335
buildPhase = ''
3436
make PG_CONFIG=${postgresql}/bin/pg_config
35-
36-
# Create version-specific SQL file
37-
cp pg_cron.sql pg_cron--${version}.sql
38-
39-
# Create versioned control file with modified module path
40-
sed -e "/^default_version =/d" \
41-
-e "s|^module_pathname = .*|module_pathname = '\$libdir/pg_cron'|" \
42-
pg_cron.control > pg_cron--${version}.control
4337
'';
4438

4539
installPhase = ''
@@ -48,21 +42,25 @@ let
4842
# Install versioned library
4943
install -Dm755 ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
5044
51-
# Install version-specific files
52-
install -Dm644 ${pname}--${version}.sql $out/share/postgresql/extension/
53-
install -Dm644 ${pname}--${version}.control $out/share/postgresql/extension/
54-
55-
# Install upgrade scripts
56-
find . -name 'pg_cron--*--*.sql' -exec install -Dm644 {} $out/share/postgresql/extension/ \;
5745
58-
# For the latest version, create default control file and symlink
5946
if [[ "${version}" == "${latestVersion}" ]]; then
60-
{
61-
echo "default_version = '${version}'"
62-
cat $out/share/postgresql/extension/${pname}--${version}.control
63-
} > $out/share/postgresql/extension/${pname}.control
64-
ln -sfn ${pname}-${version}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
47+
cp ${pname}.sql $out/share/postgresql/extension/${pname}--1.0.0.sql
48+
# Install upgrade scripts
49+
find . -name 'pg_cron--*--*.sql' -exec install -Dm644 {} $out/share/postgresql/extension/ \;
50+
mv $out/share/postgresql/extension/pg_cron--1.0--1.1.sql $out/share/postgresql/extension/pg_cron--1.0.0--1.1.0.sql
51+
mv $out/share/postgresql/extension/pg_cron--1.1--1.2.sql $out/share/postgresql/extension/pg_cron--1.1.0--1.2.0.sql
52+
mv $out/share/postgresql/extension/pg_cron--1.2--1.3.sql $out/share/postgresql/extension/pg_cron--1.2.0--1.3.1.sql
53+
mv $out/share/postgresql/extension/pg_cron--1.3--1.4.sql $out/share/postgresql/extension/pg_cron--1.3.1--1.4.2.sql
54+
mv $out/share/postgresql/extension/pg_cron--1.4--1.4-1.sql $out/share/postgresql/extension/pg_cron--1.4.0--1.4.1.sql
55+
mv $out/share/postgresql/extension/pg_cron--1.4-1--1.5.sql $out/share/postgresql/extension/pg_cron--1.4.2--1.5.2.sql
56+
mv $out/share/postgresql/extension/pg_cron--1.5--1.6.sql $out/share/postgresql/extension/pg_cron--1.5.2--1.6.4.sql
6557
fi
58+
59+
# Create versioned control file with modified module path
60+
sed -e "/^default_version =/d" \
61+
-e "/^schema =/d" \
62+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
63+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
6664
'';
6765

6866
meta = with lib; {
@@ -75,110 +73,45 @@ let
7573
};
7674
packages = builtins.attrValues (lib.mapAttrs (name: value: build name value) supportedVersions);
7775
in
78-
stdenv.mkDerivation {
79-
pname = "${pname}-all";
80-
version =
81-
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
82-
83-
buildInputs = packages;
84-
85-
dontUnpack = true;
86-
dontConfigure = true;
87-
dontBuild = true;
88-
89-
installPhase = ''
90-
mkdir -p $out/{lib,share/postgresql/extension,bin}
91-
92-
# Install all versions
93-
for drv in ${lib.concatStringsSep " " packages}; do
94-
ln -sv $drv/lib/* $out/lib/
95-
cp -v --no-clobber $drv/share/postgresql/extension/* $out/share/postgresql/extension/ || true
96-
done
97-
98-
# Find latest version
99-
latest_control=$(ls -v $out/share/postgresql/extension/${pname}--*.control | tail -n1)
100-
latest_version=$(basename "$latest_control" | sed -E 's/${pname}--([0-9.]+).control/\1/')
101-
102-
# Create main control file only if it doesn't exist
103-
if [ ! -f "$out/share/postgresql/extension/${pname}.control" ]; then
104-
# Create main control file with default_version
105-
echo "default_version = '$latest_version'" > $out/share/postgresql/extension/${pname}.control
106-
cat "$latest_control" >> $out/share/postgresql/extension/${pname}.control
107-
fi
108-
109-
# Library symlink - only if it doesn't exist
110-
if [ ! -f "$out/lib/${pname}${postgresql.dlSuffix}" ]; then
111-
ln -sfnv ${pname}-$latest_version${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
112-
fi
113-
114-
# Create version switcher script
115-
cat > $out/bin/switch_pg_cron_version <<'EOF'
116-
#!/bin/sh
117-
set -e
118-
119-
if [ $# -ne 1 ]; then
120-
echo "Usage: $0 <version>"
121-
echo "Example: $0 1.4.2"
122-
exit 1
123-
fi
124-
125-
VERSION=$1
126-
NIX_PROFILE="/var/lib/postgresql/.nix-profile"
127-
128-
# Follow the complete chain of symlinks to find the multi-version directory
129-
CURRENT_LINK="$NIX_PROFILE/lib/pg_cron-$VERSION${postgresql.dlSuffix}"
130-
echo "Starting with link: $CURRENT_LINK"
131-
132-
# Follow first two symlinks to get to the multi-version directory
133-
for i in 1 2; do
134-
if [ -L "$CURRENT_LINK" ]; then
135-
NEXT_LINK=$(readlink "$CURRENT_LINK")
136-
echo "Following link: $NEXT_LINK"
137-
if echo "$NEXT_LINK" | grep -q '^/'; then
138-
CURRENT_LINK="$NEXT_LINK"
139-
else
140-
CURRENT_LINK="$(dirname "$CURRENT_LINK")/$NEXT_LINK"
141-
fi
142-
echo "Current link is now: $CURRENT_LINK"
143-
fi
144-
done
145-
146-
# The multi-version directory should be the parent of the current link
147-
MULTI_VERSION_DIR=$(dirname "$CURRENT_LINK")
148-
echo "Found multi-version directory: $MULTI_VERSION_DIR"
149-
LIB_DIR="$MULTI_VERSION_DIR"
150-
EXTENSION_DIR="$NIX_PROFILE/share/postgresql/extension"
151-
152-
echo "Looking for file: $LIB_DIR/pg_cron-$VERSION${postgresql.dlSuffix}"
153-
ls -la "$LIB_DIR" || true
154-
155-
# Check if version exists
156-
if [ ! -f "$LIB_DIR/pg_cron-$VERSION${postgresql.dlSuffix}" ]; then
157-
echo "Error: Version $VERSION not found"
158-
exit 1
159-
fi
160-
161-
# Update library symlink
162-
ln -sfnv "pg_cron-$VERSION${postgresql.dlSuffix}" "$LIB_DIR/pg_cron${postgresql.dlSuffix}"
163-
164-
# Update control file
165-
echo "default_version = '$VERSION'" > "$EXTENSION_DIR/pg_cron.control"
166-
cat "$EXTENSION_DIR/pg_cron--$VERSION.control" >> "$EXTENSION_DIR/pg_cron.control"
167-
168-
echo "Successfully switched pg_cron to version $VERSION"
169-
EOF
170-
171-
chmod +x $out/bin/switch_pg_cron_version
76+
buildEnv {
77+
name = pname;
78+
paths = packages;
79+
nativeBuildInputs = [ makeWrapper ];
80+
81+
pathsToLink = [
82+
"/lib"
83+
"/share/postgresql/extension"
84+
];
85+
86+
postBuild = ''
87+
{
88+
echo "default_version = '${latestVersion}'"
89+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
90+
} > $out/share/postgresql/extension/${pname}.control
91+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
92+
93+
# checks
94+
(set -x
95+
test "$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)" = "${
96+
toString (numberOfVersions + 1)
97+
}"
98+
)
99+
100+
makeWrapper ${lib.getExe switch-ext-version} $out/bin/switch_pg_cron_version \
101+
--prefix EXT_WRAPPER : "$out" --prefix EXT_NAME : "${pname}"
172102
'';
173103

174-
passthru = {
175-
inherit versions numberOfVersions;
176-
};
177-
178104
meta = with lib; {
179105
description = "Run Cron jobs through PostgreSQL (multi-version compatible)";
180106
homepage = "https://github.com/citusdata/pg_cron";
181107
platforms = postgresql.meta.platforms;
182108
license = licenses.postgresql;
183109
};
110+
111+
passthru = {
112+
inherit versions numberOfVersions switch-ext-version;
113+
pname = "${pname}-all";
114+
version =
115+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
116+
};
184117
}

nix/ext/tests/pg_cron.nix

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ let
3636
};
3737
in
3838
pkg;
39+
psql_15 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
40+
psql_17 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17;
3941
in
4042
self.inputs.nixpkgs.lib.nixos.runTest {
4143
name = pname;
@@ -55,16 +57,16 @@ self.inputs.nixpkgs.lib.nixos.runTest {
5557

5658
services.postgresql = {
5759
enable = true;
58-
package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
60+
package = psql_15;
5961
settings = {
6062
"cron.database_name" = "postgres";
61-
shared_preload_libraries = "pg_cron";
63+
shared_preload_libraries = pname;
6264
};
6365
};
6466

6567
specialisation.postgresql17.configuration = {
6668
services.postgresql = {
67-
package = lib.mkForce (postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17);
69+
package = lib.mkForce psql_17;
6870
};
6971

7072
systemd.services.postgresql-migrate = {
@@ -78,8 +80,8 @@ self.inputs.nixpkgs.lib.nixos.runTest {
7880
};
7981
script =
8082
let
81-
oldPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
82-
newPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17;
83+
oldPostgresql = psql_15;
84+
newPostgresql = psql_17;
8385
oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}";
8486
newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}";
8587
in
@@ -134,18 +136,41 @@ self.inputs.nixpkgs.lib.nixos.runTest {
134136
135137
check_upgrade_path("15")
136138
139+
with subtest("Test switch_${pname}_version"):
140+
# Check that we are using the last version first
141+
ext_version = server.succeed("readlink -f ${psql_15}/lib/${pname}.so").strip()
142+
firstVersion = versions["15"][0]
143+
latestVersion = versions["15"][-1]
144+
assert ext_version.endswith(f"${pname}-{latestVersion}.so"), f"Expected ${pname} version {latestVersion}, but found {ext_version}"
145+
146+
server.succeed(
147+
f"switch_${pname}_version {firstVersion}"
148+
)
149+
150+
ext_version = server.succeed("readlink -f ${psql_15}/lib/${pname}.so").strip()
151+
assert ext_version.endswith(f"${pname}-{firstVersion}.so"), f"Expected ${pname} version {firstVersion}, but found {ext_version}"
152+
153+
server.succeed(
154+
f"switch_${pname}_version {latestVersion}"
155+
)
156+
137157
with subtest("Check ${pname} latest extension version"):
138158
server.succeed("sudo -u postgres psql -c 'DROP EXTENSION ${pname};'")
139-
server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname} CASCADE;'")
159+
server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname};'")
140160
installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""")
141161
latestVersion = versions["15"][-1]
142162
assert f"${pname},{latestVersion}" in installed_extensions
143163
144-
with subtest("switch to postgresql 17"):
164+
with subtest("switch to multiple node configuration"):
145165
server.succeed(
146166
"${pg17-configuration}/bin/switch-to-configuration test >&2"
147167
)
148168
169+
with subtest("Check ${pname} latest extension version"):
170+
installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""")
171+
latestVersion = versions["15"][-1]
172+
assert f"${pname},{latestVersion}" in installed_extensions
173+
149174
check_upgrade_path("17")
150175
'';
151176
}

nix/overlays/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
postgresql_17
1212
postgresql_orioledb-17
1313
supabase-groonga
14+
switch-ext-version
1415
;
1516

1617
xmrig = throw "The xmrig package has been explicitly disabled in this flake.";

nix/packages/default.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
supabase-groonga = pkgs.callPackage ./groonga { };
3838
local-infra-bootstrap = pkgs.callPackage ./local-infra-bootstrap.nix { };
3939
migrate-tool = pkgs.callPackage ./migrate-tool.nix { psql_15 = self'.packages."psql_15/bin"; };
40+
overlayfs-on-package = pkgs.callPackage ./overlayfs-on-package.nix { };
4041
packer = pkgs.callPackage ./packer.nix { inherit inputs; };
4142
pg-restore = pkgs.callPackage ./pg-restore.nix { psql_15 = self'.packages."psql_15/bin"; };
4243
pg_prove = pkgs.perlPackages.TAPParserSourceHandlerpgTAP;
@@ -57,6 +58,9 @@
5758
inherit pkgs;
5859
name = "start-postgres-server";
5960
};
61+
switch-ext-version = pkgs.callPackage ./switch-ext-version.nix {
62+
inherit (self'.packages) overlayfs-on-package;
63+
};
6064
sync-exts-versions = pkgs.callPackage ./sync-exts-versions.nix { inherit (inputs') nix-editor; };
6165
trigger-nix-build = pkgs.callPackage ./trigger-nix-build.nix { };
6266
update-readme = pkgs.callPackage ./update-readme.nix { };

nix/packages/overlayfs-on-package.nix

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{ writeShellApplication, coreutils }:
2+
writeShellApplication {
3+
name = "overlayfs-on-package";
4+
runtimeInputs = [ coreutils ];
5+
text = ''
6+
# This script enable overlayfs on a specific nix store path
7+
set -euo pipefail
8+
9+
if [ $# -ne 1 ]; then
10+
echo "Usage: $0 <path>"
11+
exit 1
12+
fi
13+
14+
PACKAGE_PATH="$1"
15+
PACKAGE_NAME=$(basename "$1"|cut -c 34-)
16+
17+
# Nixos compatibility: use systemd mount unit
18+
#shellcheck disable=SC1091
19+
source /etc/os-release || true
20+
if [[ "$ID" == "nixos" ]]; then
21+
# This script is used in NixOS test only for the moment
22+
SYSTEMD_DIR="/run/systemd/system"
23+
else
24+
SYSTEMD_DIR="/etc/systemd/system"
25+
fi
26+
27+
# Create required directories for overlay
28+
echo "$PACKAGE_NAME"
29+
mkdir -p "/var/lib/overlay/$PACKAGE_NAME/"{upper,work}
30+
31+
PACKAGE_MOUNT_PATH=$(systemd-escape -p --suffix=mount "$PACKAGE_PATH")
32+
33+
cat > "$SYSTEMD_DIR/$PACKAGE_MOUNT_PATH" <<EOF
34+
[Unit]
35+
Description=Overlay mount for PostgreSQL extension $PACKAGE_NAME
36+
37+
[Mount]
38+
What=overlay
39+
Type=overlay
40+
Options=lowerdir=$PACKAGE_PATH,upperdir=/var/lib/overlay/$PACKAGE_NAME/upper,workdir=/var/lib/overlay/$PACKAGE_NAME/work
41+
42+
[Install]
43+
WantedBy=multi-user.target
44+
EOF
45+
46+
systemctl daemon-reload
47+
systemctl start "$PACKAGE_MOUNT_PATH"
48+
'';
49+
}

0 commit comments

Comments
 (0)