use std::path::{Path, PathBuf};
use glob::glob;
use which::which;
use crate::errors::{TmpPostgrustError, TmpPostgrustResult};
const SEARCH_PATHS: [&str; 5] = [
"/usr/local/pgsql",
"/usr/local",
"/usr/pgsql-*",
"/usr/lib/postgresql/*",
"/opt/local/lib/postgresql*",
];
pub(crate) fn find_postgresql_command(
bin_dir: Option<&Path>,
name: &str,
) -> TmpPostgrustResult<PathBuf> {
if let Some(dir) = bin_dir {
return which::which_in(name, Some(dir), std::path::Path::new(".")).map_err(|_| {
TmpPostgrustError::PostgresCommandNotFound {
command: name.to_string(),
searched_dir: Some(dir.to_owned()),
}
});
}
if let Ok(path) = which(name) {
return Ok(path);
}
for path in SEARCH_PATHS {
if let Some(entry) = glob(&(path.to_string() + "/bin/" + name))
.expect("Failed to read glob pattern")
.flatten()
.next()
{
return Ok(entry);
}
}
Err(TmpPostgrustError::PostgresCommandNotFound {
command: name.to_string(),
searched_dir: None,
})
}
#[derive(Debug)]
pub(crate) struct PostgresBinaries {
pub postgres: PathBuf,
pub initdb: PathBuf,
pub createdb: PathBuf,
pub createuser: PathBuf,
}
impl PostgresBinaries {
pub(crate) fn resolve(bin_dir: Option<&Path>) -> TmpPostgrustResult<Self> {
Ok(Self {
postgres: find_postgresql_command(bin_dir, "postgres")?,
initdb: find_postgresql_command(bin_dir, "initdb")?,
createdb: find_postgresql_command(bin_dir, "createdb")?,
createuser: find_postgresql_command(bin_dir, "createuser")?,
})
}
}
pub(crate) fn all_dir_entries(src_dir: &Path) -> TmpPostgrustResult<(Vec<PathBuf>, Vec<PathBuf>)> {
let mut dirs = Vec::new();
let mut others = Vec::new();
for read_dir in src_dir
.read_dir()
.map_err(TmpPostgrustError::CopyCachedInitDBFailedFileNotFound)?
{
let entry = read_dir.map_err(TmpPostgrustError::CopyCachedInitDBFailedFileNotFound)?;
let entry_file_type = entry
.file_type()
.map_err(TmpPostgrustError::CopyCachedInitDBFailedCouldNotReadFileType)?;
if entry_file_type.is_dir() {
let (sub_dirs, sub_others) = all_dir_entries(&entry.path())?;
dirs.push(entry.path());
dirs.extend(sub_dirs);
others.extend(sub_others);
} else {
others.push(entry.path());
}
}
Ok((dirs, others))
}
pub(crate) fn build_copy_dst_path(
target_path: &Path,
src_dir: &Path,
dst_dir: &Path,
) -> TmpPostgrustResult<PathBuf> {
let entry_sub_path = target_path
.strip_prefix(src_dir)
.map_err(TmpPostgrustError::CopyCachedInitDBFailedCouldNotStripPathPrefix)?;
let dst_path = dst_dir.join(entry_sub_path);
Ok(dst_path)
}