Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
281 lines (245 loc) · 11.9 KB
/
Copy pathMakefile
File metadata and controls
281 lines (245 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# Copyright (c) Microsoft Corporation.
# Licensed under the PostgreSQL License.
# pg_durable Makefile
# PostgreSQL major version for pgrx (override with: make ... PG_VERSION=pg18)
PG_VERSION ?= pg17
CARGO ?= cargo
EXTRA_FEATURES ?=
ACR_REGISTRY ?= myregistry.azurecr.io
ACR_IMAGE ?= pg_durable
.PHONY: all build package install uninstall test test-unit test-e2e test-regress pg-clean docker-build docker-push pg-install META.json pgxn-zip install-pgrx pgrx-init
# Default target
all: package
# Build the extension
build:
cargo build
# Build release artifacts for source installation. This runs without elevated
# privileges; `install` only copies the resulting package tree.
package:
@if test -e "$(PGRX_PACKAGE_DIR)" \
&& test "$(PGRX_PACKAGE_DIR)" != "$(DEFAULT_PGRX_PACKAGE_DIR)" \
&& test ! -f "$(PGRX_PACKAGE_MARKER)" \
&& { test ! -d "$(PGRX_PACKAGE_DIR)" \
|| test -n "$$(ls -A "$(PGRX_PACKAGE_DIR)" 2>/dev/null)"; }; then \
echo "refusing to replace unowned package directory: $(PGRX_PACKAGE_DIR)" >&2; \
exit 1; \
fi
@set -eu; \
if test ! -f "$(PGRX_CONFIG)"; then \
if test "$(PGRX_AUTO_INIT)" = "0"; then \
echo "cargo-pgrx is not initialized: $(PGRX_CONFIG) not found" >&2; \
echo "run: $(MAKE) pgrx-init PG_CONFIG=\"$(PG_CONFIG)\"" >&2; \
exit 1; \
fi; \
echo "cargo-pgrx is not initialized; running 'cargo pgrx init --pg$(PG_MAJOR)'"; \
$(CARGO) pgrx init --pg$(PG_MAJOR) "$(PG_CONFIG)"; \
fi
rm -rf "$(PGRX_PACKAGE_DIR)"
$(CARGO) pgrx package --pg-config "$(PG_CONFIG)" \
--out-dir "$(PGRX_PACKAGE_DIR)" \
--no-default-features --features "$(strip pg$(PG_MAJOR) $(EXTRA_FEATURES))"
@touch "$(PGRX_PACKAGE_MARKER)"
# Run all tests (unit + E2E)
test:
./scripts/test.sh --all
# Run only pgrx unit tests
test-unit:
./scripts/test.sh --unit
# Run only E2E tests (Docker-based)
test-e2e:
./scripts/test.sh --e2e
# Build Docker image
docker-build:
docker build --platform linux/amd64 -t pg_durable:latest .
# Build and push to ACR
docker-push: docker-build
docker tag pg_durable:latest $(ACR_REGISTRY)/$(ACR_IMAGE):latest
REGISTRY_NAME="$(ACR_REGISTRY)"; az acr login --name "$${REGISTRY_NAME%%.*}"
docker push $(ACR_REGISTRY)/$(ACR_IMAGE):latest
# Run local development server
run:
cargo pgrx run pg17
# Clean build artifacts (renamed to avoid PGXS conflict)
pg-clean:
cargo clean
rm -rf target/
rm -f META.json $(DISTNAME)-$(DISTVERSION).zip
# Install extension locally (renamed to avoid PGXS conflict)
pg-install:
cargo pgrx install
# Run pg_regress tests (convenience target)
# Override version: make test-regress PG_VERSION=pg18
test-regress:
@echo "Resetting PostgreSQL..."
./scripts/pg-reset.sh $(subst pg,,$(PG_VERSION))
@echo "Starting PostgreSQL with PGDATABASE=contrib_regression..."
PGDATABASE=contrib_regression ./scripts/pg-start.sh --pg-version $(subst pg,,$(PG_VERSION))
@echo "Running pg_regress tests..."
PGHOST=$(HOME)/.pgrx PGUSER=postgres PG_CONFIG=$$(cargo pgrx info pg-config $(PG_VERSION)) $(MAKE) -e installcheck
# Help
help:
@echo "pg_durable Makefile targets:"
@echo ""
@echo " all - Build release artifacts for source installation"
@echo " build - Build the extension in debug mode"
@echo " package - Build release artifacts for source installation"
@echo " test - Run all tests (unit + E2E)"
@echo " test-unit - Run pgrx unit tests only"
@echo " test-e2e - Run E2E tests only (Docker)"
@echo " test-regress - Run pg_regress tests (resets and starts PostgreSQL)"
@echo " installcheck - Run pg_regress tests (requires PostgreSQL running, via PGXS)"
@echo " docker-build - Build Docker image"
@echo " docker-push - Build and push to ACR"
@echo " run - Start local pgrx dev server"
@echo " pg-clean - Clean build artifacts"
@echo " install - Install prebuilt artifacts for the selected PostgreSQL"
@echo " uninstall - Remove installed artifacts for the selected PostgreSQL"
@echo " pg-install - Install extension locally"
@echo " pgxn-zip - Build the PGXN release bundle (META.json + zip)"
@echo " install-pgrx - Install the cargo-pgrx release pinned in Cargo.toml"
@echo " pgrx-init - Register PG_CONFIG with cargo-pgrx (needed once per machine)"
# ============================================================================
# cargo-pgrx toolchain
# ============================================================================
# cargo-pgrx keeps its configuration in $PGRX_HOME (default ~/.pgrx) and refuses
# to build without it, failing with "$PGRX_HOME does not exist" or
# "config.toml not found". Only `cargo pgrx init` creates that file.
#
# Installers that drive this Makefile never run it: `pgxn install pg_durable`
# runs `make all` and then `make install`, so on a machine that has PostgreSQL,
# Rust and cargo-pgrx but has never initialized pgrx, `package` failed before
# the guard in that target existed.
#
# Only the presence of config.toml matters. `package` always passes an explicit
# --pg-config, so the entries recorded in that file are never consulted, and an
# existing pgrx configuration naming a different PostgreSQL cannot redirect the
# build.
PGRX_VERSION = $(shell sed -nE 's/^pgrx[[:space:]]*=[[:space:]]*"=?([0-9][^"]*)".*/\1/p' Cargo.toml | head -1)
PGRX_HOME_DIR = $(if $(PGRX_HOME),$(PGRX_HOME),$(HOME)/.pgrx)
PGRX_CONFIG = $(PGRX_HOME_DIR)/config.toml
# Install the cargo-pgrx release pinned in Cargo.toml, so the build tool and the
# pgrx crate cannot drift apart.
install-pgrx:
$(CARGO) install --locked cargo-pgrx --version "$(PGRX_VERSION)"
# Register PG_CONFIG with cargo-pgrx. Passing an existing pg_config makes this a
# validate-and-record step: cargo-pgrx does not download or build a PostgreSQL
# of its own.
pgrx-init:
$(CARGO) pgrx init --pg$(PG_MAJOR) "$(PG_CONFIG)"
# ============================================================================
# PGXN packaging
# ============================================================================
# The distribution version is read from Cargo.toml so the PGXN metadata can
# never drift from the crate version. META.json is generated, not committed.
DISTNAME = pg_durable
PGXN_TREEISH ?= HEAD
DISTVERSION = $(shell git show "$(PGXN_TREEISH):Cargo.toml" \
| sed -n 's/^version = "\(.*\)"/\1/p' | head -1)
PGXN_META ?= $(CURDIR)/META.json
PGXN_ARCHIVE ?= $(CURDIR)/$(DISTNAME)-$(DISTVERSION).zip
PGXN_README_TEMPLATE = pgxn/README.md.in
PGXN_INDEXED_DOCS = pgxn/indexed-docs.txt
# Render the PGXN metadata, stamping in the Cargo.toml version and deriving
# no_index from the explicit reader-facing documentation allowlist.
META.json: META.json.in Cargo.toml $(PGXN_INDEXED_DOCS) scripts/render-pgxn-meta.sh
./scripts/render-pgxn-meta.sh \
META.json.in $(PGXN_INDEXED_DOCS) "$(DISTVERSION)" "$(PGXN_TREEISH)" "$(PGXN_META)"
# Build the PGXN release bundle. The PGXN-only README is added at the archive
# root in place of the repository README; every other tracked source file stays.
pgxn-zip: META.json
@set -eu; \
tmp_dir="$$(mktemp -d)"; \
trap 'rm -rf "$$tmp_dir"' EXIT HUP INT TERM; \
sed 's/@CARGO_VERSION@/$(DISTVERSION)/g' \
"$(PGXN_README_TEMPLATE)" > "$$tmp_dir/README.md"; \
git archive --format zip --prefix $(DISTNAME)-$(DISTVERSION)/ \
--add-file "$$tmp_dir/README.md" \
--add-file "$(PGXN_META)" \
-o "$(PGXN_ARCHIVE)" "$(PGXN_TREEISH)" ':(exclude)README.md'
# ============================================================================
# pg_regress (PGXS) configuration
# ============================================================================
EXTENSION = pg_durable
REGRESS = 00_init simple sequence variables parallel conditional
REQUESTED_GOALS := $(if $(MAKECMDGOALS),$(MAKECMDGOALS),all)
PG_CONFIG_GOALS := all package install uninstall installcheck pgrx-init
ifneq ($(filter $(PG_CONFIG_GOALS),$(REQUESTED_GOALS)),)
ifndef PG_CONFIG
PG_CONFIG := $(shell $(CARGO) pgrx info pg-config $(PG_VERSION) 2>/dev/null)
ifeq ($(PG_CONFIG),)
PG_CONFIG := $(shell command -v pg_config 2>/dev/null)
endif
endif
ifeq ($(PG_CONFIG),)
$(error PG_CONFIG is not set and pg_config could not be found via cargo-pgrx or PATH)
endif
PG_MAJOR := $(shell "$(PG_CONFIG)" --version 2>/dev/null | sed -nE 's/^PostgreSQL ([0-9]+).*/\1/p')
ifeq ($(filter $(PG_MAJOR),17 18),)
$(error unsupported PostgreSQL major '$(PG_MAJOR)'; pg_durable supports PostgreSQL 17 and 18)
endif
endif
ifneq ($(filter install uninstall,$(REQUESTED_GOALS)),)
ifneq ($(filter installcheck,$(REQUESTED_GOALS)),)
$(error run 'make install' or 'make uninstall' and 'make installcheck' as separate commands)
endif
endif
# PGXS is used only for the regression-test entry point. Keeping it out of
# normal builds prevents its `install` recipe from conflicting with ours.
ifneq ($(filter installcheck,$(REQUESTED_GOALS)),)
ifndef PGXS
PGXS := $(shell "$(PG_CONFIG)" --pgxs)
endif
include $(PGXS)
endif
# ============================================================================
# Source installation
# ============================================================================
DEFAULT_PGRX_PACKAGE_DIR = $(CURDIR)/target/release/pg_durable-pg$(PG_MAJOR)
PGRX_PACKAGE_DIR ?= $(DEFAULT_PGRX_PACKAGE_DIR)
PGRX_PACKAGE_MARKER = $(PGRX_PACKAGE_DIR).pg_durable-owned
PG_DLSUFFIX ?= $(if $(filter Darwin,$(shell uname -s)),.dylib,.so)
ifeq ($(filter installcheck,$(REQUESTED_GOALS)),)
PG_PKGLIBDIR = $(shell "$(PG_CONFIG)" --pkglibdir)
PG_EXTENSION_DIR = $(shell "$(PG_CONFIG)" --sharedir)/extension
PACKAGE_LIBRARY = $(PGRX_PACKAGE_DIR)$(PG_PKGLIBDIR)/pg_durable$(PG_DLSUFFIX)
PACKAGE_EXTENSION_DIR = $(PGRX_PACKAGE_DIR)$(PG_EXTENSION_DIR)
# Same directories relative to the package root, for auditing the packaged tree.
PG_PKGLIBDIR_REL = $(patsubst /%,%,$(PG_PKGLIBDIR))
PG_EXTENSION_DIR_REL = $(patsubst /%,%,$(PG_EXTENSION_DIR))
install:
@set -eu; \
package_library="$(PACKAGE_LIBRARY)"; \
package_extension_dir="$(PACKAGE_EXTENSION_DIR)"; \
test -f "$$package_library" || { echo "missing packaged library: $$package_library; run 'make package' first" >&2; exit 1; }; \
test -f "$$package_extension_dir/pg_durable.control" || { echo "missing packaged control file; run 'make package' first" >&2; exit 1; }; \
set -- "$$package_extension_dir"/pg_durable--*.sql; \
test -f "$$1" || { echo "missing packaged SQL files; run 'make package' first" >&2; exit 1; }; \
unexpected="$$(cd "$(PGRX_PACKAGE_DIR)" && find . -type f \
! -path "./$(PG_PKGLIBDIR_REL)/pg_durable$(PG_DLSUFFIX)" \
! -path "./$(PG_EXTENSION_DIR_REL)/pg_durable.control" \
! -path "./$(PG_EXTENSION_DIR_REL)/pg_durable--*.sql")"; \
test -z "$$unexpected" || { \
echo "packaged tree contains files this target does not install:" >&2; \
echo "$$unexpected" >&2; \
echo "the Debian package ships the whole tree, so a source install would silently differ from it; extend the install and uninstall recipes or exclude these files" >&2; \
exit 1; }; \
install -d -m 0755 "$(DESTDIR)$(PG_PKGLIBDIR)" "$(DESTDIR)$(PG_EXTENSION_DIR)"; \
install -m 0755 "$$package_library" "$(DESTDIR)$(PG_PKGLIBDIR)/pg_durable$(PG_DLSUFFIX)"; \
install -m 0644 "$$package_extension_dir/pg_durable.control" "$$@" "$(DESTDIR)$(PG_EXTENSION_DIR)/"
# `pgxn uninstall` runs this target directly, without building first, so it must
# not depend on a package tree. It removes only what `install` places, and is
# idempotent so a partial installation can always be cleaned up.
uninstall:
@set -eu; \
extension_dir="$(DESTDIR)$(PG_EXTENSION_DIR)"; \
library="$(DESTDIR)$(PG_PKGLIBDIR)/pg_durable$(PG_DLSUFFIX)"; \
removed=0; \
if test -e "$$library"; then rm -f "$$library"; removed=1; fi; \
if test -e "$$extension_dir/pg_durable.control"; then rm -f "$$extension_dir/pg_durable.control"; removed=1; fi; \
for sql in "$$extension_dir"/pg_durable--*.sql; do \
test -e "$$sql" || continue; \
rm -f "$$sql"; \
removed=1; \
done; \
test "$$removed" -eq 1 || echo "pg_durable is not installed for $(PG_CONFIG); nothing to remove"
endif