Skip to content
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
43 changes: 39 additions & 4 deletions src/asynchronous.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::convert::TryInto;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::{Arc, OnceLock};

Expand Down Expand Up @@ -115,6 +115,7 @@ pub(crate) async fn exec_create_db(
port: u32,
owner: &str,
dbname: &str,
template_db: Option<&str>,
) -> TmpPostgrustResult<()> {
let mut command = Command::new(createdb_bin);
command
Expand All @@ -126,8 +127,11 @@ pub(crate) async fn exec_create_db(
.arg("postgres")
.arg("-O")
.arg(owner)
.arg("--echo")
.arg(dbname);
.arg("--echo");
if let Some(template_db) = template_db {
command.arg("-T").arg(template_db);
}
command.arg(dbname);
cmd_as_non_root(&mut command);
exec_process(&mut command, TmpPostgrustError::CreateDBFailed).await
}
Expand Down Expand Up @@ -199,6 +203,7 @@ pub struct ProcessGuard {
pub(crate) _cache_directory: Arc<TempDir>,
/// Socket directory for connection to the running process.
pub(crate) socket_dir: Arc<TempDir>,
pub(crate) createdb_bin: PathBuf,
pub(crate) postgres_process: Child,
// Limit the total concurrent processes.
pub(crate) _process_permit: SemaphorePermit<'static>,
Expand All @@ -224,17 +229,47 @@ impl ProcessGuard {
/// Panics if a string file path cannot be obtained from the socket directory.
#[must_use]
pub fn connection_string(&self) -> String {
self.connection_string_for_db(&self.db_name)
}

/// Get a Postgresql format connection string for a database on this running instance.
///
/// # Panics
///
/// Panics if a string file path cannot be obtained from the socket directory.
#[must_use]
pub fn connection_string_for_db(&self, db_name: &str) -> String {
format!(
"postgresql:///?host={}&port={}&dbname={}&user={}",
self.socket_dir
.path()
.to_str()
.expect("Failed to convert socket directory to a path"),
self.port,
self.db_name,
db_name,
self.user_name,
)
}

/// Clone the current database in this running instance.
///
/// The returned connection string points at the newly-created database.
///
/// # Errors
///
/// Returns an error if `createdb` fails to clone the current database.
pub async fn clone_database(&self, db_name: &str) -> TmpPostgrustResult<String> {
exec_create_db(
&self.createdb_bin,
self.socket_dir.path(),
self.port,
&self.user_name,
db_name,
Some(&self.db_name),
)
.await?;
Ok(self.connection_string_for_db(db_name))
}
}

fn cmd_as_non_root(command: &mut Command) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ impl TmpPostgrustFactory {
process.port,
&process.user_name,
&process.db_name,
None,
)?;

Ok(factory)
Expand Down Expand Up @@ -352,6 +353,7 @@ impl TmpPostgrustFactory {
process.port,
&process.user_name,
&process.db_name,
None,
)
.await?;

Expand Down Expand Up @@ -467,6 +469,7 @@ impl TmpPostgrustFactory {
_data_directory: Arc::clone(dir),
_cache_directory: Arc::clone(&self.cache_dir),
socket_dir: Arc::clone(&self.socket_dir),
createdb_bin: self.binaries.createdb.clone(),
})
}

Expand Down Expand Up @@ -548,6 +551,7 @@ impl TmpPostgrustFactory {
_data_directory: Arc::clone(dir),
_cache_directory: Arc::clone(&self.cache_dir),
socket_dir: Arc::clone(&self.socket_dir),
createdb_bin: self.binaries.createdb.clone(),
postgres_process: postgres_process_handle,
_process_permit: permit,
})
Expand Down
42 changes: 38 additions & 4 deletions src/synchronous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fs::create_dir_all;
use std::io::BufReader;
use std::io::Lines;
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Child;
use std::process::ChildStderr;
use std::process::ChildStdout;
Expand Down Expand Up @@ -125,6 +125,7 @@ pub(crate) fn exec_create_db(
port: u32,
owner: &str,
dbname: &str,
template_db: Option<&str>,
) -> TmpPostgrustResult<()> {
let mut command = Command::new(createdb_bin);
command
Expand All @@ -136,8 +137,11 @@ pub(crate) fn exec_create_db(
.arg("postgres")
.arg("-O")
.arg(owner)
.arg("--echo")
.arg(dbname);
.arg("--echo");
if let Some(template_db) = template_db {
command.arg("-T").arg(template_db);
}
command.arg(dbname);
cmd_as_non_root(&mut command);
exec_process(&mut command, TmpPostgrustError::CreateDBFailed)
}
Expand Down Expand Up @@ -192,6 +196,7 @@ pub struct ProcessGuard {
pub(crate) _cache_directory: Arc<TempDir>,
/// Socket directory for connection to the running process.
pub(crate) socket_dir: Arc<TempDir>,
pub(crate) createdb_bin: PathBuf,
}

impl ProcessGuard {
Expand All @@ -202,17 +207,46 @@ impl ProcessGuard {
/// Panics if a string file path cannot be obtained from the socket directory.
#[must_use]
pub fn connection_string(&self) -> String {
self.connection_string_for_db(&self.db_name)
}

/// Get a Postgresql format connection string for a database on this running instance.
///
/// # Panics
///
/// Panics if a string file path cannot be obtained from the socket directory.
#[must_use]
pub fn connection_string_for_db(&self, db_name: &str) -> String {
format!(
"postgresql:///?host={}&port={}&dbname={}&user={}",
self.socket_dir
.path()
.to_str()
.expect("Failed to convert socket directory to a path"),
self.port,
self.db_name,
db_name,
self.user_name,
)
}

/// Clone the current database in this running instance.
///
/// The returned connection string points at the newly-created database.
///
/// # Errors
///
/// Returns an error if `createdb` fails to clone the current database.
pub fn clone_database(&self, db_name: &str) -> TmpPostgrustResult<String> {
exec_create_db(
&self.createdb_bin,
self.socket_dir.path(),
self.port,
&self.user_name,
db_name,
Some(&self.db_name),
)?;
Ok(self.connection_string_for_db(db_name))
}
}

/// Signal that the process needs to end.
Expand Down
Loading