Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate PgConfig into pipeline #21

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod pgxs;
mod pipeline;

use crate::{error::BuildError, pgrx::Pgrx, pgxs::Pgxs, pipeline::Pipeline};
use pg_config::PgConfig;
use pgxn_meta::{dist, release::Release};
use std::path::Path;

Expand All @@ -31,17 +32,22 @@ enum Build<P: AsRef<Path>> {
impl<P: AsRef<Path>> Build<P> {
/// Returns a build pipeline identified by `pipe`, or an error if `pipe`
/// is unknown.
fn new(pipe: &dist::Pipeline, dir: P, sudo: bool) -> Result<Build<P>, BuildError> {
fn new(
pipe: &dist::Pipeline,
dir: P,
cfg: PgConfig,
sudo: bool,
) -> Result<Build<P>, BuildError> {
match pipe {
dist::Pipeline::Pgxs => Ok(Build::Pgxs(Pgxs::new(dir, sudo))),
dist::Pipeline::Pgrx => Ok(Build::Pgrx(Pgrx::new(dir, sudo))),
dist::Pipeline::Pgxs => Ok(Build::Pgxs(Pgxs::new(dir, cfg, sudo))),
dist::Pipeline::Pgrx => Ok(Build::Pgrx(Pgrx::new(dir, cfg, sudo))),
_ => Err(BuildError::UnknownPipeline(pipe.to_string())),
}
}

/// Attempts to detect and return the appropriate build pipeline to build
/// the contents of `dir`. Returns an error if no pipeline can do so.
fn detect(dir: P, sudo: bool) -> Result<Build<P>, BuildError> {
fn detect(dir: P, cfg: PgConfig, sudo: bool) -> Result<Build<P>, BuildError> {
// Start with PGXS.
let mut score = Pgxs::confidence(&dir);
let mut pipe = dist::Pipeline::Pgxs;
Expand All @@ -61,8 +67,8 @@ impl<P: AsRef<Path>> Build<P> {

// Construct the winner.
match pipe {
dist::Pipeline::Pgrx => Ok(Build::Pgrx(Pgrx::new(dir, sudo))),
dist::Pipeline::Pgxs => Ok(Build::Pgxs(Pgxs::new(dir, sudo))),
dist::Pipeline::Pgrx => Ok(Build::Pgrx(Pgrx::new(dir, cfg, sudo))),
dist::Pipeline::Pgxs => Ok(Build::Pgxs(Pgxs::new(dir, cfg, sudo))),
_ => unreachable!("unknown pipelines {pipe}"),
}
}
Expand All @@ -77,15 +83,15 @@ pub struct Builder<P: AsRef<Path>> {

impl<P: AsRef<Path>> Builder<P> {
/// Creates and returns a new builder using the appropriate pipeline.
pub fn new(dir: P, meta: Release, sudo: bool) -> Result<Self, BuildError> {
pub fn new(dir: P, meta: Release, cfg: PgConfig, sudo: bool) -> Result<Self, BuildError> {
let pipeline = if let Some(deps) = meta.dependencies() {
if let Some(pipe) = deps.pipeline() {
Build::new(pipe, dir, sudo)?
Build::new(pipe, dir, cfg, sudo)?
} else {
Build::detect(dir, sudo)?
Build::detect(dir, cfg, sudo)?
}
} else {
Build::detect(dir, sudo)?
Build::detect(dir, cfg, sudo)?
};

Ok(Builder { pipeline, meta })
Expand Down
8 changes: 7 additions & 1 deletion src/pg_config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::{

use crate::error::BuildError;

pub(crate) struct PgConfig(HashMap<String, String>);
#[derive(Debug, PartialEq, Clone)]
pub struct PgConfig(HashMap<String, String>);

impl PgConfig {
/// Executes `pg_config`, parses the output, and returns a `PgConfig`
Expand Down Expand Up @@ -40,6 +41,11 @@ impl PgConfig {
Ok(PgConfig(cfg))
}

#[cfg(test)]
pub(crate) fn from_map(map: HashMap<String, String>) -> Self {
Self(map)
}

/// Returns the `pg_config` value for `cfg`, which should be a lowercase
/// string.
pub fn get(&mut self, cfg: &str) -> Option<&str> {
Expand Down
11 changes: 9 additions & 2 deletions src/pgrx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! [pgrx]: https://github.com/pgcentralfoundation/pgrx

use crate::error::BuildError;
use crate::pg_config::PgConfig;
use crate::pipeline::Pipeline;
use std::path::Path;

Expand All @@ -12,19 +13,25 @@ use std::path::Path;
#[derive(Debug, PartialEq)]
pub(crate) struct Pgrx<P: AsRef<Path>> {
sudo: bool,
cfg: PgConfig,
dir: P,
}

impl<P: AsRef<Path>> Pipeline<P> for Pgrx<P> {
fn new(dir: P, sudo: bool) -> Self {
Pgrx { sudo, dir }
fn new(dir: P, cfg: PgConfig, sudo: bool) -> Self {
Pgrx { sudo, cfg, dir }
}

/// Returns the directory passed to [`Self::new`].
fn dir(&self) -> &P {
&self.dir
}

/// Returns the PgConfig passed to [`Self::new`].
fn pg_config(&self) -> &PgConfig {
&self.cfg
}

/// Determines the confidence that the Pgrx pipeline can build the
/// contents of `dir`. Returns 255 if it contains a file named
/// `Cargo.toml` and lists pgrx as a dependency. Otherwise returns 1 if
Expand Down
12 changes: 8 additions & 4 deletions src/pgrx/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use std::{fs::File, io::Write};
use std::{collections::HashMap, fs::File, io::Write};
use tempfile::tempdir;

#[test]
Expand Down Expand Up @@ -27,22 +27,26 @@ fn confidence() -> Result<(), BuildError> {
#[test]
fn new() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgrx::new(dir, false);
let cfg = PgConfig::from_map(HashMap::new());
let pipe = Pgrx::new(dir, cfg.clone(), false);
assert_eq!(dir, pipe.dir);
assert_eq!(&dir, pipe.dir());
assert_eq!(&cfg, pipe.pg_config());
assert!(!pipe.sudo);

let dir2 = dir.join("corpus");
let pipe = Pgrx::new(dir2.as_path(), true);
let cfg2 = PgConfig::from_map(HashMap::from([("bindir".to_string(), "bin".to_string())]));
let pipe = Pgrx::new(dir2.as_path(), cfg2.clone(), true);
assert_eq!(dir2, pipe.dir);
assert_eq!(&dir2, pipe.dir());
assert_eq!(&cfg2, pipe.pg_config());
assert!(pipe.sudo);
}

#[test]
fn configure_et_al() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgrx::new(dir, false);
let pipe = Pgrx::new(dir, PgConfig::from_map(HashMap::new()), false);
assert!(pipe.configure().is_ok());
assert!(pipe.compile().is_ok());
assert!(pipe.test().is_ok());
Expand Down
12 changes: 9 additions & 3 deletions src/pgxs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//!
//! [PGXS]: https://www.postgresql.org/docs/current/extend-pgxs.html

use crate::error::BuildError;
use crate::pipeline::Pipeline;
use crate::{error::BuildError, pg_config::PgConfig};
use log::info;
use regex::Regex;
use std::{
Expand All @@ -18,12 +18,13 @@ use std::{
#[derive(Debug, PartialEq)]
pub(crate) struct Pgxs<P: AsRef<Path>> {
sudo: bool,
cfg: PgConfig,
dir: P,
}

impl<P: AsRef<Path>> Pipeline<P> for Pgxs<P> {
fn new(dir: P, sudo: bool) -> Self {
Pgxs { sudo, dir }
fn new(dir: P, cfg: PgConfig, sudo: bool) -> Self {
Pgxs { sudo, cfg, dir }
}

/// Determines the confidence that the Pgxs pipeline can build the
Expand Down Expand Up @@ -70,6 +71,11 @@ impl<P: AsRef<Path>> Pipeline<P> for Pgxs<P> {
&self.dir
}

/// Returns the PgConfig passed to [`Self::new`].
fn pg_config(&self) -> &PgConfig {
&self.cfg
}

fn configure(&self) -> Result<(), BuildError> {
// Run configure if it exists.
if let Ok(ok) = fs::exists(self.dir().as_ref().join("configure")) {
Expand Down
17 changes: 11 additions & 6 deletions src/pgxs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use assertables::*;
#[cfg(target_family = "unix")]
use std::os::unix::fs::PermissionsExt;
use std::{
collections::HashMap,
fs::{self, File},
io::Write,
};
Expand Down Expand Up @@ -55,22 +56,26 @@ fn confidence() -> Result<(), BuildError> {
#[test]
fn new() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgxs::new(dir, false);
let cfg = PgConfig::from_map(HashMap::new());
let pipe = Pgxs::new(dir, cfg.clone(), false);
assert_eq!(dir, pipe.dir);
assert_eq!(&dir, pipe.dir());
assert_eq!(&cfg, pipe.pg_config());
assert!(!pipe.sudo);

let dir2 = dir.join("corpus");
let pipe = Pgxs::new(dir2.as_path(), true);
let cfg2 = PgConfig::from_map(HashMap::from([("bindir".to_string(), "bin".to_string())]));
let pipe = Pgxs::new(dir2.as_path(), cfg2.clone(), true);
assert_eq!(dir2, pipe.dir);
assert_eq!(&dir2, pipe.dir());
assert_eq!(&cfg2, pipe.pg_config());
assert!(pipe.sudo);
}

#[test]
fn configure() -> Result<(), BuildError> {
let tmp = tempdir()?;
let pipe = Pgxs::new(&tmp, false);
let pipe = Pgxs::new(&tmp, PgConfig::from_map(HashMap::new()), false);

// Try with no Configure file.
if let Err(e) = pipe.configure() {
Expand Down Expand Up @@ -122,23 +127,23 @@ fn configure() -> Result<(), BuildError> {
#[test]
fn compile() -> Result<(), BuildError> {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgxs::new(dir, false);
let pipe = Pgxs::new(dir, PgConfig::from_map(HashMap::new()), false);
assert!(pipe.compile().is_err());
Ok(())
}

#[test]
fn test() -> Result<(), BuildError> {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgxs::new(dir, false);
let pipe = Pgxs::new(dir, PgConfig::from_map(HashMap::new()), false);
assert!(pipe.test().is_err());
Ok(())
}

#[test]
fn install() -> Result<(), BuildError> {
let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let pipe = Pgxs::new(dir, false);
let pipe = Pgxs::new(dir, PgConfig::from_map(HashMap::new()), false);
assert!(pipe.install().is_err());
Ok(())
}
7 changes: 5 additions & 2 deletions src/pipeline/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Build Pipeline interface definition.

use crate::error::BuildError;
use crate::{error::BuildError, pg_config::PgConfig};
use log::debug;
use std::{io::Write, path::Path, process::Command};

/// Defines the interface for build pipelines to configure, compile, and test
/// PGXN distributions.
pub(crate) trait Pipeline<P: AsRef<Path>> {
/// Creates an instance of a Pipeline.
fn new(dir: P, sudo: bool) -> Self;
fn new(dir: P, pg_config: PgConfig, sudo: bool) -> Self;

/// Returns a score for the confidence that this pipeline can build the
/// contents of `dir`. A score of 0 means no confidence and 255 means the
Expand All @@ -31,6 +31,9 @@ pub(crate) trait Pipeline<P: AsRef<Path>> {
/// Returns the directory passed to [`new`].
fn dir(&self) -> &P;

/// Returns the PgConfig passed to [`new`].
fn pg_config(&self) -> &PgConfig;

/// Attempts to write a temporary file to `dir` and returns `true` on
/// success and `false` on failure. The temporary file will be deleted.
fn is_writeable<D: AsRef<Path>>(&self, dir: D) -> bool {
Expand Down
18 changes: 13 additions & 5 deletions src/pipeline/tests.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
use super::*;
use crate::tests::compile_mock;
use assertables::*;
use std::env;
use std::{collections::HashMap, env};
use tempfile::tempdir;

struct TestPipeline<P: AsRef<Path>> {
dir: P,
cfg: PgConfig,
}

// Create a mock version of the trait.
#[cfg(test)]
impl<P: AsRef<Path>> Pipeline<P> for TestPipeline<P> {
fn new(dir: P, _: bool) -> Self {
TestPipeline { dir }
fn new(dir: P, cfg: PgConfig, _: bool) -> Self {
TestPipeline { dir, cfg }
}

fn dir(&self) -> &P {
&self.dir
}

fn pg_config(&self) -> &PgConfig {
&self.cfg
}

fn confidence(_: P) -> u8 {
0
}
Expand All @@ -38,9 +44,10 @@ impl<P: AsRef<Path>> Pipeline<P> for TestPipeline<P> {
#[test]
fn run() -> Result<(), BuildError> {
let tmp = tempdir()?;
let cfg = PgConfig::from_map(HashMap::new());

// Test basic success.
let pipe = TestPipeline::new(&tmp, false);
let pipe = TestPipeline::new(&tmp, cfg, false);
if let Err(e) = pipe.run("echo", ["hello"], false) {
panic!("echo hello failed: {e}");
}
Expand Down Expand Up @@ -95,8 +102,9 @@ fn run() -> Result<(), BuildError> {
#[test]
fn is_writeable() -> Result<(), BuildError> {
let tmp = tempdir()?;
let cfg = PgConfig::from_map(HashMap::new());

let pipe = TestPipeline::new(&tmp, false);
let pipe = TestPipeline::new(&tmp, cfg, false);
assert!(pipe.is_writeable(&tmp));
assert!(!pipe.is_writeable(tmp.path().join(" nonesuch")));

Expand Down
Loading
Loading