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

feat!: allow releases URL to be configured #80

Merged
merged 6 commits into from
Jun 20, 2024
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ PostgreSQL is covered under [The PostgreSQL License](https://opensource.org/lice

## Notes

Uses PostgreSQL binaries from [theseus-rs/postgresql-binaries](https://github.com/theseus-rs/postgresql_binaries).
Uses PostgreSQL binaries from [theseus-rs/postgresql-binaries](https://github.com/theseus-rs/postgresql_binaries) by
default.

## Contribution

Expand Down
4 changes: 2 additions & 2 deletions examples/archive_async/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![forbid(unsafe_code)]
#![deny(clippy::pedantic)]

use postgresql_archive::{extract, get_archive, Result, LATEST};
use postgresql_archive::{extract, get_archive, Result, DEFAULT_RELEASES_URL, LATEST};

#[tokio::main]
async fn main() -> Result<()> {
let (archive_version, archive) = get_archive(&LATEST).await?;
let (archive_version, archive) = get_archive(DEFAULT_RELEASES_URL, &LATEST).await?;
let out_dir = tempfile::tempdir()?.into_path();
extract(&archive, &out_dir).await?;
println!(
Expand Down
4 changes: 2 additions & 2 deletions examples/archive_sync/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
#![deny(clippy::pedantic)]

use postgresql_archive::blocking::{extract, get_archive};
use postgresql_archive::{Result, LATEST};
use postgresql_archive::{Result, DEFAULT_RELEASES_URL, LATEST};

fn main() -> Result<()> {
let (archive_version, archive) = get_archive(&LATEST)?;
let (archive_version, archive) = get_archive(DEFAULT_RELEASES_URL, &LATEST)?;
let out_dir = tempfile::tempdir()?.into_path();
extract(&archive, &out_dir)?;
println!(
Expand Down
4 changes: 2 additions & 2 deletions postgresql_archive/benches/archive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bytes::Bytes;
use criterion::{criterion_group, criterion_main, Criterion};
use postgresql_archive::blocking::{extract, get_archive};
use postgresql_archive::{Result, LATEST};
use postgresql_archive::{Result, DEFAULT_RELEASES_URL, LATEST};
use std::fs::{create_dir_all, remove_dir_all};
use std::time::Duration;

Expand All @@ -11,7 +11,7 @@ fn benchmarks(criterion: &mut Criterion) {

fn bench_extract(criterion: &mut Criterion) -> Result<()> {
let version = &LATEST;
let (_archive_version, archive) = get_archive(version)?;
let (_archive_version, archive) = get_archive(DEFAULT_RELEASES_URL, version)?;

criterion.bench_function("extract", |bencher| {
bencher.iter(|| {
Expand Down
39 changes: 23 additions & 16 deletions postgresql_archive/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use tracing::{debug, instrument, warn};

const GITHUB_API_VERSION_HEADER: &str = "X-GitHub-Api-Version";
const GITHUB_API_VERSION: &str = "2022-11-28";
pub const DEFAULT_RELEASES_URL: &str =
"https://api.github.com/repos/theseus-rs/postgresql-binaries/releases";

lazy_static! {
static ref GITHUB_TOKEN: Option<String> = match std::env::var("GITHUB_TOKEN") {
Expand Down Expand Up @@ -103,14 +105,13 @@ fn reqwest_client() -> ClientWithMiddleware {
/// Gets a release from GitHub for a given [version](Version) of PostgreSQL. If a release for the
/// [version](Version) is not found, then a [ReleaseNotFound] error is returned.
#[instrument(level = "debug")]
async fn get_release(version: &Version) -> Result<Release> {
let url = "https://api.github.com/repos/theseus-rs/postgresql-binaries/releases";
async fn get_release(releases_url: &str, version: &Version) -> Result<Release> {
let client = reqwest_client();

debug!("Attempting to locate release for version {version}");

if version.minor.is_some() && version.release.is_some() {
let request = client.get(format!("{url}/tags/{version}"));
let request = client.get(format!("{releases_url}/tags/{version}"));
let response = request.send().await?.error_for_status()?;
let release = response.json::<Release>().await?;

Expand All @@ -123,7 +124,7 @@ async fn get_release(version: &Version) -> Result<Release> {

loop {
let request = client
.get(url)
.get(releases_url)
.query(&[("page", page.to_string().as_str()), ("per_page", "100")]);
let response = request.send().await?.error_for_status()?;
let response_releases = response.json::<Vec<Release>>().await?;
Expand Down Expand Up @@ -169,8 +170,8 @@ async fn get_release(version: &Version) -> Result<Release> {
/// specified, then the latest version is returned. If a release for the [version](Version) is not found, then a
/// [ReleaseNotFound] error is returned.
#[instrument(level = "debug")]
pub async fn get_version(version: &Version) -> Result<Version> {
let release = get_release(version).await?;
pub async fn get_version(releases_url: &str, version: &Version) -> Result<Version> {
let release = get_release(releases_url, version).await?;
Version::from_str(&release.tag_name)
}

Expand All @@ -181,8 +182,12 @@ pub async fn get_version(version: &Version) -> Result<Version> {
///
/// Two assets are returned. The first [asset](Asset) is the archive, and the second [asset](Asset) is the archive hash.
#[instrument(level = "debug", skip(target))]
async fn get_asset<S: AsRef<str>>(version: &Version, target: S) -> Result<(Version, Asset, Asset)> {
let release = get_release(version).await?;
async fn get_asset<S: AsRef<str>>(
releases_url: &str,
version: &Version,
target: S,
) -> Result<(Version, Asset, Asset)> {
let release = get_release(releases_url, version).await?;
let asset_version = Version::from_str(&release.tag_name)?;
let mut asset: Option<Asset> = None;
let mut asset_hash: Option<Asset> = None;
Expand Down Expand Up @@ -213,8 +218,8 @@ async fn get_asset<S: AsRef<str>>(version: &Version, target: S) -> Result<(Versi
///
/// Returns the archive version and bytes.
#[instrument]
pub async fn get_archive(version: &Version) -> Result<(Version, Bytes)> {
get_archive_for_target(version, target_triple::TARGET).await
pub async fn get_archive(releases_url: &str, version: &Version) -> Result<(Version, Bytes)> {
get_archive_for_target(releases_url, version, target_triple::TARGET).await
}

/// Gets the archive for a given [version](Version) of PostgreSQL and
Expand All @@ -226,10 +231,11 @@ pub async fn get_archive(version: &Version) -> Result<(Version, Bytes)> {
#[allow(clippy::cast_precision_loss)]
#[instrument(level = "debug", skip(target))]
pub async fn get_archive_for_target<S: AsRef<str>>(
releases_url: &str,
version: &Version,
target: S,
) -> Result<(Version, Bytes)> {
let (asset_version, asset, asset_hash) = get_asset(version, target).await?;
let (asset_version, asset, asset_hash) = get_asset(releases_url, version, target).await?;

debug!(
"Downloading archive hash {}",
Expand Down Expand Up @@ -436,21 +442,22 @@ mod tests {

#[test(tokio::test)]
async fn test_get_release() -> Result<()> {
let _ = get_release(&VERSION).await?;
let _ = get_release(DEFAULT_RELEASES_URL, &VERSION).await?;
Ok(())
}

#[test(tokio::test)]
async fn test_get_release_version_not_found() -> Result<()> {
let release = get_release(&INVALID_VERSION).await;
let release = get_release(DEFAULT_RELEASES_URL, &INVALID_VERSION).await;
assert!(release.is_err());
Ok(())
}

#[test(tokio::test)]
async fn test_get_asset() -> Result<()> {
let target_triple = "x86_64-unknown-linux-musl".to_string();
let (asset_version, asset, asset_hash) = get_asset(&VERSION, &target_triple).await?;
let (asset_version, asset, asset_hash) =
get_asset(DEFAULT_RELEASES_URL, &VERSION, &target_triple).await?;
assert!(asset_version.matches(&VERSION));
assert!(asset.name.contains(&target_triple));
assert!(asset_hash.name.contains(&target_triple));
Expand All @@ -462,15 +469,15 @@ mod tests {
#[test(tokio::test)]
async fn test_get_asset_version_not_found() -> Result<()> {
let target_triple = "x86_64-unknown-linux-musl".to_string();
let result = get_asset(&INVALID_VERSION, &target_triple).await;
let result = get_asset(DEFAULT_RELEASES_URL, &INVALID_VERSION, &target_triple).await;
assert!(result.is_err());
Ok(())
}

#[test(tokio::test)]
async fn test_get_asset_target_not_found() -> Result<()> {
let target_triple = "wasm64-unknown-unknown".to_string();
let result = get_asset(&VERSION, &target_triple).await;
let result = get_asset(DEFAULT_RELEASES_URL, &VERSION, &target_triple).await;
assert!(result.is_err());
Ok(())
}
Expand Down
67 changes: 67 additions & 0 deletions postgresql_archive/src/blocking/archive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::Version;
use bytes::Bytes;
use std::path::Path;
use tokio::runtime::Runtime;

lazy_static! {
static ref RUNTIME: Runtime = Runtime::new().unwrap();
}

/// Gets the version of PostgreSQL for the specified [version](Version). If the version minor or release is not
/// specified, then the latest version is returned. If a release for the [version](Version) is not found, then a
/// [ReleaseNotFound](crate::Error::ReleaseNotFound) error is returned.
///
/// # Errors
///
/// Returns an error if the version is not found.
pub fn get_version(releases_url: &str, version: &Version) -> crate::Result<Version> {
RUNTIME
.handle()
.block_on(async move { crate::get_version(releases_url, version).await })
}

/// Gets the archive for a given [version](Version) of PostgreSQL for the current target.
/// If the [version](Version) is not found for this target, then an
/// [error](crate::Error) is returned.
///
/// Returns the archive version and bytes.
///
/// # Errors
///
/// Returns an error if the version is not found.
pub fn get_archive(releases_url: &str, version: &Version) -> crate::Result<(Version, Bytes)> {
RUNTIME
.handle()
.block_on(async move { crate::get_archive(releases_url, version).await })
}

/// Gets the archive for a given [version](Version) of PostgreSQL and
/// [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html).
/// If the [version](Version) or [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html)
/// is not found, then an [error](crate::error::Error) is returned.
///
/// Returns the archive version and bytes.
///
/// # Errors
///
/// Returns an error if the version or target is not found.
pub fn get_archive_for_target<S: AsRef<str>>(
releases_url: &str,
version: &Version,
target: S,
) -> crate::Result<(Version, Bytes)> {
RUNTIME
.handle()
.block_on(async move { crate::get_archive_for_target(releases_url, version, target).await })
}

/// Extracts the compressed tar [bytes](Bytes) to the [out_dir](Path).
///
/// # Errors
///
/// Returns an error if the extraction fails.
pub fn extract(bytes: &Bytes, out_dir: &Path) -> crate::Result<()> {
RUNTIME
.handle()
.block_on(async move { crate::extract(bytes, out_dir).await })
}
67 changes: 2 additions & 65 deletions postgresql_archive/src/blocking/mod.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,3 @@
use crate::Version;
use bytes::Bytes;
use std::path::Path;
use tokio::runtime::Runtime;
mod archive;

lazy_static! {
static ref RUNTIME: Runtime = Runtime::new().unwrap();
}

/// Gets the version of PostgreSQL for the specified [version](Version). If the version minor or release is not
/// specified, then the latest version is returned. If a release for the [version](Version) is not found, then a
/// [ReleaseNotFound](crate::Error::ReleaseNotFound) error is returned.
///
/// # Errors
///
/// Returns an error if the version is not found.
pub fn get_version(version: &Version) -> crate::Result<Version> {
RUNTIME
.handle()
.block_on(async move { crate::get_version(version).await })
}

/// Gets the archive for a given [version](Version) of PostgreSQL for the current target.
/// If the [version](Version) is not found for this target, then an
/// [error](crate::Error) is returned.
///
/// Returns the archive version and bytes.
///
/// # Errors
///
/// Returns an error if the version is not found.
pub fn get_archive(version: &Version) -> crate::Result<(Version, Bytes)> {
RUNTIME
.handle()
.block_on(async move { crate::get_archive(version).await })
}

/// Gets the archive for a given [version](Version) of PostgreSQL and
/// [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html).
/// If the [version](Version) or [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html)
/// is not found, then an [error](crate::error::Error) is returned.
///
/// Returns the archive version and bytes.
///
/// # Errors
///
/// Returns an error if the version or target is not found.
pub fn get_archive_for_target<S: AsRef<str>>(
version: &Version,
target: S,
) -> crate::Result<(Version, Bytes)> {
RUNTIME
.handle()
.block_on(async move { crate::get_archive_for_target(version, target).await })
}

/// Extracts the compressed tar [bytes](Bytes) to the [out_dir](Path).
///
/// # Errors
///
/// Returns an error if the extraction fails.
pub fn extract(bytes: &Bytes, out_dir: &Path) -> crate::Result<()> {
RUNTIME
.handle()
.block_on(async move { crate::extract(bytes, out_dir).await })
}
pub use archive::{extract, get_archive, get_archive_for_target, get_version};
10 changes: 6 additions & 4 deletions postgresql_archive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
//! ### Asynchronous API
//!
//! ```no_run
//! use postgresql_archive::{extract, get_archive, Result, LATEST};
//! use postgresql_archive::{extract, get_archive, Result, DEFAULT_RELEASES_URL, LATEST};
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! let (archive_version, archive) = get_archive(&LATEST).await?;
//! let (archive_version, archive) = get_archive(DEFAULT_RELEASES_URL, &LATEST).await?;
//! let out_dir = std::env::temp_dir();
//! extract(&archive, &out_dir).await
//! }
Expand All @@ -34,10 +34,10 @@
//! ### Synchronous API
//! ```no_run
//! #[cfg(feature = "blocking")] {
//! use postgresql_archive::LATEST;
//! use postgresql_archive::{DEFAULT_RELEASES_URL, LATEST};
//! use postgresql_archive::blocking::{extract, get_archive};
//!
//! let (archive_version, archive) = get_archive(&LATEST).unwrap();
//! let (archive_version, archive) = get_archive(DEFAULT_RELEASES_URL, &LATEST).unwrap();
//! let out_dir = std::env::temp_dir();
//! let result = extract(&archive, &out_dir).unwrap();
//! }
Expand Down Expand Up @@ -106,6 +106,7 @@
#![forbid(unsafe_code)]
#![deny(clippy::pedantic)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::module_name_repetitions)]

#[macro_use]
extern crate lazy_static;
Expand All @@ -117,6 +118,7 @@ mod error;
mod github;
mod version;

pub use archive::DEFAULT_RELEASES_URL;
pub use archive::{extract, get_archive, get_archive_for_target, get_version};
pub use error::{Error, Result};
#[allow(deprecated)]
Expand Down
Loading
Loading