chatdesk-ui/postgres_15.8.1.044/flake.nix

895 lines
38 KiB
Nix

{
description = "Prototype tooling for deploying PostgreSQL";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
nix2container.url = "github:nlewo/nix2container";
nix-editor.url = "github:snowfallorg/nix-editor";
rust-overlay.url = "github:oxalica/rust-overlay";
};
outputs = { self, nixpkgs, flake-utils, nix2container, nix-editor, rust-overlay, ...}:
let
gitRev = "vcs=${self.shortRev or "dirty"}+${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}";
ourSystems = with flake-utils.lib; [
system.x86_64-linux
system.aarch64-linux
system.aarch64-darwin
];
in
flake-utils.lib.eachSystem ourSystems (system:
let
pgsqlDefaultPort = "5435";
pgsqlSuperuser = "supabase_admin";
nix2img = nix2container.packages.${system}.nix2container;
pkgs = import nixpkgs {
config = {
allowUnfree = true;
permittedInsecurePackages = [
"v8-9.7.106.18"
];
};
inherit system;
overlays = [
# NOTE: add any needed overlays here. in theory we could
# pull them from the overlays/ directory automatically, but we don't
# want to have an arbitrary order, since it might matter. being
# explicit is better.
(import rust-overlay)
(final: prev: {
cargo-pgrx = final.callPackage ./nix/cargo-pgrx/default.nix {
inherit (final) lib;
inherit (final) darwin;
inherit (final) fetchCrate;
inherit (final) openssl;
inherit (final) pkg-config;
inherit (final) makeRustPlatform;
inherit (final) stdenv;
inherit (final) rust-bin;
};
buildPgrxExtension = final.callPackage ./nix/cargo-pgrx/buildPgrxExtension.nix {
inherit (final) cargo-pgrx;
inherit (final) lib;
inherit (final) Security;
inherit (final) pkg-config;
inherit (final) makeRustPlatform;
inherit (final) stdenv;
inherit (final) writeShellScriptBin;
};
buildPgrxExtension_0_11_3 = prev.buildPgrxExtension.override {
cargo-pgrx = final.cargo-pgrx.cargo-pgrx_0_11_3;
};
buildPgrxExtension_0_12_6 = prev.buildPgrxExtension.override {
cargo-pgrx = final.cargo-pgrx.cargo-pgrx_0_12_6;
};
buildPgrxExtension_0_12_9 = prev.buildPgrxExtension.override {
cargo-pgrx = final.cargo-pgrx.cargo-pgrx_0_12_9;
};
})
(final: prev: {
postgresql = final.callPackage ./nix/postgresql/default.nix {
inherit (final) lib stdenv fetchurl makeWrapper callPackage buildEnv newScope;
};
})
];
};
sfcgal = pkgs.callPackage ./nix/ext/sfcgal/sfcgal.nix { };
supabase-groonga = pkgs.callPackage ./nix/supabase-groonga.nix { };
mecab-naist-jdic = pkgs.callPackage ./nix/ext/mecab-naist-jdic/default.nix { };
# Our list of PostgreSQL extensions which come from upstream Nixpkgs.
# These are maintained upstream and can easily be used here just by
# listing their name. Anytime the version of nixpkgs is upgraded, these
# may also bring in new versions of the extensions.
psqlExtensions = [
/* pljava */
/*"postgis"*/
];
#FIXME for now, timescaledb is not included in the orioledb version of supabase extensions, as there is an issue
# with building timescaledb with the orioledb patched version of postgresql
orioledbPsqlExtensions = [
/* pljava */
/*"timescaledb"*/
];
# Custom extensions that exist in our repository. These aren't upstream
# either because nobody has done the work, maintaining them here is
# easier and more expedient, or because they may not be suitable, or are
# too niche/one-off.
#
# Ideally, most of these should have copies upstream for third party
# use, but even if they did, keeping our own copies means that we can
# rollout new versions of these critical things easier without having to
# go through the upstream release engineering process.
ourExtensions = [
./nix/ext/rum.nix
./nix/ext/timescaledb.nix
./nix/ext/timescaledb-2.9.1.nix
./nix/ext/pgroonga.nix
./nix/ext/index_advisor.nix
./nix/ext/wal2json.nix
./nix/ext/pgmq.nix
./nix/ext/pg_repack.nix
./nix/ext/pg-safeupdate.nix
./nix/ext/plpgsql-check.nix
./nix/ext/pgjwt.nix
./nix/ext/pgaudit.nix
./nix/ext/postgis.nix
./nix/ext/pgrouting.nix
./nix/ext/pgtap.nix
./nix/ext/pg_backtrace.nix
./nix/ext/pg_cron.nix
./nix/ext/pgsql-http.nix
./nix/ext/pg_plan_filter.nix
./nix/ext/pg_net.nix
./nix/ext/pg_hashids.nix
./nix/ext/pgsodium.nix
./nix/ext/pg_graphql.nix
./nix/ext/pg_stat_monitor.nix
./nix/ext/pg_jsonschema.nix
./nix/ext/pgvector.nix
./nix/ext/vault.nix
./nix/ext/hypopg.nix
./nix/ext/pg_tle.nix
./nix/ext/wrappers/default.nix
./nix/ext/supautils.nix
./nix/ext/plv8.nix
];
#Where we import and build the orioledb extension, we add on our custom extensions
# plus the orioledb option
#we're not using timescaledb in the orioledb version of supabase extensions
orioleFilteredExtensions = builtins.filter (
x:
x != ./nix/ext/timescaledb.nix &&
x != ./nix/ext/timescaledb-2.9.1.nix &&
x != ./nix/ext/plv8.nix
) ourExtensions;
orioledbExtensions = orioleFilteredExtensions ++ [ ./nix/ext/orioledb.nix ];
getPostgresqlPackage = version:
pkgs.postgresql."postgresql_${version}";
# Create a 'receipt' file for a given postgresql package. This is a way
# of adding a bit of metadata to the package, which can be used by other
# tools to inspect what the contents of the install are: the PSQL
# version, the installed extensions, et cetera.
#
# This takes three arguments:
# - pgbin: the postgresql package we are building on top of
# - upstreamExts: the list of extensions from upstream nixpkgs. This is
# not a list of packages, but an attrset containing extension names
# mapped to versions.
# - ourExts: the list of extensions from upstream nixpkgs. This is not
# a list of packages, but an attrset containing extension names
# mapped to versions.
#
# The output is a package containing the receipt.json file, which can be
# merged with the PostgreSQL installation using 'symlinkJoin'.
makeReceipt = pgbin: upstreamExts: ourExts: pkgs.writeTextFile {
name = "receipt";
destination = "/receipt.json";
text = builtins.toJSON {
revision = gitRev;
psql-version = pgbin.version;
nixpkgs = {
revision = nixpkgs.rev;
extensions = upstreamExts;
};
extensions = ourExts;
# NOTE this field can be used to do cache busting (e.g.
# force a rebuild of the psql packages) but also to helpfully inform
# tools what version of the schema is being used, for forwards and
# backwards compatibility
receipt-version = "1";
};
};
makeOurPostgresPkgs = version:
let
postgresql = getPostgresqlPackage version;
extensionsToUse = if (builtins.elem version ["orioledb-17"])
then orioledbExtensions
else ourExtensions;
in map (path: pkgs.callPackage path { inherit postgresql; }) extensionsToUse;
# Create an attrset that contains all the extensions included in a server.
makeOurPostgresPkgsSet = version:
(builtins.listToAttrs (map
(drv:
{ name = drv.pname; value = drv; }
)
(makeOurPostgresPkgs version)))
// { recurseForDerivations = true; };
# Create a binary distribution of PostgreSQL, given a version.
#
# NOTE: The version here does NOT refer to the exact PostgreSQL version;
# it refers to the *major number only*, which is used to select the
# correct version of the package from nixpkgs. This is because we want
# to be able to do so in an open ended way. As an example, the version
# "15" passed in will use the nixpkgs package "postgresql_15" as the
# basis for building extensions, etc.
makePostgresBin = version:
let
postgresql = getPostgresqlPackage version;
upstreamExts = map
(ext: {
name = postgresql.pkgs."${ext}".pname;
version = postgresql.pkgs."${ext}".version;
})
psqlExtensions;
ourExts = map (ext: { name = ext.pname; version = ext.version; }) (makeOurPostgresPkgs version);
pgbin = postgresql.withPackages (ps:
(map (ext: ps."${ext}") psqlExtensions) ++ (makeOurPostgresPkgs version)
);
in
pkgs.symlinkJoin {
inherit (pgbin) name version;
paths = [ pgbin (makeReceipt pgbin upstreamExts ourExts) ];
};
# Create an attribute set, containing all the relevant packages for a
# PostgreSQL install, wrapped up with a bow on top. There are three
# packages:
#
# - bin: the postgresql package itself, with all the extensions
# installed, and a receipt.json file containing metadata about the
# install.
# - exts: an attrset containing all the extensions, mapped to their
# package names.
makePostgres = version: rec {
bin = makePostgresBin version;
exts = makeOurPostgresPkgsSet version;
recurseForDerivations = true;
};
makePostgresDevSetup = { pkgs, name, extraSubstitutions ? {} }:
let
paths = {
migrationsDir = builtins.path {
name = "migrations";
path = ./migrations/db;
};
postgresqlSchemaSql = builtins.path {
name = "postgresql-schema";
path = ./nix/tools/postgresql_schema.sql;
};
pgbouncerAuthSchemaSql = builtins.path {
name = "pgbouncer-auth-schema";
path = ./ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql;
};
statExtensionSql = builtins.path {
name = "stat-extension";
path = ./ansible/files/stat_extension.sql;
};
pgconfigFile = builtins.path {
name = "postgresql.conf";
path = ./ansible/files/postgresql_config/postgresql.conf.j2;
};
supautilsConfigFile = builtins.path {
name = "supautils.conf";
path = ./ansible/files/postgresql_config/supautils.conf.j2;
};
loggingConfigFile = builtins.path {
name = "logging.conf";
path = ./ansible/files/postgresql_config/postgresql-csvlog.conf;
};
readReplicaConfigFile = builtins.path {
name = "readreplica.conf";
path = ./ansible/files/postgresql_config/custom_read_replica.conf.j2;
};
pgHbaConfigFile = builtins.path {
name = "pg_hba.conf";
path = ./ansible/files/postgresql_config/pg_hba.conf.j2;
};
pgIdentConfigFile = builtins.path {
name = "pg_ident.conf";
path = ./ansible/files/postgresql_config/pg_ident.conf.j2;
};
postgresqlExtensionCustomScriptsPath = builtins.path {
name = "extension-custom-scripts";
path = ./ansible/files/postgresql_extension_custom_scripts;
};
getkeyScript = builtins.path {
name = "pgsodium_getkey.sh";
path = ./nix/tests/util/pgsodium_getkey.sh;
};
};
localeArchive = if pkgs.stdenv.isDarwin
then "${pkgs.darwin.locale}/share/locale"
else "${pkgs.glibcLocales}/lib/locale/locale-archive";
substitutions = {
SHELL_PATH = "${pkgs.bash}/bin/bash";
PGSQL_DEFAULT_PORT = "${pgsqlDefaultPort}";
PGSQL_SUPERUSER = "${pgsqlSuperuser}";
PSQL15_BINDIR = "${basePackages.psql_15.bin}";
PSQL_CONF_FILE = "${paths.pgconfigFile}";
PSQLORIOLEDB17_BINDIR = "${basePackages.psql_orioledb-17.bin}";
PGSODIUM_GETKEY = "${paths.getkeyScript}";
READREPL_CONF_FILE = "${paths.readReplicaConfigFile}";
LOGGING_CONF_FILE = "${paths.loggingConfigFile}";
SUPAUTILS_CONF_FILE = "${paths.supautilsConfigFile}";
PG_HBA = "${paths.pgHbaConfigFile}";
PG_IDENT = "${paths.pgIdentConfigFile}";
LOCALES = "${localeArchive}";
EXTENSION_CUSTOM_SCRIPTS_DIR = "${paths.postgresqlExtensionCustomScriptsPath}";
MECAB_LIB = "${basePackages.psql_15.exts.pgroonga}/lib/groonga/plugins/tokenizers/tokenizer_mecab.so";
GROONGA_DIR = "${supabase-groonga}";
MIGRATIONS_DIR = "${paths.migrationsDir}";
POSTGRESQL_SCHEMA_SQL = "${paths.postgresqlSchemaSql}";
PGBOUNCER_AUTH_SCHEMA_SQL = "${paths.pgbouncerAuthSchemaSql}";
STAT_EXTENSION_SQL = "${paths.statExtensionSql}";
CURRENT_SYSTEM = "${system}";
} // extraSubstitutions; # Merge in any extra substitutions
in pkgs.runCommand name {
inherit (paths) migrationsDir postgresqlSchemaSql pgbouncerAuthSchemaSql statExtensionSql;
} ''
set -x
mkdir -p $out/bin $out/etc/postgresql-custom $out/etc/postgresql $out/extension-custom-scripts
# Copy config files with error handling
cp ${paths.supautilsConfigFile} $out/etc/postgresql-custom/supautils.conf || { echo "Failed to copy supautils.conf"; exit 1; }
cp ${paths.pgconfigFile} $out/etc/postgresql/postgresql.conf || { echo "Failed to copy postgresql.conf"; exit 1; }
cp ${paths.loggingConfigFile} $out/etc/postgresql-custom/logging.conf || { echo "Failed to copy logging.conf"; exit 1; }
cp ${paths.readReplicaConfigFile} $out/etc/postgresql-custom/read-replica.conf || { echo "Failed to copy read-replica.conf"; exit 1; }
cp ${paths.pgHbaConfigFile} $out/etc/postgresql/pg_hba.conf || { echo "Failed to copy pg_hba.conf"; exit 1; }
cp ${paths.pgIdentConfigFile} $out/etc/postgresql/pg_ident.conf || { echo "Failed to copy pg_ident.conf"; exit 1; }
cp -r ${paths.postgresqlExtensionCustomScriptsPath}/* $out/extension-custom-scripts/ || { echo "Failed to copy custom scripts"; exit 1; }
echo "Copy operation completed"
chmod 644 $out/etc/postgresql-custom/supautils.conf
chmod 644 $out/etc/postgresql/postgresql.conf
chmod 644 $out/etc/postgresql-custom/logging.conf
chmod 644 $out/etc/postgresql/pg_hba.conf
substitute ${./nix/tools/run-server.sh.in} $out/bin/start-postgres-server \
${builtins.concatStringsSep " " (builtins.attrValues (builtins.mapAttrs
(name: value: "--subst-var-by '${name}' '${value}'")
substitutions
))}
chmod +x $out/bin/start-postgres-server
'';
# The base set of packages that we export from this Nix Flake, that can
# be used with 'nix build'. Don't use the names listed below; check the
# name in 'nix flake show' in order to make sure exactly what name you
# want.
basePackages = let
# Function to get the PostgreSQL version from the attribute name
getVersion = name:
let
match = builtins.match "psql_([0-9]+)" name;
in
if match == null then null else builtins.head match;
# Define the available PostgreSQL versions
postgresVersions = {
psql_15 = makePostgres "15";
psql_orioledb-17 = makePostgres "orioledb-17" ;
};
# Find the active PostgreSQL version
activeVersion = getVersion (builtins.head (builtins.attrNames postgresVersions));
# Function to create the pg_regress package
makePgRegress = version:
let
postgresqlPackage = pkgs."postgresql_${version}";
in
pkgs.callPackage ./nix/ext/pg_regress.nix {
postgresql = postgresqlPackage;
};
postgresql_15 = getPostgresqlPackage "15";
postgresql_orioledb-17 = getPostgresqlPackage "orioledb-17";
in
postgresVersions // {
supabase-groonga = supabase-groonga;
cargo-pgrx_0_11_3 = pkgs.cargo-pgrx.cargo-pgrx_0_11_3;
cargo-pgrx_0_12_6 = pkgs.cargo-pgrx.cargo-pgrx_0_12_6;
cargo-pgrx_0_12_9 = pkgs.cargo-pgrx.cargo-pgrx_0_12_9;
# PostgreSQL versions.
psql_15 = postgresVersions.psql_15;
psql_orioledb-17 = postgresVersions.psql_orioledb-17;
sfcgal = sfcgal;
pg_prove = pkgs.perlPackages.TAPParserSourceHandlerpgTAP;
inherit postgresql_15 postgresql_orioledb-17;
postgresql_15_debug = if pkgs.stdenv.isLinux then postgresql_15.debug else null;
postgresql_orioledb-17_debug = if pkgs.stdenv.isLinux then postgresql_orioledb-17.debug else null;
postgresql_15_src = pkgs.stdenv.mkDerivation {
pname = "postgresql-15-src";
version = postgresql_15.version;
src = postgresql_15.src;
nativeBuildInputs = [ pkgs.bzip2 ];
phases = [ "unpackPhase" "installPhase" ];
installPhase = ''
mkdir -p $out
cp -r . $out
'';
meta = with pkgs.lib; {
description = "PostgreSQL 15 source files";
homepage = "https://www.postgresql.org/";
license = licenses.postgresql;
platforms = platforms.all;
};
};
postgresql_orioledb-17_src = pkgs.stdenv.mkDerivation {
pname = "postgresql-17-src";
version = postgresql_orioledb-17.version;
src = postgresql_orioledb-17.src;
nativeBuildInputs = [ pkgs.bzip2 ];
phases = [ "unpackPhase" "installPhase" ];
installPhase = ''
mkdir -p $out
cp -r . $out
'';
meta = with pkgs.lib; {
description = "PostgreSQL 15 source files";
homepage = "https://www.postgresql.org/";
license = licenses.postgresql;
platforms = platforms.all;
};
};
mecab_naist_jdic = mecab-naist-jdic;
supabase_groonga = supabase-groonga;
pg_regress = makePgRegress activeVersion;
# Start a version of the server.
start-server = makePostgresDevSetup {
inherit pkgs;
name = "start-postgres-server";
};
# Start a version of the client and runs migrations script on server.
start-client =
let
migrationsDir = ./migrations/db;
postgresqlSchemaSql = ./nix/tools/postgresql_schema.sql;
pgbouncerAuthSchemaSql = ./ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql;
statExtensionSql = ./ansible/files/stat_extension.sql;
in
pkgs.runCommand "start-postgres-client" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/run-client.sh.in} $out/bin/start-postgres-client \
--subst-var-by 'PGSQL_DEFAULT_PORT' '${pgsqlDefaultPort}' \
--subst-var-by 'PGSQL_SUPERUSER' '${pgsqlSuperuser}' \
--subst-var-by 'PSQL15_BINDIR' '${basePackages.psql_15.bin}' \
--subst-var-by 'PSQLORIOLEDB17_BINDIR' '${basePackages.psql_orioledb-17.bin}' \
--subst-var-by 'MIGRATIONS_DIR' '${migrationsDir}' \
--subst-var-by 'POSTGRESQL_SCHEMA_SQL' '${postgresqlSchemaSql}' \
--subst-var-by 'PGBOUNCER_AUTH_SCHEMA_SQL' '${pgbouncerAuthSchemaSql}' \
--subst-var-by 'STAT_EXTENSION_SQL' '${statExtensionSql}'
chmod +x $out/bin/start-postgres-client
'';
# Migrate between two data directories.
migrate-tool =
let
configFile = ./nix/tests/postgresql.conf.in;
getkeyScript = ./nix/tests/util/pgsodium_getkey.sh;
primingScript = ./nix/tests/prime.sql;
migrationData = ./nix/tests/migrations/data.sql;
in
pkgs.runCommand "migrate-postgres" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/migrate-tool.sh.in} $out/bin/migrate-postgres \
--subst-var-by 'PSQL15_BINDIR' '${basePackages.psql_15.bin}' \
--subst-var-by 'PSQL_CONF_FILE' '${configFile}' \
--subst-var-by 'PGSODIUM_GETKEY' '${getkeyScript}' \
--subst-var-by 'PRIMING_SCRIPT' '${primingScript}' \
--subst-var-by 'MIGRATION_DATA' '${migrationData}'
chmod +x $out/bin/migrate-postgres
'';
start-replica = pkgs.runCommand "start-postgres-replica" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/run-replica.sh.in} $out/bin/start-postgres-replica \
--subst-var-by 'PGSQL_SUPERUSER' '${pgsqlSuperuser}' \
--subst-var-by 'PSQL15_BINDIR' '${basePackages.psql_15.bin}'
chmod +x $out/bin/start-postgres-replica
'';
pg-restore =
pkgs.runCommand "run-pg-restore" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/run-restore.sh.in} $out/bin/pg-restore \
--subst-var-by PSQL15_BINDIR '${basePackages.psql_15.bin}'
chmod +x $out/bin/pg-restore
'';
sync-exts-versions = pkgs.runCommand "sync-exts-versions" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/sync-exts-versions.sh.in} $out/bin/sync-exts-versions \
--subst-var-by 'YQ' '${pkgs.yq}/bin/yq' \
--subst-var-by 'JQ' '${pkgs.jq}/bin/jq' \
--subst-var-by 'NIX_EDITOR' '${nix-editor.packages.${system}.nix-editor}/bin/nix-editor' \
--subst-var-by 'NIXPREFETCHURL' '${pkgs.nixVersions.nix_2_20}/bin/nix-prefetch-url' \
--subst-var-by 'NIX' '${pkgs.nixVersions.nix_2_20}/bin/nix'
chmod +x $out/bin/sync-exts-versions
'';
local-infra-bootstrap = pkgs.runCommand "local-infra-bootstrap" { } ''
mkdir -p $out/bin
substitute ${./nix/tools/local-infra-bootstrap.sh.in} $out/bin/local-infra-bootstrap
chmod +x $out/bin/local-infra-bootstrap
'';
dbmate-tool =
let
migrationsDir = ./migrations/db;
ansibleVars = ./ansible/vars.yml;
pgbouncerAuthSchemaSql = ./ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql;
statExtensionSql = ./ansible/files/stat_extension.sql;
in
pkgs.runCommand "dbmate-tool" {
buildInputs = with pkgs; [
overmind
dbmate
nix
jq
yq
];
nativeBuildInputs = with pkgs; [
makeWrapper
];
} ''
mkdir -p $out/bin $out/migrations
cp -r ${migrationsDir}/* $out
substitute ${./nix/tools/dbmate-tool.sh.in} $out/bin/dbmate-tool \
--subst-var-by 'PGSQL_DEFAULT_PORT' '${pgsqlDefaultPort}' \
--subst-var-by 'MIGRATIONS_DIR' $out \
--subst-var-by 'PGSQL_SUPERUSER' '${pgsqlSuperuser}' \
--subst-var-by 'ANSIBLE_VARS' ${ansibleVars} \
--subst-var-by 'CURRENT_SYSTEM' '${system}' \
--subst-var-by 'PGBOUNCER_AUTH_SCHEMA_SQL' '${pgbouncerAuthSchemaSql}' \
--subst-var-by 'STAT_EXTENSION_SQL' '${statExtensionSql}'
chmod +x $out/bin/dbmate-tool
wrapProgram $out/bin/dbmate-tool \
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.overmind pkgs.dbmate pkgs.nix pkgs.jq pkgs.yq ]}
'';
update-readme = pkgs.runCommand "update-readme" {
nativeBuildInputs = [ pkgs.makeWrapper ];
buildInputs = [ pkgs.nushell ];
} ''
mkdir -p $out/bin
cp ${./nix/tools/update_readme.nu} $out/bin/update-readme
chmod +x $out/bin/update-readme
wrapProgram $out/bin/update-readme \
--prefix PATH : ${pkgs.nushell}/bin
'';
};
# Create a testing harness for a PostgreSQL package. This is used for
# 'nix flake check', and works with any PostgreSQL package you hand it.
makeCheckHarness = pgpkg:
let
sqlTests = ./nix/tests/smoke;
pg_prove = pkgs.perlPackages.TAPParserSourceHandlerpgTAP;
pg_regress = basePackages.pg_regress;
getkey-script = pkgs.writeScriptBin "pgsodium-getkey" ''
#!${pkgs.bash}/bin/bash
set -euo pipefail
TMPDIR_BASE=$(mktemp -d)
if [[ "$(uname)" == "Darwin" ]]; then
KEY_DIR="/private/tmp/pgsodium"
else
KEY_DIR="''${PGSODIUM_KEY_DIR:-$TMPDIR_BASE/pgsodium}"
fi
KEY_FILE="$KEY_DIR/pgsodium.key"
if ! mkdir -p "$KEY_DIR" 2>/dev/null; then
echo "Error: Could not create key directory $KEY_DIR" >&2
exit 1
fi
chmod 1777 "$KEY_DIR"
if [[ ! -f "$KEY_FILE" ]]; then
if ! (dd if=/dev/urandom bs=32 count=1 2>/dev/null | od -A n -t x1 | tr -d ' \n' > "$KEY_FILE"); then
if ! (openssl rand -hex 32 > "$KEY_FILE"); then
echo "00000000000000000000000000000000" > "$KEY_FILE"
echo "Warning: Using fallback key" >&2
fi
fi
chmod 644 "$KEY_FILE"
fi
if [[ -f "$KEY_FILE" && -r "$KEY_FILE" ]]; then
cat "$KEY_FILE"
else
echo "Error: Cannot read key file $KEY_FILE" >&2
exit 1
fi
'';
# Use the shared setup but with a test-specific name
start-postgres-server-bin = makePostgresDevSetup {
inherit pkgs;
name = "start-postgres-server-test";
extraSubstitutions = {
PGSODIUM_GETKEY = "${getkey-script}/bin/pgsodium-getkey";
};
};
getVersionArg = pkg:
let
name = pkg.version;
in
if builtins.match "15.*" name != null then "15"
else if builtins.match "17.*" name != null then "orioledb-17"
else throw "Unsupported PostgreSQL version: ${name}";
# Helper function to filter SQL files based on version
filterTestFiles = version: dir:
let
files = builtins.readDir dir;
isValidFile = name:
let
isVersionSpecific = builtins.match "z_([0-9]+)_.*" name != null;
matchesVersion =
if isVersionSpecific
then builtins.match ("z_" + version + "_.*") name != null
else true;
in
pkgs.lib.hasSuffix ".sql" name && matchesVersion;
in
pkgs.lib.filterAttrs (name: _: isValidFile name) files;
# Get the major version for filtering
majorVersion =
if builtins.match ".*17.*" pgpkg.version != null
then "17"
else "15";
# Filter SQL test files
filteredSqlTests = filterTestFiles majorVersion ./nix/tests/sql;
# Convert filtered tests to a sorted list of basenames (without extension)
testList = pkgs.lib.mapAttrsToList (name: _:
builtins.substring 0 (pkgs.lib.stringLength name - 4) name
) filteredSqlTests;
sortedTestList = builtins.sort (a: b: a < b) testList;
in
pkgs.runCommand "postgres-${pgpkg.version}-check-harness"
{
nativeBuildInputs = with pkgs; [
coreutils bash perl pgpkg pg_prove pg_regress procps
start-postgres-server-bin which getkey-script supabase-groonga
];
} ''
set -e
#First we need to create a generic pg cluster for pgtap tests and run those
export GRN_PLUGINS_DIR=${supabase-groonga}/lib/groonga/plugins
PGTAP_CLUSTER=$(mktemp -d)
initdb --locale=C --username=supabase_admin -D "$PGTAP_CLUSTER"
substitute ${./nix/tests/postgresql.conf.in} "$PGTAP_CLUSTER"/postgresql.conf \
--subst-var-by PGSODIUM_GETKEY_SCRIPT "${getkey-script}/bin/pgsodium-getkey"
echo "listen_addresses = '*'" >> "$PGTAP_CLUSTER"/postgresql.conf
echo "port = 5435" >> "$PGTAP_CLUSTER"/postgresql.conf
echo "host all all 127.0.0.1/32 trust" >> $PGTAP_CLUSTER/pg_hba.conf
# Remove timescaledb if running orioledb-17 check
echo "I AM ${pgpkg.version}===================================================="
if [[ "${pgpkg.version}" == *"17"* ]]; then
perl -pi -e 's/ timescaledb,//g' "$PGTAP_CLUSTER/postgresql.conf"
fi
#NOTE in the future we may also need to add the orioledb extension to the cluster when cluster is oriole
echo "PGTAP_CLUSTER directory contents:"
ls -la "$PGTAP_CLUSTER"
# Check if postgresql.conf exists
if [ ! -f "$PGTAP_CLUSTER/postgresql.conf" ]; then
echo "postgresql.conf is missing!"
exit 1
fi
# PostgreSQL startup
if [[ "$(uname)" == "Darwin" ]]; then
pg_ctl -D "$PGTAP_CLUSTER" -l "$PGTAP_CLUSTER"/postgresql.log -o "-k "$PGTAP_CLUSTER" -p 5435 -d 5" start 2>&1
else
mkdir -p "$PGTAP_CLUSTER/sockets"
pg_ctl -D "$PGTAP_CLUSTER" -l "$PGTAP_CLUSTER"/postgresql.log -o "-k $PGTAP_CLUSTER/sockets -p 5435 -d 5" start 2>&1
fi || {
echo "pg_ctl failed to start PostgreSQL"
echo "Contents of postgresql.log:"
cat "$PGTAP_CLUSTER"/postgresql.log
exit 1
}
for i in {1..60}; do
if pg_isready -h localhost -p 5435; then
echo "PostgreSQL is ready"
break
fi
sleep 1
if [ $i -eq 60 ]; then
echo "PostgreSQL is not ready after 60 seconds"
echo "PostgreSQL status:"
pg_ctl -D "$PGTAP_CLUSTER" status
echo "PostgreSQL log content:"
cat "$PGTAP_CLUSTER"/postgresql.log
exit 1
fi
done
createdb -p 5435 -h localhost --username=supabase_admin testing
if ! psql -p 5435 -h localhost --username=supabase_admin -d testing -v ON_ERROR_STOP=1 -Xaf ${./nix/tests/prime.sql}; then
echo "Error executing SQL file. PostgreSQL log content:"
cat "$PGTAP_CLUSTER"/postgresql.log
pg_ctl -D "$PGTAP_CLUSTER" stop
exit 1
fi
SORTED_DIR=$(mktemp -d)
for t in $(printf "%s\n" ${builtins.concatStringsSep " " sortedTestList}); do
psql -p 5435 -h localhost --username=supabase_admin -d testing -f "${./nix/tests/sql}/$t.sql" || true
done
rm -rf "$SORTED_DIR"
pg_ctl -D "$PGTAP_CLUSTER" stop
rm -rf $PGTAP_CLUSTER
# End of pgtap tests
# from here on out we are running pg_regress tests, we use a different cluster for this
# which is start by the start-postgres-server-bin script
# start-postgres-server-bin script closely matches our AMI setup, configurations and migrations
# Ensure pgsodium key directory exists with proper permissions
if [[ "$(uname)" == "Darwin" ]]; then
mkdir -p /private/tmp/pgsodium
chmod 1777 /private/tmp/pgsodium
fi
unset GRN_PLUGINS_DIR
${start-postgres-server-bin}/bin/start-postgres-server ${getVersionArg pgpkg} --daemonize
for i in {1..60}; do
if pg_isready -h localhost -p 5435 -U supabase_admin -q; then
echo "PostgreSQL is ready"
break
fi
sleep 1
if [ $i -eq 60 ]; then
echo "PostgreSQL failed to start"
exit 1
fi
done
if ! psql -p 5435 -h localhost --no-password --username=supabase_admin -d postgres -v ON_ERROR_STOP=1 -Xaf ${./nix/tests/prime.sql}; then
echo "Error executing SQL file"
exit 1
fi
mkdir -p $out/regression_output
if ! pg_regress \
--use-existing \
--dbname=postgres \
--inputdir=${./nix/tests} \
--outputdir=$out/regression_output \
--host=localhost \
--port=5435 \
--user=supabase_admin \
${builtins.concatStringsSep " " sortedTestList}; then
echo "pg_regress tests failed"
exit 1
fi
# Copy logs to output
for logfile in $(find /tmp -name postgresql.log -type f); do
cp "$logfile" $out/postgresql.log
done
exit 0
'';
in
rec {
# The list of all packages that can be built with 'nix build'. The list
# of names that can be used can be shown with 'nix flake show'
packages = flake-utils.lib.flattenTree basePackages // {
# Any extra packages we might want to include in our package
# set can go here.
inherit (pkgs);
};
# The list of exported 'checks' that are run with every run of 'nix
# flake check'. This is run in the CI system, as well.
checks = {
psql_15 = makeCheckHarness basePackages.psql_15.bin;
psql_orioledb-17 = makeCheckHarness basePackages.psql_orioledb-17.bin;
};
# Apps is a list of names of things that can be executed with 'nix run';
# these are distinct from the things that can be built with 'nix build',
# so they need to be listed here too.
apps =
let
mkApp = attrName: binName: {
type = "app";
program = "${basePackages."${attrName}"}/bin/${binName}";
};
in
{
start-server = mkApp "start-server" "start-postgres-server";
start-client = mkApp "start-client" "start-postgres-client";
start-replica = mkApp "start-replica" "start-postgres-replica";
migrate-postgres = mkApp "migrate-tool" "migrate-postgres";
sync-exts-versions = mkApp "sync-exts-versions" "sync-exts-versions";
pg-restore = mkApp "pg-restore" "pg-restore";
local-infra-bootstrap = mkApp "local-infra-bootstrap" "local-infra-bootstrap";
dbmate-tool = mkApp "dbmate-tool" "dbmate-tool";
update-readme = mkApp "update-readme" "update-readme";
};
# 'devShells.default' lists the set of packages that are included in the
# ambient $PATH environment when you run 'nix develop'. This is useful
# for development and puts many convenient devtools instantly within
# reach.
devShells = let
mkCargoPgrxDevShell = { pgrxVersion, rustVersion }: pkgs.mkShell {
packages = with pkgs; [
basePackages."cargo-pgrx_${pgrxVersion}"
(rust-bin.stable.${rustVersion}.default.override {
extensions = [ "rust-src" ];
})
];
shellHook = ''
export HISTFILE=.history
'';
};
in {
default = pkgs.mkShell {
packages = with pkgs; [
coreutils
just
nix-update
#pg_prove
shellcheck
ansible
ansible-lint
(packer.overrideAttrs (oldAttrs: {
version = "1.7.8";
}))
basePackages.start-server
basePackages.start-client
basePackages.start-replica
basePackages.migrate-tool
basePackages.sync-exts-versions
dbmate
nushell
];
shellHook = ''
export HISTFILE=.history
'';
};
cargo-pgrx_0_11_3 = mkCargoPgrxDevShell {
pgrxVersion = "0_11_3";
rustVersion = "1.80.0";
};
cargo-pgrx_0_12_6 = mkCargoPgrxDevShell {
pgrxVersion = "0_12_6";
rustVersion = "1.80.0";
};
};
}
);
}