misc: initial implementation

This commit is contained in:
hdbg
2025-12-04 18:30:19 +01:00
parent c20f8d6d5f
commit ba079d24b5
6 changed files with 43 additions and 51 deletions

View File

@@ -1,3 +1,3 @@
version = "18.1"
password = "odqAsS49KNyaXjrw"
password = "P8t42UQ53iIza2Ic"
port = 5432

View File

@@ -1,8 +1,7 @@
_ __ __ ___ __
| '_ \ / _` \ \/ /
| |_) | (_| |> <
| .__/ \__, /_/\_\
| | __/ |
|_| |___/
_______ _______ __ __
| || || |_| |
| _ || ___|| |
| |_| || | __ | |
| ___|| || | | |
| | | |_| || _ |
|___| |_______||__| |__|

View File

@@ -1,4 +1,4 @@
use clap::{Args, Parser, Subcommand, builder::styling};
use clap::{Parser, Subcommand, builder::styling};
const STYLES: styling::Styles = styling::Styles::styled()
.header(styling::AnsiColor::Green.on_default().bold())

View File

@@ -35,7 +35,7 @@ impl Display for PostgresVersion {
}
}
const PROJECT_FILENAME: &'static str = "pgx.toml";
const PROJECT_FILENAME: &str = "pgx.toml";
/// Configuration stored in pgx.toml
#[serde_as]

View File

@@ -8,13 +8,13 @@ use bollard::{
errors::Error,
query_parameters::{
CreateContainerOptions, CreateImageOptions, InspectContainerOptions, ListImagesOptions,
ListImagesOptionsBuilder, SearchImagesOptions, StartContainerOptions, StopContainerOptions,
StartContainerOptions, StopContainerOptions,
},
secret::{ContainerConfig, ContainerCreateBody, CreateImageInfo},
secret::{ContainerCreateBody, CreateImageInfo},
};
use futures::{Stream, StreamExt, TryStreamExt};
use indicatif::{MultiProgress, ProgressBar, ProgressState, ProgressStyle};
use miette::{Context, IntoDiagnostic, Result, diagnostic};
use miette::{Context, IntoDiagnostic, Result};
use tracing::info;
use crate::{
@@ -38,7 +38,7 @@ const DEFAULT_POSTGRES_PORT: u16 = 5432;
const PORT_SEARCH_RANGE: u16 = 100;
fn format_image(ver: &PostgresVersion) -> String {
format!("{DOCKERHUB_POSTGRES}:{}", ver.to_string())
format!("{DOCKERHUB_POSTGRES}:{}", ver)
}
fn find_available_port() -> Result<u16> {
@@ -60,9 +60,7 @@ fn find_available_port() -> Result<u16> {
fn new_download_pb(multi: &MultiProgress, layer_id: &str) -> ProgressBar {
let pb = multi.add(ProgressBar::new(0));
pb.set_style(
ProgressStyle::with_template(&format!(
"{{spinner:.green}} [{{elapsed_precise}}] {{msg}} [{{wide_bar:.cyan/blue}}] {{bytes}}/{{total_bytes}} ({{eta}})"
))
ProgressStyle::with_template(&"{spinner:.green} [{elapsed_precise}] {msg} [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})".to_string())
.unwrap()
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| {
write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()
@@ -399,16 +397,15 @@ const DATABASE: &str = "postgres";
const PASSWORD_LENGTH: usize = 16;
pub fn generate_password() -> String {
let password = (&mut rand::rng())
(&mut rand::rng())
.sample_iter(Alphanumeric)
.take(PASSWORD_LENGTH)
.map(|b| b as char)
.collect();
password
.collect()
}
const MAX_RETRIES: u32 = 10;
const VERIFY_DURATION_SECS: u64 = 5;
const VERIFY_DURATION_SECS: u64 = 10;
pub struct Controller {
pub docker: DockerController,
@@ -473,7 +470,7 @@ impl Controller {
let instance_state = state.get_mut(&project.name);
let container_id = match instance_state {
Some(instance) => match self.ensure_container_exists(&instance).await? {
Some(instance) => match self.ensure_container_exists(instance).await? {
Some(id) => id,
None => self.update_project_container(project, &mut state).await?,
},
@@ -493,7 +490,6 @@ impl Controller {
.is_container_running_by_id(&container_id)
.await?
{
println!("Container is already running");
return Ok(());
}
@@ -503,7 +499,7 @@ impl Controller {
let result = self.try_starting_container(&container_id, attempt).await;
match result {
Ok(_) => break,
Ok(_) => return Ok(()),
Err(err) => println!("Error: {:#?}", err),
}
@@ -520,31 +516,29 @@ impl Controller {
container_id: &String,
attempt: u32,
) -> Result<(), miette::Error> {
Ok(
match self.docker.start_container_by_id(container_id).await {
Ok(_) => {
tokio::time::sleep(tokio::time::Duration::from_secs(VERIFY_DURATION_SECS))
.await;
match self.docker.start_container_by_id(container_id).await {
Ok(_) => {
tokio::time::sleep(tokio::time::Duration::from_secs(VERIFY_DURATION_SECS)).await;
if self.docker.is_container_running_by_id(container_id).await? {
println!("Container started successfully and verified running");
if self.docker.is_container_running_by_id(container_id).await? {
println!("Container started successfully and verified running");
return Ok(());
} else {
println!(
"Container stopped unexpectedly after start (attempt {}/{})",
attempt, MAX_RETRIES
);
}
}
Err(e) => {
return Ok(());
} else {
println!(
"Failed to start container (attempt {}/{}): {}",
attempt, MAX_RETRIES, e
"Container stopped unexpectedly after start (attempt {}/{})",
attempt, MAX_RETRIES
);
}
},
)
}
Err(e) => {
println!(
"Failed to start container (attempt {}/{}): {}",
attempt, MAX_RETRIES, e
);
}
};
Ok(())
}
async fn update_project_container(
@@ -596,7 +590,7 @@ impl Controller {
_container_id: &String,
container_version: PostgresVersion,
) -> Result<(), miette::Error> {
Ok(if container_version != project.config.version {
let _: () = if container_version != project.config.version {
let needs_upgrade = container_version < project.config.version;
if needs_upgrade {
@@ -627,6 +621,7 @@ impl Controller {
project.config.version
);
}
})
};
Ok(())
}
}

View File

@@ -14,12 +14,12 @@ use crate::controller::Controller;
#[tokio::main]
async fn main() -> Result<()> {
println!("{}", include_str!("./banner.txt"));
let controller = Controller::new().await?;
let cli = Cli::parse();
init_tracing(cli.verbose);
info!("pgx.start");
let controller = Controller::new().await?;
match cli.command {
cli::Commands::Init => controller.init_project().await?,
@@ -33,7 +33,5 @@ async fn main() -> Result<()> {
fn init_tracing(verbose: bool) {
use tracing_subscriber::{fmt, prelude::*};
tracing_subscriber::registry()
.with(fmt::layer().with_target(false).with_level(true))
.init();
tracing_subscriber::fmt::init();
}