Skip to content

Check for existing installations in children before installing. #162

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

Merged
merged 3 commits into from
Feb 26, 2025
Merged
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
63 changes: 52 additions & 11 deletions postgresql_embedded/src/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
use postgresql_commands::pg_ctl::Mode::{Start, Stop};
use postgresql_commands::pg_ctl::PgCtlBuilder;
use postgresql_commands::pg_ctl::ShutdownMode::Fast;
use semver::Version;
use sqlx::{PgPool, Row};
use std::fs::{remove_dir_all, remove_file};
use std::fs::{read_dir, remove_dir_all, remove_file};
use std::io::prelude::*;
use std::net::TcpListener;
use std::path::PathBuf;
use tracing::{debug, instrument};

use crate::Error::{CreateDatabaseError, DatabaseExistsError, DropDatabaseError};
Expand Down Expand Up @@ -73,7 +75,7 @@
Status::Started
} else if self.is_initialized() {
Status::Stopped
} else if self.is_installed() {
} else if self.installed_dir().is_some() {
Status::Installed
} else {
Status::NotInstalled
Expand All @@ -86,13 +88,48 @@
&self.settings
}

/// Check if the `PostgreSQL` server is installed
fn is_installed(&self) -> bool {
let Some(version) = self.settings.version.exact_version() else {
return false;
};
/// Find a directory where `PostgreSQL` server is installed.
/// This first checks if the installation directory exists and matches the version requirement.
/// If it doesn't, it will search all the child directories for the latest version that matches the requirement.
/// If it returns None, we couldn't find a matching installation.
fn installed_dir(&self) -> Option<PathBuf> {
let path = &self.settings.installation_dir;
path.ends_with(version.to_string()) && path.exists()
let maybe_path_version = path
.file_name()
.and_then(|file_name| Version::parse(&file_name.to_string_lossy()).ok());
// If this directory matches the version requirement, we're done.
if let Some(path_version) = maybe_path_version {
if self.settings.version.matches(&path_version) && path.exists() {
return Some(path.clone());
}
}

Check warning on line 105 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L105

Added line #L105 was not covered by tests

// Get all directories in the path as versions.
let mut versions = read_dir(path)
.ok()?
.filter_map(|entry| {
let Some(entry) = entry.ok() else {

Check warning on line 111 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L110-L111

Added lines #L110 - L111 were not covered by tests
// We ignore filesystem errors.
return None;

Check warning on line 113 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L113

Added line #L113 was not covered by tests
};
// Skip non-directories
if !entry.file_type().ok()?.is_dir() {
return None;
}
let file_name = entry.file_name();
let version = Version::parse(&file_name.to_string_lossy()).ok()?;
if self.settings.version.matches(&version) {
Some((version, entry.path()))

Check warning on line 122 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L116-L122

Added lines #L116 - L122 were not covered by tests
} else {
None

Check warning on line 124 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L124

Added line #L124 was not covered by tests
}
})
.collect::<Vec<_>>();
// Sort the versions in descending order i.e. latest version first
versions.sort_by(|(a, _), (b, _)| b.cmp(a));
// Get the first matching version as the best match
let version_path = versions.first().map(|(_, path)| path.clone());
version_path

Check warning on line 132 in postgresql_embedded/src/postgresql.rs

View check run for this annotation

Codecov / codecov/patch

postgresql_embedded/src/postgresql.rs#L126-L132

Added lines #L126 - L132 were not covered by tests
}

/// Check if the `PostgreSQL` server is initialized
Expand All @@ -111,10 +148,14 @@
/// If the data directory already exists, the database will not be initialized.
#[instrument(skip(self))]
pub async fn setup(&mut self) -> Result<()> {
if !self.is_installed() {
self.install().await?;
match self.installed_dir() {
Some(installed_dir) => {
self.settings.installation_dir = installed_dir;
}
None => {
self.install().await?;
}
}

if !self.is_initialized() {
self.initialize().await?;
}
Expand Down
Loading