main.rsannotatedmain.rssource43 lines · 1.7 KB · raw
1//! Writes an extension's install script from the schema entities pgrx
2//! 0.19 embeds in the `.pgrxsc` section of the built shared object: the
3//! part of `cargo pgrx schema` a buck build needs (contract §4).
4//!
5//! Usage: pgrx-schema <lib-name> <lib.so> <control-file> <out.sql>
6
7use std::error::Error;
8
9use object::{Object, ObjectSection};
10use pgrx_sql_entity_graph::section::{decode_entities, is_schema_section_name};
11use pgrx_sql_entity_graph::{ControlFile, PgrxSql, SqlGraphEntity};
12
13fn main() {
14    if let Err(e) = run() {
15        eprintln!("pgrx-schema: {e}");
16        std::process::exit(1);
17    }
18}
19
20fn run() -> Result<(), Box<dyn Error>> {
21    let args: Vec<String> = std::env::args().skip(1).collect();
22    let [lib_name, so_path, control_path, out_path] = args.as_slice() else {
23        return Err("usage: pgrx-schema <lib-name> <lib.so> <control-file> <out.sql>".into());
24    };
25
26    let so = std::fs::read(so_path)?;
27    let file = object::File::parse(so.as_slice())?;
28    let section = file
29        .sections()
30        .find(|s| s.name().is_ok_and(is_schema_section_name))
31        .ok_or_else(|| format!("{so_path}: no pgrx schema section"))?;
32    let bytes = section.data()?;
33
34    let control = ControlFile::from_str(&std::fs::read_to_string(control_path)?)?;
35    // A control file naming module_pathname gets MODULE_PATHNAME in the
36    // script; one without gets a versioned library path (cargo-pgrx's rule).
37    let versioned_so = control.module_pathname.is_none();
38
39    let entities = std::iter::once(SqlGraphEntity::ExtensionRoot(control))
40        .chain(decode_entities(bytes)?);
41    PgrxSql::build(entities, lib_name.clone(), versioned_so)?.to_file(out_path)?;
42    Ok(())
43}