use crate::command::get::get_property;
use crate::command::install::install_extension;
use crate::command::start::start_postgres;
use crate::command::stop::stop_postgres;
use crate::profile::CargoProfile;
use crate::CommandExecute;
use cargo_toml::Manifest;
use eyre::{eyre, WrapErr};
use owo_colors::OwoColorize;
use pgx_pg_config::{createdb, PgConfig, Pgx};
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::process::Command;
#[derive(clap::Args, Debug)]
#[clap(author)]
pub(crate) struct Run {
#[clap(env = "PG_VERSION")]
pg_version: Option<String>,
dbname: Option<String>,
#[clap(long, short)]
package: Option<String>,
#[clap(long)]
manifest_path: Option<String>,
#[clap(long, short)]
release: bool,
#[clap(long)]
profile: Option<String>,
#[clap(flatten)]
features: clap_cargo::Features,
#[clap(from_global, action = ArgAction::Count)]
verbose: u8,
#[clap(env = "PGX_PGCLI", long)]
pgcli: bool,
}
impl CommandExecute for Run {
#[tracing::instrument(level = "error", skip(self))]
fn execute(mut self) -> eyre::Result<()> {
let metadata = crate::metadata::metadata(&self.features, self.manifest_path.as_ref())
.wrap_err("couldn't get cargo metadata")?;
crate::metadata::validate(&metadata)?;
let package_manifest_path =
crate::manifest::manifest_path(&metadata, self.package.as_ref())
.wrap_err("Couldn't get manifest path")?;
let package_manifest =
Manifest::from_path(&package_manifest_path).wrap_err("Couldn't parse manifest")?;
let pgx = Pgx::from_config()?;
let (pg_config, pg_version) = match self.pg_version {
Some(pg_version) => {
match pgx.get(&pg_version) {
Ok(pg_config) => (pg_config, pg_version),
Err(err) => {
if self.dbname.is_some() {
return Err(err);
}
self.dbname = Some(pg_version);
let default_pg_version =
crate::manifest::default_pg_version(&package_manifest)
.ok_or(eyre!("No provided `pg$VERSION` flag."))?;
(pgx.get(&default_pg_version)?, default_pg_version)
}
}
}
None => {
let default_pg_version = crate::manifest::default_pg_version(&package_manifest)
.ok_or(eyre!("No provided `pg$VERSION` flag."))?;
(pgx.get(&default_pg_version)?, default_pg_version)
}
};
let features =
crate::manifest::features_for_version(self.features, &package_manifest, &pg_version);
let dbname = match self.dbname {
Some(dbname) => dbname,
None => get_property(&package_manifest_path, "extname")?
.ok_or(eyre!("could not determine extension name"))?,
};
let profile = CargoProfile::from_flags(self.release, self.profile.as_deref())?;
run(
pg_config,
self.manifest_path.as_ref(),
self.package.as_ref(),
package_manifest_path,
&dbname,
&profile,
self.pgcli,
&features,
)
}
}
#[tracing::instrument(level = "error", skip_all, fields(
pg_version = %pg_config.version()?,
dbname,
profile = ?profile,
))]
pub(crate) fn run(
pg_config: &PgConfig,
user_manifest_path: Option<impl AsRef<Path>>,
user_package: Option<&String>,
package_manifest_path: impl AsRef<Path>,
dbname: &str,
profile: &CargoProfile,
pgcli: bool,
features: &clap_cargo::Features,
) -> eyre::Result<()> {
stop_postgres(pg_config)?;
install_extension(
user_manifest_path,
user_package,
package_manifest_path,
pg_config,
profile,
false,
None,
features,
)?;
start_postgres(pg_config)?;
if !createdb(pg_config, dbname, false, true)? {
println!("{} existing database {}", " Re-using".bold().cyan(), dbname);
}
exec_psql(pg_config, dbname, pgcli)
}
pub(crate) fn exec_psql(pg_config: &PgConfig, dbname: &str, pgcli: bool) -> eyre::Result<()> {
let mut command = Command::new(match pgcli {
false => pg_config.psql_path()?.into_os_string(),
true => "pgcli".to_string().into(),
});
command
.env_remove("PGDATABASE")
.env_remove("PGHOST")
.env_remove("PGPORT")
.env_remove("PGUSER")
.arg("-h")
.arg(pg_config.host())
.arg("-p")
.arg(pg_config.port()?.to_string())
.arg(dbname);
panic!("{}", command.exec());
}