use pgx_pg_config::{PgConfig, Pgx};
pub(crate) fn pgx_default(supported_major_versions: &[u16]) -> eyre::Result<Pgx> {
let mut pgx = Pgx::new();
rss::PostgreSQLVersionRss::new(supported_major_versions)?
.into_iter()
.for_each(|version| pgx.push(PgConfig::from(version)));
Ok(pgx)
}
mod rss {
use env_proxy::for_url_str;
use eyre::WrapErr;
use owo_colors::OwoColorize;
use pgx_pg_config::PgVersion;
use serde_derive::Deserialize;
use ureq::{Agent, AgentBuilder, Proxy};
use url::Url;
pub(super) struct PostgreSQLVersionRss;
impl PostgreSQLVersionRss {
pub(super) fn new(supported_major_versions: &[u16]) -> eyre::Result<Vec<PgVersion>> {
static VERSIONS_RSS_URL: &str = "https://www.postgresql.org/versions.rss";
let http_client = if let Some((host, port)) = for_url_str(VERSIONS_RSS_URL).host_port()
{
AgentBuilder::new()
.proxy(Proxy::new(format!("https://{host}:{port}"))?)
.build()
} else {
Agent::new()
};
let response = http_client
.get(VERSIONS_RSS_URL)
.call()
.wrap_err_with(|| format!("unable to retrieve {}", VERSIONS_RSS_URL))?;
let rss: Rss = match serde_xml_rs::from_str(&response.into_string()?) {
Ok(rss) => rss,
Err(e) => return Err(e.into()),
};
let mut versions = Vec::new();
for item in rss.channel.item {
let title = item.title.trim();
let mut parts = title.split('.');
let major = parts.next();
let minor = parts.next();
let major = major.unwrap().parse::<u16>().unwrap_or_default();
let minor = minor.unwrap().parse::<u16>().unwrap_or_default();
if supported_major_versions.contains(&major) {
versions.push(PgVersion::new(
major,
minor,
Url::parse(
&format!("https://ftp.postgresql.org/pub/source/v{major}.{minor}/postgresql-{major}.{minor}.tar.bz2",
major = major, minor = minor)
)
.expect("invalid url")
))
}
}
println!(
"{} Postgres {}",
" Discovered".white().bold(),
versions
.iter()
.map(|ver| format!("v{ver}"))
.collect::<Vec<_>>()
.join(", ")
);
Ok(versions)
}
}
#[derive(Deserialize)]
struct Rss {
channel: Channel,
}
#[derive(Deserialize)]
struct Channel {
item: Vec<Item>,
}
#[derive(Deserialize)]
struct Item {
title: String,
}
}