use crate::CommandExecute;
use eyre::{Result, WrapErr, eyre};
use pgrx_pg_config::PgConfig;
use std::{
path::{Path, PathBuf},
process::{Command, Stdio},
};
#[derive(clap::Args, Debug)]
pub(crate) struct PgrxTarget {
#[arg(long, short = 'c', value_parser)]
pub pg_config: Option<PathBuf>,
#[arg(long, short = 'o', value_parser)]
pub output: Option<PathBuf>,
#[arg(long, value_parser)]
pub pg_sys_path: Option<PathBuf>,
#[arg(long, short = 'P', value_parser)]
pub pg_version: Option<u16>,
#[arg(long, value_parser)]
pub scratch_dir: Option<PathBuf>,
}
impl CommandExecute for PgrxTarget {
fn execute(self) -> eyre::Result<()> {
let mut temp: Option<tempfile::TempDir> = None;
let temp_path = if let Some(scratch) = &self.scratch_dir {
&**scratch
} else {
temp = Some(tempfile::tempdir()?);
temp.as_ref().unwrap().path()
};
make_target_info(&self, temp_path)?;
if let Some(temp) = temp {
temp.close()?;
}
Ok(())
}
}
#[tracing::instrument(level = "error")]
fn make_target_info(cmd: &PgrxTarget, tmp: &Path) -> Result<()> {
let pg_config_path = cmd.pg_config.clone().unwrap_or_else(|| "pg_config".into()).to_owned();
let pg_config = PgConfig::new_with_defaults(pg_config_path.clone());
let major_version = pg_config.major_version()?;
if let Some(expected_pg_version) = cmd.pg_version {
eyre::ensure!(
major_version == expected_pg_version,
"the provided `pg_config` had the wrong major version",
);
}
run(crate::cargo::cargo().args(["init", "--lib", "--name", "temp-crate"]).current_dir(tmp))?;
let cargo_add: Vec<String> = if let Some(pg_sys_path) = &cmd.pg_sys_path {
let abs = pg_sys_path.canonicalize().wrap_err_with(|| {
format!("given `--pg-sys-path` could not be canonicalized: {pg_sys_path:?}")
})?;
vec!["pgrx-pg-sys".into(), "--path".into(), abs.display().to_string()]
} else {
let own_version = env!("CARGO_PKG_VERSION");
vec![format!("pgrx-pg-sys@={own_version}")]
};
run(crate::cargo::cargo()
.arg("add")
.args(cargo_add)
.arg("--no-default-features")
.current_dir(tmp))?;
let filename = format!("pg{major_version}_raw_bindings.rs");
run(crate::cargo::cargo()
.current_dir(tmp)
.arg("build")
.arg("--features")
.arg(format!("pgrx-pg-sys/pg{major_version}"))
.env("PGRX_PG_CONFIG_PATH", &pg_config_path)
.env("PGRX_PG_SYS_EXTRA_OUTPUT_PATH", tmp.join(&filename)))?;
run(Command::new("rustfmt").current_dir(tmp).arg(&filename))?;
run(Command::new("tar").current_dir(tmp).arg("czf").arg("out.tgz").arg(&filename))?;
std::fs::rename(tmp.join("out.tgz"), format!("pgrx-target.{}.tgz", std::env::consts::ARCH))?;
Ok(())
}
#[tracing::instrument(level = "info", fields(command = ?c), err)]
fn run(c: &mut Command) -> Result<()> {
c.stdout(Stdio::inherit()).stderr(Stdio::inherit());
let status = c.status().wrap_err("Unable to create temporary crate")?;
if !status.success() { Err(eyre!("{c:?} failed with exit code: {status}")) } else { Ok(()) }
}