Skip to content

Commit

Permalink
Scaffold the build interface
Browse files Browse the repository at this point in the history
The `Builder` struct defines the public interface for building a PGXN
release. Internally, it delegates `configure`, `compile`, and `test`
commands (so far) to pipeline-specific build modules. Its `new`
constructor reads the pgxn_meta Release pipeline to determine which one
to instantiate; in the future it will also fall back on detecting the
pipeline where none is specified.

The `error` module define errors returned by the crate, while the
`pipeline` module defines a trait with the functions `Builder` expects
to dispatch to. All pipelines must implement this trait. This will make
it easy to add new pipelines in the future; They just have to implement
the trait, add a new `Build` enum, then add appropriate calls to its
methods in `Builder`'s dispatching methods.

For now, the `pgxs` and `pgrx` modules alone define structs that
implement the `pipeline.Pipeline` trait with no-op functions.

Add tests for basic functionality of `Builder`.
  • Loading branch information
theory committed Oct 16, 2024
1 parent 2dc2885 commit 4ae3125
Show file tree
Hide file tree
Showing 8 changed files with 1,227 additions and 28 deletions.
959 changes: 959 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ version = "0.1.0"
edition = "2021"

[dependencies]
pgxn_meta = "0.4"
thiserror = "1.0"

[dev-dependencies]
serde_json = "1.0.128"
14 changes: 14 additions & 0 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Build Errors.
use thiserror::Error;

/// Build errors.
#[derive(Error, Debug, PartialEq)]
pub enum BuildError {
/// Errors configuring a build.
#[error("configuration failure")]
Configuration(),

/// Unknown pipeline error.
#[error("unknown build pipeline `{0}`")]
UnknownPipeline(String),
}
90 changes: 62 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,79 @@ This crate builds PGXN distributions for a variety of platforms and Postgres
versions.
*/
use thiserror::Error;

/// Build errors.
#[derive(Error, Debug)]
pub enum BuildError {
/// Errors configuring a build.
#[error("configuration failure")]
Configuration(),
pub mod error;
mod pgrx;
mod pgxs;
mod pipeline;

use crate::{error::BuildError, pgrx::Pgrx, pgxs::Pgxs, pipeline::Pipeline};
use pgxn_meta::{dist, release::Release};

/// Defines the types of builders.
#[derive(Debug, PartialEq)]
enum Build {
/// Defines a builder using the PGXS pipeline.
Pgxs(Pgxs),

/// Defines a builder using the pgrx pipeline.
Pgrx(Pgrx),
}

/// Defines the interface for downloading, configuring, building, and testing
/// PGXN distributions.
pub trait Builder {
/// Downloads a distribution.
fn download() -> Result<(), BuildError>;
/// Builder builds PGXN releases.
#[derive(Debug, PartialEq)]
pub struct Builder(Build);

/// Unpacks a downloaded distribution.
fn unpack() -> Result<(), BuildError>;
impl Builder {
/// Creates and returns a new builder using the appropriate pipeline.
pub fn new(meta: Release) -> Result<Self, BuildError> {
if let Some(deps) = meta.dependencies() {
if let Some(pipeline) = deps.pipeline() {
return match pipeline {
dist::Pipeline::Pgxs => Ok(Builder(Build::Pgxs(Pgxs::new(meta)))),
dist::Pipeline::Pgrx => Ok(Builder(Build::Pgrx(Pgrx::new(meta)))),
_ => Err(BuildError::UnknownPipeline(pipeline.to_string())),
};
}
}
println!("HERE");
todo!("Detect pipeline");
}

/// Patches a distribution.
fn patch() -> Result<(), BuildError>;
/// Downloads a release.
pub fn download(&self) -> Result<(), BuildError> {
Ok(())
}

/// Unpacks a release.
pub fn unpack(&self) -> Result<(), BuildError> {
Ok(())
}

/// Configures a distribution to build on a particular platform and
/// Postgres version.
fn configure() -> Result<(), BuildError>;
pub fn configure(&self) -> Result<(), BuildError> {
match &self.0 {
Build::Pgxs(pgxs) => pgxs.configure(),
Build::Pgrx(pgrx) => pgrx.configure(),
}
}

/// Compiles a distribution on a particular platform and Postgres version.
fn compile() -> Result<(), BuildError>;
pub fn compile(&self) -> Result<(), BuildError> {
match &self.0 {
Build::Pgxs(pgxs) => pgxs.compile(),
Build::Pgrx(pgrx) => pgrx.compile(),
}
}

/// Tests a distribution a particular platform and Postgres version.
fn test() -> Result<(), BuildError>;
pub fn test(&self) -> Result<(), BuildError> {
match &self.0 {
Build::Pgxs(pgxs) => pgxs.test(),
Build::Pgrx(pgrx) => pgrx.test(),
}
}
}

#[cfg(test)]
mod tests {
// use super::*;

#[test]
fn it_works() {
assert!(true == true);
}
}
mod tests;
32 changes: 32 additions & 0 deletions src/pgrx/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Builder implementation for [pgrx] Pipelines.
//!
//! [pgrx]: https://github.com/pgcentralfoundation/pgrx
use crate::error::BuildError;
use crate::pipeline::Pipeline;
use pgxn_meta::release::Release;

/// Builder implementation for [pgrx] Pipelines.
///
/// [pgrx]: https://github.com/pgcentralfoundation/pgrx
#[derive(Debug, PartialEq)]
pub(crate) struct Pgrx {
meta: Release,
}

impl Pipeline for Pgrx {
fn new(meta: Release) -> Self {
Pgrx { meta }
}
fn configure(&self) -> Result<(), BuildError> {
Ok(())
}

fn compile(&self) -> Result<(), BuildError> {
Ok(())
}

fn test(&self) -> Result<(), BuildError> {
Ok(())
}
}
33 changes: 33 additions & 0 deletions src/pgxs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Builder implementation for [PGXS] Pipelines.
//!
//! [PGXS]: https://www.postgresql.org/docs/current/extend-pgxs.html
use crate::error::BuildError;
use crate::pipeline::Pipeline;
use pgxn_meta::release::Release;

/// Builder implementation for [PGXS] Pipelines.
///
/// [PGXS]: https://www.postgresql.org/docs/current/extend-pgxs.html
#[derive(Debug, PartialEq)]
pub(crate) struct Pgxs {
meta: Release,
}

impl Pipeline for Pgxs {
fn new(meta: Release) -> Self {
Pgxs { meta }
}

fn configure(&self) -> Result<(), BuildError> {
Ok(())
}

fn compile(&self) -> Result<(), BuildError> {
Ok(())
}

fn test(&self) -> Result<(), BuildError> {
Ok(())
}
}
21 changes: 21 additions & 0 deletions src/pipeline/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Build Pipeline interface definition.
use crate::error::BuildError;
use pgxn_meta::release::Release;

/// Defines the interface for build pipelines to configure, compile, and test
/// PGXN distributions.
pub(crate) trait Pipeline {
/// Creates an instance of a Builder.
fn new(meta: Release) -> Self;

/// Configures a distribution to build on a particular platform and
/// Postgres version.
fn configure(&self) -> Result<(), BuildError>;

/// Compiles a distribution on a particular platform and Postgres version.
fn compile(&self) -> Result<(), BuildError>;

/// Tests a distribution a particular platform and Postgres version.
fn test(&self) -> Result<(), BuildError>;
}
102 changes: 102 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use super::*;
use serde_json::{json, Value};

fn release_meta(pipeline: &str) -> Value {
json!({
"name": "pair",
"abstract": "A key/value pair data type",
"version": "0.1.8",
"maintainers": [
{ "name": "David E. Wheeler", "email": "[email protected]" }
],
"license": "PostgreSQL",
"contents": {
"extensions": {
"pair": {
"sql": "sql/pair.sql",
"control": "pair.control"
}
}
},
"dependencies": { "pipeline": pipeline },
"meta-spec": { "version": "2.0.0" },
"certs": {
"pgxn": {
"payload": "eyJ1c2VyIjoidGhlb3J5IiwiZGF0ZSI6IjIwMjQtMDktMTNUMTc6MzI6NTVaIiwidXJpIjoiZGlzdC9wYWlyLzAuMS43L3BhaXItMC4xLjcuemlwIiwiZGlnZXN0cyI6eyJzaGE1MTIiOiJiMzUzYjVhODJiM2I1NGU5NWY0YTI4NTllN2EyYmQwNjQ4YWJjYjM1YTdjMzYxMmIxMjZjMmM3NTQzOGZjMmY4ZThlZTFmMTllNjFmMzBmYTU0ZDdiYjY0YmNmMjE3ZWQxMjY0NzIyYjQ5N2JjYjYxM2Y4MmQ3ODc1MTUxNWI2NyJ9fQ",
"signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q",
},
},
})
}

#[test]
fn pgxs() {
// Test pgxs pipeline.
let meta = release_meta("pgxs");
let rel = Release::try_from(meta.clone()).unwrap();
let builder = Builder::new(rel).unwrap();
let rel = Release::try_from(meta).unwrap();
let exp = Builder(Build::Pgxs(Pgxs::new(rel)));
assert_eq!(exp, builder, "pgxs");
assert!(builder.download().is_ok());
assert!(builder.unpack().is_ok());
assert!(builder.configure().is_ok());
assert!(builder.compile().is_ok());
assert!(builder.test().is_ok());
}

#[test]
fn pgrx() {
// Test pgrx pipeline.
let meta = release_meta("pgrx");
let rel = Release::try_from(meta.clone()).unwrap();
let builder = Builder::new(rel).unwrap();
let rel = Release::try_from(meta).unwrap();
let exp = Builder(Build::Pgrx(Pgrx::new(rel)));
assert_eq!(exp, builder, "pgrx");
assert!(builder.download().is_ok());
assert!(builder.unpack().is_ok());
assert!(builder.configure().is_ok());
assert!(builder.compile().is_ok());
assert!(builder.test().is_ok());
}

#[test]
fn unsupported_pipeline() {
// Test unsupported pipeline.
let meta = release_meta("meson");
let rel = Release::try_from(meta).unwrap();
assert_eq!(
BuildError::UnknownPipeline("meson".to_string()),
Builder::new(rel).unwrap_err(),
);
}

#[test]
#[should_panic(expected = "Detect pipeline")]
fn detect_pipeline() {
// Test unspecified pipeline.
let mut meta = release_meta("");
meta.as_object_mut().unwrap().remove("dependencies");
let rel = Release::try_from(meta).unwrap();
_ = Builder::new(rel);
}

#[test]
#[should_panic(expected = "Detect pipeline")]
fn no_pipeline() {
// Test unspecified pipeline.
let mut meta = release_meta("");
let deps = meta
.as_object_mut()
.unwrap()
.get_mut("dependencies")
.unwrap()
.as_object_mut()
.unwrap();

deps.remove("pipeline");
deps.insert("postgres".to_string(), json!({"version": "14"}));
let rel = Release::try_from(meta).unwrap();
_ = Builder::new(rel);
}

0 comments on commit 4ae3125

Please sign in to comment.