use anyhow::{anyhow, Context, Result}; use std::{ fs::File, path::{Path, PathBuf}, process::Stdio, thread, time::Duration, }; use super::docker_compose; use crate::{command_builder::CommandBuilder, debug_eprintln}; fn get_containers(container: &str) -> Result<[String; 2]> { // get db container let db_container = CommandBuilder::docker_compose() .args("ps -q") .args(container) .exec_get_stdout()? .trim() .to_string(); let no_result = db_container.is_empty(); if no_result { return Err(anyhow!("no container")); } // get all containers and filter out db container let app_containers = CommandBuilder::docker_compose() .args("ps -q") .exec_get_stdout()? .split_whitespace() .filter(|x| x != &db_container) .collect::>() .join(" "); Ok([db_container, app_containers]) } pub fn import(container: &str, file: &Path) -> Result<()> { let [db_container, app_containers] = get_containers(container)?; let dump_file = file.to_string_lossy(); eprintln!("stopping all containers"); docker_compose::stop()?; eprintln!("starting db container"); docker_compose::start(Some(container))?; eprintln!("restoring database"); let commands = [ format!("cp {dump_file} {db_container}:/tmp/dbdump"), format!("exec {db_container} dropdb -U db db"), format!("exec {db_container} createdb -U db -E utf8 -T template0 db"), format!("exec {db_container} pg_restore -U db --dbname=db /tmp/dbdump"), ]; for command in commands { debug_eprintln!("waiting until pg_isready"); while !CommandBuilder::docker() .args(&format!( "exec {db_container} pg_isready -h {container} -p 5432 -U db", )) .build()? .stdout(Stdio::null()) .spawn()? .wait()? .success() { thread::sleep(Duration::from_secs(1)); } CommandBuilder::docker().args(&command).exec()?; } eprintln!("restarting containers"); docker_compose::stop()?; docker_compose::up()?; Ok(()) } pub fn dump(container: &str, file: &PathBuf) -> Result<()> { let [db_container, _] = get_containers(container)?; eprintln!("dumping to local file {}", file.to_string_lossy()); let file = File::create(file)?; let stdout = Stdio::from(file); let command = format!("exec {db_container} pg_dump -U db --format=c db"); CommandBuilder::docker() .args(&command) .exec_redirect_stdout(stdout)?; Ok(()) }