From 8bed5d25df47be5e787405cce5dad1bd97b591ab Mon Sep 17 00:00:00 2001 From: Jose Garcia <47431411+ruxwez@users.noreply.github.com> Date: Fri, 24 Oct 2025 00:04:48 +0200 Subject: [PATCH 1/4] Introduce extension version compatibility struct Add Makefile and structs::ExtensionVersionCompatibility Refactor extensions to accept Arc pg_version Resolve per-Postgres extension versions via LazyLock --- makefile | 7 +++++++ src/extensions/mod.rs | 10 ++++++---- src/extensions/pgmq.rs | 26 ++++++++++++++++++++------ src/extensions/pgvector.rs | 26 ++++++++++++++++++++------ src/extensions/postgis.rs | 23 ++++++++++++++++++----- src/main.rs | 5 ++++- src/structs.rs | 21 +++++++++++++++++++++ 7 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 makefile create mode 100644 src/structs.rs diff --git a/makefile b/makefile new file mode 100644 index 0000000..f46762e --- /dev/null +++ b/makefile @@ -0,0 +1,7 @@ + +test: + docker build -t ruxwez/postgres . --no-cache + docker rmi ruxwez/postgres + +build: + docker build -t ruxwez/postgres . diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs index f25c3f1..7e77395 100644 --- a/src/extensions/mod.rs +++ b/src/extensions/mod.rs @@ -1,12 +1,14 @@ +use std::sync::Arc; + mod pgmq; mod pgvector; mod postgis; -pub async fn install(pg_version: String) { - postgis::install(pg_version); +pub async fn install(pg_version: Arc) { + postgis::install(pg_version.clone()); - let pgmq_handle = pgmq::install(); - let pgvector_handle = pgvector::install(); + let pgmq_handle = pgmq::install(pg_version.clone()); + let pgvector_handle = pgvector::install(pg_version.clone()); // Wait for all installations to complete let _ = tokio::join!(pgmq_handle, pgvector_handle); diff --git a/src/extensions/pgmq.rs b/src/extensions/pgmq.rs index b31f6eb..c11c7bc 100644 --- a/src/extensions/pgmq.rs +++ b/src/extensions/pgmq.rs @@ -1,15 +1,29 @@ -use crate::common::run; -use std::fs; +use crate::{common::run, structs::ExtensionVersionCompatibility}; +use std::{ + fs, + sync::{Arc, LazyLock}, +}; use tokio::task::JoinHandle; -static EXTENSION_VERSION: &str = "1.7.0"; +static VERSIONS: LazyLock> = LazyLock::new(|| { + Arc::new(ExtensionVersionCompatibility { + v16: "1.7.0", + v17: "1.7.0", + v18: "1.7.0", + }) +}); + +pub fn install(pg_version: Arc) -> JoinHandle<()> { + let version = match VERSIONS.get_version(&pg_version.to_owned()) { + Some(v) => v, + None => panic!("Unsupported PostgreSQL version"), + }; -pub fn install() -> JoinHandle<()> { tokio::spawn(async move { - tokio::task::spawn_blocking(|| { + tokio::task::spawn_blocking(move || { run(&format!( "git clone --branch v{} --depth 1 https://github.com/pgmq/pgmq.git /tmp/pgmq", - EXTENSION_VERSION + version )); run("cd /tmp/pgmq/pgmq-extension && make && make install"); diff --git a/src/extensions/pgvector.rs b/src/extensions/pgvector.rs index 3483478..2086af8 100644 --- a/src/extensions/pgvector.rs +++ b/src/extensions/pgvector.rs @@ -1,16 +1,30 @@ -use crate::common::run; -use std::fs; +use crate::{common::run, structs::ExtensionVersionCompatibility}; +use std::{ + fs, + sync::{Arc, LazyLock}, +}; use tokio::task::JoinHandle; -static EXTENSION_VERSION: &str = "0.8.1"; +static VERSIONS: LazyLock> = LazyLock::new(|| { + Arc::new(ExtensionVersionCompatibility { + v16: "0.8.1", + v17: "0.8.1", + v18: "0.8.1", + }) +}); + +pub fn install(pg_version: Arc) -> JoinHandle<()> { + let version = match VERSIONS.get_version(&pg_version.to_owned()) { + Some(v) => v, + None => panic!("Unsupported PostgreSQL version"), + }; -pub fn install() -> JoinHandle<()> { tokio::spawn(async move { - tokio::task::spawn_blocking(|| { + tokio::task::spawn_blocking(move || { // Clone the repository run(&format!( "git clone --branch v{} --depth 1 https://github.com/pgvector/pgvector.git /tmp/pgvector", - EXTENSION_VERSION + version )); // Build and install pgvector diff --git a/src/extensions/postgis.rs b/src/extensions/postgis.rs index 175fd6a..47ecd0e 100644 --- a/src/extensions/postgis.rs +++ b/src/extensions/postgis.rs @@ -1,14 +1,27 @@ -use crate::common::run; +use std::sync::{Arc, LazyLock}; -static EXTENSION_VERSION: &str = "3"; +use crate::{common::run, structs::ExtensionVersionCompatibility}; -pub fn install(pg_version: String) { - let pg_major = pg_version.split('.').next().unwrap().to_owned(); +static VERSIONS: LazyLock> = LazyLock::new(|| { + Arc::new(ExtensionVersionCompatibility { + v16: "3", + v17: "3", + v18: "3", + }) +}); + +pub fn install(pg_version: Arc) { + let pg_major = pg_version.to_owned().split('.').next().unwrap().to_owned(); + + let ex_version = match VERSIONS.get_version(&pg_major.clone()) { + Some(v) => v, + None => panic!("Unsupported PostgreSQL version"), + }; run(&format!( "apt-get install -y \ postgresql-{}-postgis-{} \ postgresql-{}-postgis-{}-scripts", - pg_major, EXTENSION_VERSION, pg_major, EXTENSION_VERSION + pg_major, ex_version, pg_major, ex_version )); } diff --git a/src/main.rs b/src/main.rs index af84b20..69dfe0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ -use std::env; +use std::{env, sync::Arc}; use crate::common::{run, run_output}; mod common; mod extensions; +mod structs; #[tokio::main] async fn main() { @@ -33,6 +34,8 @@ async fn main() { pg_version = numeric_version; } + let pg_version = Arc::new(pg_version); + let pg_major = pg_version.split(".").next().unwrap(); println!( diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 0000000..9cf5a19 --- /dev/null +++ b/src/structs.rs @@ -0,0 +1,21 @@ +pub struct ExtensionVersionCompatibility<'a> { + pub v16: &'a str, + pub v17: &'a str, + pub v18: &'a str, +} + +impl ExtensionVersionCompatibility<'static> { + pub fn get_version(&self, version: &str) -> Option { + if version.contains('.') { + let major_version = version.split('.').next().unwrap(); + return self.get_version(major_version); + } + + match version.to_string().as_str() { + "16" => Some(self.v16.to_string()), + "17" => Some(self.v17.to_string()), + "18" => Some(self.v18.to_string()), + _ => None, + } + } +} From 4c43c7fd11e4621ff992aeb04387256913c3dd60 Mon Sep 17 00:00:00 2001 From: Jose Garcia <47431411+ruxwez@users.noreply.github.com> Date: Fri, 24 Oct 2025 00:16:56 +0200 Subject: [PATCH 2/4] Remove Arc wrapper and simplify spawn usage --- src/extensions/pgmq.rs | 25 ++++++++++--------------- src/extensions/pgvector.rs | 29 +++++++++++++---------------- src/extensions/postgis.rs | 7 +++---- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/extensions/pgmq.rs b/src/extensions/pgmq.rs index c11c7bc..f778b1b 100644 --- a/src/extensions/pgmq.rs +++ b/src/extensions/pgmq.rs @@ -5,13 +5,12 @@ use std::{ }; use tokio::task::JoinHandle; -static VERSIONS: LazyLock> = LazyLock::new(|| { - Arc::new(ExtensionVersionCompatibility { +static VERSIONS: LazyLock = + LazyLock::new(|| ExtensionVersionCompatibility { v16: "1.7.0", v17: "1.7.0", v18: "1.7.0", - }) -}); + }); pub fn install(pg_version: Arc) -> JoinHandle<()> { let version = match VERSIONS.get_version(&pg_version.to_owned()) { @@ -19,17 +18,13 @@ pub fn install(pg_version: Arc) -> JoinHandle<()> { None => panic!("Unsupported PostgreSQL version"), }; - tokio::spawn(async move { - tokio::task::spawn_blocking(move || { - run(&format!( - "git clone --branch v{} --depth 1 https://github.com/pgmq/pgmq.git /tmp/pgmq", - version - )); + tokio::task::spawn_blocking(move || { + run(&format!( + "git clone --branch v{} --depth 1 https://github.com/pgmq/pgmq.git /tmp/pgmq", + version + )); - run("cd /tmp/pgmq/pgmq-extension && make && make install"); - fs::remove_dir_all("/tmp/pgmq").ok(); - }) - .await - .expect("Blocking task failed"); + run("cd /tmp/pgmq/pgmq-extension && make && make install"); + fs::remove_dir_all("/tmp/pgmq").ok(); }) } diff --git a/src/extensions/pgvector.rs b/src/extensions/pgvector.rs index 2086af8..b6dd51c 100644 --- a/src/extensions/pgvector.rs +++ b/src/extensions/pgvector.rs @@ -5,13 +5,12 @@ use std::{ }; use tokio::task::JoinHandle; -static VERSIONS: LazyLock> = LazyLock::new(|| { - Arc::new(ExtensionVersionCompatibility { +static VERSIONS: LazyLock = + LazyLock::new(|| ExtensionVersionCompatibility { v16: "0.8.1", v17: "0.8.1", v18: "0.8.1", - }) -}); + }); pub fn install(pg_version: Arc) -> JoinHandle<()> { let version = match VERSIONS.get_version(&pg_version.to_owned()) { @@ -19,19 +18,17 @@ pub fn install(pg_version: Arc) -> JoinHandle<()> { None => panic!("Unsupported PostgreSQL version"), }; - tokio::spawn(async move { - tokio::task::spawn_blocking(move || { - // Clone the repository - run(&format!( - "git clone --branch v{} --depth 1 https://github.com/pgvector/pgvector.git /tmp/pgvector", - version - )); + tokio::task::spawn_blocking(move || { + // Clone the repository + run(&format!( + "git clone --branch v{} --depth 1 https://github.com/pgvector/pgvector.git /tmp/pgvector", + version + )); - // Build and install pgvector - run("cd /tmp/pgvector && make clean && make OPTFLAGS='' && make install"); + // Build and install pgvector + run("cd /tmp/pgvector && make clean && make OPTFLAGS='' && make install"); - // Clean up the temporary directory - fs::remove_dir_all("/tmp/pgvector").ok(); - }).await.expect("Blocking task failed"); + // Clean up the temporary directory + fs::remove_dir_all("/tmp/pgvector").ok(); }) } diff --git a/src/extensions/postgis.rs b/src/extensions/postgis.rs index 47ecd0e..3cd77e6 100644 --- a/src/extensions/postgis.rs +++ b/src/extensions/postgis.rs @@ -2,13 +2,12 @@ use std::sync::{Arc, LazyLock}; use crate::{common::run, structs::ExtensionVersionCompatibility}; -static VERSIONS: LazyLock> = LazyLock::new(|| { - Arc::new(ExtensionVersionCompatibility { +static VERSIONS: LazyLock = + LazyLock::new(|| ExtensionVersionCompatibility { v16: "3", v17: "3", v18: "3", - }) -}); + }); pub fn install(pg_version: Arc) { let pg_major = pg_version.to_owned().split('.').next().unwrap().to_owned(); From 9d629f386661af07ec3ff13b659e3105022e0ca1 Mon Sep 17 00:00:00 2001 From: Jose Garcia <47431411+ruxwez@users.noreply.github.com> Date: Fri, 24 Oct 2025 01:29:43 +0200 Subject: [PATCH 3/4] Add English and Spanish READMEs and CONTRIBUTING --- CONTRIBUTING.es.md | 99 ++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 105 +++++++++++++++++++++++++++++++++++++++++++++ README.es.md | 55 ++++++++++++++++++++++++ README.md | 54 +++++++++++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 CONTRIBUTING.es.md create mode 100644 CONTRIBUTING.md create mode 100644 README.es.md create mode 100644 README.md diff --git a/CONTRIBUTING.es.md b/CONTRIBUTING.es.md new file mode 100644 index 0000000..da0adad --- /dev/null +++ b/CONTRIBUTING.es.md @@ -0,0 +1,99 @@ +# Contribuir al proyecto + +¡Gracias por tu interés en contribuir! Este documento explica cómo reportar problemas, proponer características, contribuir con código y cómo preparar un Pull Request (PR) claro para que los mantenedores puedan revisar y fusionar tus cambios con rapidez. + +Contenido +- Reportar problemas o proponer características +- Contribuir con código (flujo de trabajo) +- Lista de verificación para PR +- Notas de codificación y estilo +- Integración continua / pruebas +- Documentación y actualizaciones +- Licencia y soporte + +--- + +## 1) Reportar un problema o proponer una característica + +- Para bugs: abre un Issue usando la plantilla **Bug report** en `.github/ISSUE_TEMPLATE/bug_report.md`. +- Para propuestas: abre un Issue usando la plantilla **Feature request** en `.github/ISSUE_TEMPLATE/feature_request.md`. + +Incluye en el Issue: +- Título claro y resumen conciso. +- Pasos para reproducir (si aplica). +- Comportamiento esperado vs comportamiento observado. +- Entorno: versión de Postgres solicitada, imagen base, sistema operativo, CI, etc. +- Logs o salidas relevantes (copiar/pegar fragmentos útiles). +- Comandos ejecutados (por ejemplo, comandos `docker build` o `cargo`). + +Antes de abrir un Issue: +1. Busca Issues y PRs abiertos para evitar duplicados. +2. Si piensas implementar la solución, indícalo en el Issue para coordinar trabajo. + +--- + +## 2) Contribuir con código — flujo general + +1. Haz fork del repositorio. +2. Crea una rama con un nombre descriptivo: + - `fix/` + - `feat/` + - `chore/` +3. Si el cambio es significativo, abre un Issue antes de implementar o vincula uno existente. +4. Implementa los cambios con commits atómicos y descriptivos. +5. Construye localmente: `cargo build --release`. +6. Prueba en un entorno representativo (contenedor Linux si procede). +7. Abre un PR hacia `main` indicando: + - Motivación y resumen de cambios. + - Cómo probar localmente (comandos y ejemplos). + - Número del Issue relacionado. + - Notas de compatibilidad y dependencias del sistema. + +--- + +## 3) Lista de verificación para PR + +Antes de solicitar revisión: +- [ ] Existe un Issue que describa el cambio o el PR lo referencia. +- [ ] La rama está basada en `main` actualizada. +- [ ] El código compila: `cargo build --release`. +- [ ] La descripción del PR contiene pasos de prueba reproducibles. +- [ ] Documentaste cualquier cambio en comportamiento público o flags. +- [ ] Actualizaste documentación relevante (`README.md`, `README.es.md`, u otros). + +--- + +## 4) Notas de codificación y estilo + +- Usamos Rust estable; sigue las prácticas idiomáticas de Rust. +- Mantén el código claro y robusto; detecta y maneja errores en vez de suprimirlos. +- Para ejecutar comandos shell desde Rust utiliza los helpers existentes (si los hay) en lugar de duplicar lógica. +- Comenta y documenta funciones públicas y comportamientos no triviales. +- Evita introducir dependencias innecesarias; prioriza soluciones simples. + +--- + +## 5) Integración continua y pruebas + +- Los PRs disparan workflows de GitHub Actions definidos en `.github/workflows/` (p. ej. `pr-test.yml`) que construyen la imagen en una matriz de versiones. +- Asegúrate de que tus cambios sean compatibles con las versiones y plataformas probadas en CI. +- Si tu cambio añade dependencias del sistema o modifica el proceso de build, indica claramente el motivo y los pasos de validación en el PR. + +--- + +## 6) Documentación y actualizaciones + +- Mantén `README.md` actualizado con cambios relevantes para usuarios. +- Para contenido en español, actualiza `README.es.md` o abre un Issue solicitando ayuda con la traducción si corresponde. +- Añade notas de cambios en la descripción del PR para facilitar la revisión. + +--- + +## 7) Licencia y soporte + +- Contribuciones están sujetas a la licencia del proyecto (archivo `LICENSE`). +- Si necesitas orientación antes de empezar, abre un Issue describiendo tu plan y marca la conversación como `discussion` o `help wanted`. + +--- + +Gracias por querer mejorar este proyecto. Tu colaboración ayuda a que el software sea más útil y robusto para todos. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..899ad42 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,105 @@ +# Contributing to PostgreSQL Extensions Installer + +Thank you for your interest in contributing! This document explains how to report problems, propose features, contribute code (including new extensions), and how to prepare a clear PR so maintainers can review and merge your changes quickly. + +Contents +- Reporting issues or proposing features +- Contributing code (high-level workflow) +- Pull request checklist +- How the extension system works +- How to add a new extension (step-by-step) +- Coding and style notes +- Continuous Integration / tests +- License and code of conduct + +--- + +## Reporting issues or proposing features + +- If you found a bug, please open an Issue using the **Bug Report** template. +- If you want to propose a new feature (including adding a new extension), open an Issue using the **Feature Request** template. + +Every issue should include: +- A clear title and a short description. +- Steps to reproduce (if it's a bug). +- Expected behavior vs actual behavior. +- The environment you used (docker image / base postgres version used, OS if relevant). +- Logs / command output (when applicable). + +Before opening an issue: +1. Search existing issues to avoid duplicates. +2. If you plan to implement the fix or feature, mention that in the issue to avoid duplicated work. + +--- + +## Contributing code — high-level workflow + +1. Fork the repository. +2. Create a feature branch named using the pattern: + - `fix/`, or + - `feat/`, or + - `ext/` (for new extension work) +3. If you are implementing a non-trivial change, create an Issue first (see above). If none exists, create one and reference it from your PR. +4. Implement your changes. Build and test locally (see "CI / tests" below). +5. Create a pull request (PR) from your branch to `main` with a descriptive title. +6. In the PR description include: + - Motivation and summary of changes. + - How to test locally (commands and examples). + - Linked issue number (if any). +7. Wait for CI and maintainers' review. Respond to review comments and iterate as needed. + +--- + +## Pull request checklist + +Before requesting review, make sure: + +- [ ] You signed and/or accepted the project license terms by contributing (the repository uses an open source license in `LICENSE`). +- [ ] You created / linked an Issue describing the problem or feature (unless the change is trivial). +- [ ] Your branch is based on the latest `main`. +- [ ] The code compiles: `cargo build --release`. +- [ ] You included testing steps in the PR description. +- [ ] You documented any new public API, command-line behavior, or Docker build args. +- [ ] You updated relevant docs (README or this CONTRIBUTING file if needed). + +GitHub Actions are configured to perform build tests for multiple Postgres versions. The CI matrix is defined in `.github/workflows/pr-test.yml`. + + +--- + +## Coding and style notes + +- This project uses stable Rust with `tokio` for concurrency. +- Keep code simple and robust: handle command failures and avoid silent errors. +- Use `crate::common::run(...)` and `run_output(...)` rather than reimplementing command execution. +- When adding new public API surfaces, document them in the README and update the top-level README with notes for the new extension. + +--- + +## CI and testing + +- PRs trigger a matrix build defined in `.github/workflows/pr-test.yml`. The CI builds images for multiple Postgres versions and architectures. +- Ensure your changes are compatible across the supported Postgres versions listed in the matrix (see the workflow file). +- If your change only affects docs, you can still create a PR, and maintainers may merge it if checks are satisfied. + +--- + +## Documentation updates + +- Update `README.md` when adding new extensions or changing default behavior. +- For Spanish users, there's a `README.es.md` — when adding content that should appear in the Spanish readme, propose a matching translation or open an issue asking for assistance. + +Suggested README link updates: +- Add a link to this file in `README.md`: + - `See CONTRIBUTING.md for contribution guidelines.` +- Add a link to the Spanish copy (when created) in `README.es.md`. + +--- + +## Questions and support + +If you need help deciding how to implement an extension or want feedback before coding, open an Issue with the "feature request" template describing your plan and the extension you want to add. + +--- + +Thank you for helping improve this project — contributions are very welcome! diff --git a/README.es.md b/README.es.md new file mode 100644 index 0000000..12bce85 --- /dev/null +++ b/README.es.md @@ -0,0 +1,55 @@ +# Instalador de extensiones para PostgreSQL (imagen Docker derivada) + +## Propósito + +Este proyecto genera una imagen Docker derivada de `postgres` que ya incluye varias extensiones populares de PostgreSQL instaladas y listas para usar. La instalación de las extensiones se realiza durante el proceso de build mediante un binario escrito en Rust (`install-extensions`) que se compila en una etapa `builder` y se ejecuta dentro de la imagen base de PostgreSQL. + +El objetivo principal es ahorrar tiempo y complejidad al desplegar contenedores PostgreSQL que necesiten extensiones comunes ya instaladas y correctamente compiladas para la versión de PostgreSQL seleccionada. + +## Extensiones incluidas + +- PostGIS — PostGIS 3 (PostgreSQL 16 / 17 / 18) — ver en `src/extensions/postgis.rs` +- pgvector — v0.8.1 (PostgreSQL 16 / 17 / 18) — ver en `src/extensions/pgvector.rs` +- pgmq — v1.7.0 (PostgreSQL 16 / 17 / 18) — ver en `src/extensions/pgmq.rs` + +También se instala: + +- `postgresql-contrib` + +Durante el build se instalan temporalmente paquetes necesarios para compilar las extensiones (por ejemplo `build-essential`, `git`, `postgresql-server-dev-`, `ca-certificates`). Estos paquetes se purgan al finalizar el proceso para reducir el tamaño final de la imagen. + +## ¿Por qué he usado `Rust`? + +He elegido `Rust` para el instalador porque necesitaba: + +- Control total sobre qué versiones de cada extensión se instalan y cómo se instalan. +- Un binario autocontenible que pueda compilarse en la etapa `builder` y copiarse a la imagen final (`/usr/local/bin/installer`), para ejecutarlo y eliminarlo después (ver `Dockerfile`). + Esto permite que la imagen final sea ligera y no incluya dependencias de compilación ni runtimes interpretados. + +Ventajas concretas de `Rust` en este caso: + +- Binario nativo y sin runtime adicional: reduce el tamaño de la imagen y la superficie de ataque frente a soluciones basadas en `Python` u otros lenguajes interpretados. +- Tipado estático y manejo de errores: facilita detectar y controlar condiciones de fallo durante la instalación en tiempo de compilación y en ejecución. +- Buenas herramientas para concurrencia: puedo usar crates como `tokio` para ejecutar instalaciones en paralelo de forma segura y eficiente. +- Reproducibilidad y empaquetado: con `cargo` y la compilación en `builder` stage la lógica queda encapsulada en un único ejecutable. + +## ¿Como funciona el gestor de versiones? + +```rust +static VERSIONS: LazyLock = + LazyLock::new(|| ExtensionVersionCompatibility { + v16: "1.7.0", + v17: "1.7.0", + v18: "1.7.0", + }); +``` + +Esta estructura define la ultima version compatible con la version major de PostgreSQL. Esto permite que el instalador seleccione automáticamente la versión correcta de cada extensión según la versión de PostgreSQL en uso. + +Por ejemplo, para `pgmq`, la versión `1.7.0` es compatible con PostgreSQL 16, 17 y 18. Si en el futuro se elimina el soporte en la version `1.8.0` para PostgreSQL 16, se mantendria la version `1.7.0` para PostgreSQL 16 y se podria definir una nueva version `1.8.0` para PostgreSQL 17 y 18. + +Ademas, si se desea agregar soporte para una nueva version mayor de PostgreSQL (por ejemplo, PostgreSQL 19), solo se necesita actualizar esta estructura para incluir la nueva version compatible de cada extensión. + +## ¿Como contribuir? +- Consulta `CONTRIBUTING.es.md` para las pautas de contribución en español. +- Para la versión en inglés, consulta `CONTRIBUTING.md`. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a2a38a3 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# PostgreSQL Extensions Installer (derived Docker image) + +## Purpose + +This project builds a Docker image derived from the official `postgres` image that already includes several popular PostgreSQL extensions installed and ready to use. Extensions are installed during the image build using a Rust binary (`install-extensions`) that is compiled in a `builder` stage and executed inside the base PostgreSQL image. + +The main goal is to save time and reduce complexity when deploying PostgreSQL containers that require common extensions preinstalled and compiled for the selected PostgreSQL version. + +## Included extensions + +- PostGIS — PostGIS 3 (PostgreSQL 16 / 17 / 18) — see `src/extensions/postgis.rs` +- pgvector — v0.8.1 (PostgreSQL 16 / 17 / 18) — see `src/extensions/pgvector.rs` +- pgmq — v1.7.0 (PostgreSQL 16 / 17 / 18) — see `src/extensions/pgmq.rs` + +Also installed: + +- `postgresql-contrib` + +During the build, temporary packages required to compile the extensions are installed (for example `build-essential`, `git`, `postgresql-server-dev-`, `ca-certificates`). These packages are removed at the end of the build process to reduce the final image size. + +## Why Rust? + +I chose `Rust` for the installer because I needed: + +- Full control over which versions of each extension are installed and how they are installed. +- A self-contained binary that can be built in the `builder` stage and copied into the final image (`/usr/local/bin/installer`), executed, and then removed (see the `Dockerfile`). This keeps the final image slim and free of build dependencies or interpreted runtimes. + +Concrete advantages of using `Rust` here: + +- Native binary without an additional runtime: reduces image size and the attack surface compared to solutions based on `Python` or other interpreted languages. +- Static typing and robust error handling: helps catch and manage failure conditions both at compile time and runtime. +- Good concurrency tooling: crates like `tokio` can be used to run installations in parallel safely and efficiently. +- Reproducibility and packaging: with `cargo` and the `builder` stage, the installation logic is encapsulated in a single executable. + +## How does the version manager work? + +```/dev/null/versions.rs#L1-9 +static VERSIONS: LazyLock = + LazyLock::new(|| ExtensionVersionCompatibility { + v16: "1.7.0", + v17: "1.7.0", + v18: "1.7.0", + }); +``` + +This structure defines the latest compatible version for each PostgreSQL major version. It allows the installer to automatically select the correct version of each extension according to the PostgreSQL version in use. + +For example, for `pgmq`, version `1.7.0` is compatible with PostgreSQL 16, 17, and 18. If in the future version `1.8.0` drops support for PostgreSQL 16, you would keep `1.7.0` mapped to PostgreSQL 16 and define `1.8.0` for PostgreSQL 17 and 18. + +Also, if you want to add support for a new major PostgreSQL release (for example, PostgreSQL 19), you only need to update this structure to include the new compatible version for each extension. + +## How to contribute + +See `CONTRIBUTING.md` for detailed contribution guidelines: how to report bugs or feature requests (use the provided issue templates), the PR workflow, and step-by-step instructions to add a new PostgreSQL extension. A Spanish translation of the contributor guide is available at `CONTRIBUTING.es.md` and is referenced from `README.es.md`. From ff93d1640dc9f515c134d7612c8ace887de82157 Mon Sep 17 00:00:00 2001 From: Jose Garcia <47431411+ruxwez@users.noreply.github.com> Date: Fri, 24 Oct 2025 01:43:49 +0200 Subject: [PATCH 4/4] Add status badges to READMEs --- README.es.md | 7 ++++++- README.md | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.es.md b/README.es.md index 12bce85..b6f11a4 100644 --- a/README.es.md +++ b/README.es.md @@ -1,4 +1,9 @@ # Instalador de extensiones para PostgreSQL (imagen Docker derivada) +![Docker Pulls](https://img.shields.io/docker/pulls/ruxwez/postgres?style=flat-square) +![GitHub branch status](https://img.shields.io/github/checks-status/ruxwez/postgres/main?style=flat-square) +![GitHub contributors](https://img.shields.io/github/contributors/ruxwez/postgres?style=flat-square) +![GitHub License](https://img.shields.io/github/license/ruxwez/postgres?style=flat-square) +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/ruxwez/postgres?style=flat-square) ## Propósito @@ -52,4 +57,4 @@ Ademas, si se desea agregar soporte para una nueva version mayor de PostgreSQL ( ## ¿Como contribuir? - Consulta `CONTRIBUTING.es.md` para las pautas de contribución en español. -- Para la versión en inglés, consulta `CONTRIBUTING.md`. \ No newline at end of file +- Para la versión en inglés, consulta `CONTRIBUTING.md`. diff --git a/README.md b/README.md index a2a38a3..0ffe4ae 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # PostgreSQL Extensions Installer (derived Docker image) +![Docker Pulls](https://img.shields.io/docker/pulls/ruxwez/postgres?style=flat-square) +![GitHub branch status](https://img.shields.io/github/checks-status/ruxwez/postgres/main?style=flat-square) +![GitHub contributors](https://img.shields.io/github/contributors/ruxwez/postgres?style=flat-square) +![GitHub License](https://img.shields.io/github/license/ruxwez/postgres?style=flat-square) +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/ruxwez/postgres?style=flat-square) ## Purpose