|
1 | 1 | { |
2 | 2 | lib, |
3 | 3 | stdenv, |
| 4 | + buildEnv, |
4 | 5 | fetchFromGitHub, |
5 | 6 | libkrb5, |
6 | 7 | openssl, |
7 | 8 | postgresql, |
8 | 9 | }: |
9 | 10 | #adapted from https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/sql/postgresql/ext/pgaudit.nix |
10 | 11 | let |
11 | | - source = |
12 | | - { |
13 | | - "17" = { |
14 | | - version = "17.0"; |
15 | | - hash = "sha256-3ksq09wiudQPuBQI3dhEQi8IkXKLVIsPFgBnwLiicro="; |
16 | | - }; |
17 | | - "16" = { |
18 | | - version = "16.0"; |
19 | | - hash = "sha256-8+tGOl1U5y9Zgu+9O5UDDE4bec4B0JC/BQ6GLhHzQzc="; |
| 12 | + pname = "pgaudit"; |
| 13 | + # Load version configuration from external file |
| 14 | + allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname}; |
| 15 | + |
| 16 | + # Filter versions compatible with current PostgreSQL version (these get libraries) |
| 17 | + supportedVersions = lib.filterAttrs ( |
| 18 | + _: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql |
| 19 | + ) allVersions; |
| 20 | + |
| 21 | + # Derived version information |
| 22 | + # All versions sorted (for SQL migration files) |
| 23 | + allVersionsList = lib.naturalSort (lib.attrNames allVersions); |
| 24 | + # Supported versions sorted (for libraries) |
| 25 | + versions = lib.naturalSort (lib.attrNames supportedVersions); |
| 26 | + latestVersion = lib.last versions; |
| 27 | + numberOfVersions = builtins.length versions; |
| 28 | + |
| 29 | + # Build packages only for supported versions (with libraries) |
| 30 | + packages = builtins.attrValues ( |
| 31 | + lib.mapAttrs (name: value: build name value.hash) supportedVersions |
| 32 | + ); |
| 33 | + |
| 34 | + # Helper function to generate migration SQL file pairs |
| 35 | + # Returns a list of {from, to} pairs for sequential migrations |
| 36 | + generateMigrationPairs = |
| 37 | + versions: |
| 38 | + let |
| 39 | + indexed = lib.imap0 (i: v: { |
| 40 | + idx = i; |
| 41 | + version = v; |
| 42 | + }) versions; |
| 43 | + pairs = lib.filter (x: x.idx > 0) indexed; |
| 44 | + in |
| 45 | + map (curr: { |
| 46 | + from = (lib.elemAt versions (curr.idx - 1)); |
| 47 | + to = curr.version; |
| 48 | + }) pairs; |
| 49 | + |
| 50 | + # All migration pairs across all versions (sequential) |
| 51 | + allMigrationPairs = generateMigrationPairs allVersionsList; |
| 52 | + |
| 53 | + # Get the first supported version for this PG major |
| 54 | + firstSupportedVersion = lib.head versions; |
| 55 | + |
| 56 | + # Generate bridge migrations from unsupported versions to first supported version |
| 57 | + # These are needed when upgrading PostgreSQL major versions |
| 58 | + # Only include versions that come BEFORE the first supported version (no backwards migrations) |
| 59 | + unsupportedVersions = lib.filter ( |
| 60 | + v: !(builtins.elem v versions) && (lib.versionOlder v firstSupportedVersion) |
| 61 | + ) allVersionsList; |
| 62 | + bridgeMigrations = map (v: { |
| 63 | + from = v; |
| 64 | + to = firstSupportedVersion; |
| 65 | + }) unsupportedVersions; |
| 66 | + |
| 67 | + # Build function for individual pgaudit versions |
| 68 | + build = |
| 69 | + version: hash: |
| 70 | + stdenv.mkDerivation { |
| 71 | + inherit pname version; |
| 72 | + |
| 73 | + src = fetchFromGitHub { |
| 74 | + owner = "pgaudit"; |
| 75 | + repo = "pgaudit"; |
| 76 | + rev = version; |
| 77 | + inherit hash; |
20 | 78 | }; |
21 | | - "15" = { |
22 | | - version = "1.7.0"; |
23 | | - hash = "sha256-8pShPr4HJaJQPjW1iPJIpj3CutTx8Tgr+rOqoXtgCcw="; |
| 79 | + |
| 80 | + buildInputs = [ |
| 81 | + libkrb5 |
| 82 | + openssl |
| 83 | + postgresql |
| 84 | + ]; |
| 85 | + |
| 86 | + makeFlags = [ "USE_PGXS=1" ]; |
| 87 | + |
| 88 | + postBuild = |
| 89 | + lib.optionalString (version == "1.7.0") '' |
| 90 | + mv ${pname}--1.7.sql ${pname}--1.7.0.sql |
| 91 | + cp ${pname}--1.7.0.sql ${pname}--1.6.1--1.7.0.sql |
| 92 | + '' |
| 93 | + + lib.optionalString (version == "1.7.1") '' |
| 94 | + mv ${pname}--1.7--1.7.1.sql ${pname}--1.7.0--1.7.1.sql |
| 95 | + ''; |
| 96 | + |
| 97 | + installPhase = '' |
| 98 | + runHook preInstall |
| 99 | +
|
| 100 | + mkdir -p $out/{lib,share/postgresql/extension} |
| 101 | +
|
| 102 | + # Extract the actual default_version from the control file |
| 103 | + # This is what PostgreSQL will record in pg_extension, not necessarily the git tag |
| 104 | + controlVersion=$(grep "^default_version" ${pname}.control | sed "s/default_version = '\(.*\)'/\1/") |
| 105 | + echo "$controlVersion" > $out/control_version |
| 106 | +
|
| 107 | + # Install shared library with version suffix |
| 108 | + mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix} |
| 109 | +
|
| 110 | + # Install SQL files with modifications |
| 111 | + sed -i '1s/^/DROP EVENT TRIGGER IF EXISTS pgaudit_ddl_command_end; \n/' *.sql |
| 112 | + sed -i '1s/^/DROP EVENT TRIGGER IF EXISTS pgaudit_sql_drop; \n/' *.sql |
| 113 | + sed -i 's/CREATE FUNCTION/CREATE OR REPLACE FUNCTION/' *.sql |
| 114 | + cp *.sql $out/share/postgresql/extension |
| 115 | +
|
| 116 | + # Create version-specific control file pointing to versioned library |
| 117 | + sed -e "/^default_version =/d" \ |
| 118 | + -e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \ |
| 119 | + ${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control |
| 120 | +
|
| 121 | + runHook postInstall |
| 122 | + ''; |
| 123 | + |
| 124 | + meta = with lib; { |
| 125 | + description = "Open Source PostgreSQL Audit Logging"; |
| 126 | + homepage = "https://github.com/pgaudit/pgaudit"; |
| 127 | + changelog = "https://github.com/pgaudit/pgaudit/releases/tag/${source.version}"; |
| 128 | + license = licenses.postgresql; |
| 129 | + inherit (postgresql.meta) platforms; |
24 | 130 | }; |
25 | | - } |
26 | | - .${lib.versions.major postgresql.version} |
27 | | - or (throw "Source for pgaudit is not available for ${postgresql.version}"); |
| 131 | + }; |
28 | 132 | in |
29 | | -stdenv.mkDerivation { |
30 | | - pname = "pgaudit"; |
31 | | - inherit (source) version; |
| 133 | +buildEnv { |
| 134 | + name = pname; |
| 135 | + paths = packages; |
| 136 | + pathsToLink = [ |
| 137 | + "/lib" |
| 138 | + "/share/postgresql/extension" |
| 139 | + ]; |
| 140 | + postBuild = '' |
| 141 | + # Create symlinks to latest version for library and control file |
| 142 | + ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix} |
32 | 143 |
|
33 | | - src = fetchFromGitHub { |
34 | | - owner = "pgaudit"; |
35 | | - repo = "pgaudit"; |
36 | | - rev = source.version; |
37 | | - hash = source.hash; |
38 | | - }; |
| 144 | + # Create default control file pointing to latest |
| 145 | + { |
| 146 | + echo "default_version = '${latestVersion}'" |
| 147 | + cat $out/share/postgresql/extension/${pname}--${latestVersion}.control |
| 148 | + } > $out/share/postgresql/extension/${pname}.control |
39 | 149 |
|
40 | | - buildInputs = [ |
41 | | - libkrb5 |
42 | | - openssl |
43 | | - postgresql |
44 | | - ]; |
| 150 | + # Generate cross-version migration SQL files |
| 151 | + # For each migration pair, if the target version's base SQL exists but we haven't |
| 152 | + # built that version (no library), we need to create migration files to bridge from |
| 153 | + # older versions to the first available version on this PG major |
| 154 | + ${lib.concatMapStringsSep "\n" (pair: '' |
| 155 | + # Check if we need to create migration ${pair.from}--${pair.to}.sql |
| 156 | + if [[ ! -f "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" ]]; then |
| 157 | + # If the target SQL file exists, create the migration by copying it |
| 158 | + if [[ -f "$out/share/postgresql/extension/${pname}--${pair.to}.sql" ]]; then |
| 159 | + cp "$out/share/postgresql/extension/${pname}--${pair.to}.sql" \ |
| 160 | + "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" |
| 161 | + fi |
| 162 | + fi |
| 163 | + '') allMigrationPairs} |
| 164 | +
|
| 165 | + # Generate bridge migrations from unsupported versions to first supported version |
| 166 | + # This handles cross-PostgreSQL-major-version upgrades |
| 167 | + ${lib.concatMapStringsSep "\n" (pair: '' |
| 168 | + # Create bridge migration ${pair.from}--${pair.to}.sql if not already present |
| 169 | + if [[ ! -f "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" ]]; then |
| 170 | + # The bridge migration is just a copy of the target version's base SQL |
| 171 | + if [[ -f "$out/share/postgresql/extension/${pname}--${pair.to}.sql" ]]; then |
| 172 | + cp "$out/share/postgresql/extension/${pname}--${pair.to}.sql" \ |
| 173 | + "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" |
| 174 | + fi |
| 175 | + fi |
| 176 | + '') bridgeMigrations} |
| 177 | +
|
| 178 | + # Read actual control file versions from each built package |
| 179 | + # This handles cases where git tag differs from control file default_version |
| 180 | + # (e.g., git tag 1.7.0 but control file says default_version = '1.7') |
| 181 | + ${lib.concatMapStringsSep "\n" (pkg: '' |
| 182 | + if [[ -f "${pkg}/control_version" ]]; then |
| 183 | + controlVer=$(cat "${pkg}/control_version") |
| 184 | + echo "Found control version: $controlVer from package ${pkg}" |
| 185 | +
|
| 186 | + # Create migrations from control version to all supported versions on this PG major |
| 187 | + ${ |
| 188 | + lib.concatMapStringsSep "\n" (targetVer: '' |
| 189 | + # Skip if control version equals target version |
| 190 | + if [[ "$controlVer" != "${targetVer}" ]]; then |
| 191 | + # Skip if migration already exists |
| 192 | + if [[ ! -f "$out/share/postgresql/extension/${pname}--$controlVer--${targetVer}.sql" ]]; then |
| 193 | + # Create symlink to migration if target SQL exists |
| 194 | + if [[ -f "$out/share/postgresql/extension/${pname}--${targetVer}.sql" ]]; then |
| 195 | + echo "Creating migration symlink from control version $controlVer to ${targetVer}" |
| 196 | + ln -s "$out/share/postgresql/extension/${pname}--${targetVer}.sql" \ |
| 197 | + "$out/share/postgresql/extension/${pname}--$controlVer--${targetVer}.sql" |
| 198 | + fi |
| 199 | + fi |
| 200 | + fi |
| 201 | + '') versions |
| 202 | + } |
| 203 | + fi |
| 204 | + '') packages} |
| 205 | +
|
| 206 | + # Special cross-major-version handling for pgaudit 1.7 |
| 207 | + # Upstream pgaudit git tag 1.7.0 has control file with default_version = '1.7' |
| 208 | + # Users upgrading from PG 15 to PG 17 will have version 1.7 installed |
| 209 | + # We can't read the control file from PG 15 packages when building PG 17, |
| 210 | + # so we hardcode this known mismatch |
| 211 | + ${lib.concatMapStringsSep "\n" (targetVer: '' |
| 212 | + if [[ ! -f "$out/share/postgresql/extension/${pname}--1.7--${targetVer}.sql" ]]; then |
| 213 | + if [[ -f "$out/share/postgresql/extension/${pname}--${targetVer}.sql" ]]; then |
| 214 | + echo "Creating cross-major migration symlink from pgaudit 1.7 to ${targetVer}" |
| 215 | + ln -s "$out/share/postgresql/extension/${pname}--${targetVer}.sql" \ |
| 216 | + "$out/share/postgresql/extension/${pname}--1.7--${targetVer}.sql" |
| 217 | + fi |
| 218 | + fi |
| 219 | + '') versions} |
45 | 220 |
|
46 | | - makeFlags = [ "USE_PGXS=1" ]; |
| 221 | + # Verify all expected library files are present (one per version + symlink) |
| 222 | + expectedFiles=${toString (numberOfVersions + 1)} |
| 223 | + actualFiles=$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l) |
47 | 224 |
|
48 | | - installPhase = '' |
49 | | - install -D -t $out/lib pgaudit${postgresql.dlSuffix} |
50 | | - install -D -t $out/share/postgresql/extension *.sql |
51 | | - install -D -t $out/share/postgresql/extension *.control |
| 225 | + if [[ "$actualFiles" != "$expectedFiles" ]]; then |
| 226 | + echo "Error: Expected $expectedFiles library files, found $actualFiles" |
| 227 | + echo "Files found:" |
| 228 | + ls -la $out/lib/${pname}*${postgresql.dlSuffix} || true |
| 229 | + exit 1 |
| 230 | + fi |
52 | 231 | ''; |
53 | 232 |
|
54 | | - meta = with lib; { |
55 | | - description = "Open Source PostgreSQL Audit Logging"; |
56 | | - homepage = "https://github.com/pgaudit/pgaudit"; |
57 | | - changelog = "https://github.com/pgaudit/pgaudit/releases/tag/${source.version}"; |
58 | | - platforms = postgresql.meta.platforms; |
59 | | - license = licenses.postgresql; |
| 233 | + passthru = { |
| 234 | + inherit versions numberOfVersions; |
| 235 | + pname = "${pname}-all"; |
| 236 | + version = |
| 237 | + "multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions); |
| 238 | + defaultSettings = { |
| 239 | + shared_preload_libraries = "pgaudit"; |
| 240 | + }; |
60 | 241 | }; |
61 | 242 | } |
0 commit comments