diff --git a/Cargo.lock b/Cargo.lock index c266076..fd51258 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,6 +255,26 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "comfy-table" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b" +dependencies = [ + "crossterm", + "unicode-segmentation", + "unicode-width 0.2.2", +] + [[package]] name = "console" version = "0.16.1" @@ -274,6 +294,29 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "document-features", + "parking_lot", + "rustix", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "darling" version = "0.21.3" @@ -330,6 +373,15 @@ dependencies = [ "syn", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dyn-clone" version = "1.0.20" @@ -849,6 +901,12 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.14" @@ -1006,6 +1064,8 @@ version = "0.0.1" dependencies = [ "bollard", "clap", + "colored", + "comfy-table", "futures", "indicatif", "miette", @@ -1876,13 +1936,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.5", ] [[package]] @@ -1894,6 +1963,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows-targets" version = "0.53.5" @@ -1901,58 +1986,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.1" diff --git a/Cargo.toml b/Cargo.toml index fa22ff0..202e538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ license = "MIT" [dependencies] bollard = "0.19.4" clap = { version = "4.5.53", features = ["derive"] } +colored = "3.0.0" +comfy-table = "7.2.1" futures = "0.3.31" indicatif = { version = "0.18.3", features = ["improved_unicode"] } miette = { version = "7.6.0", features = ["fancy"] } diff --git a/pgd.toml b/pgd.toml index 4f77f88..4f99abe 100644 --- a/pgd.toml +++ b/pgd.toml @@ -1,3 +1,3 @@ version = "18.1" -password = "GypnQVF1uV23DWvp" +password = "a7BASi7P3gCgc0Xx" port = 5433 diff --git a/pgx.toml b/pgx.toml deleted file mode 100644 index 5241e11..0000000 --- a/pgx.toml +++ /dev/null @@ -1,3 +0,0 @@ -version = "18.1" -password = "P8t42UQ53iIza2Ic" -port = 5432 diff --git a/src/controller.rs b/src/controller.rs index 8a60401..a2d89e9 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -1,5 +1,9 @@ +use std::time::Duration; + use miette::{bail, miette}; +use colored::Colorize; +use comfy_table::{Attribute, Cell, Color, ContentArrangement, Table, presets::UTF8_FULL}; use miette::Result; use crate::{ @@ -12,7 +16,7 @@ mod docker; mod utils; const MAX_RETRIES: u32 = 10; -const VERIFY_DURATION_SECS: u64 = 10; +const VERIFY_DURATION_SECS: u64 = 5; pub struct Controller { docker: DockerController, @@ -35,7 +39,7 @@ impl Controller { return self.reconcile(project).await; } - println!("Initializing new pgd project..."); + println!("{}", "Initializing new pgd project...".cyan()); let mut versions = self.docker.available_versions().await?; versions.sort(); @@ -50,15 +54,48 @@ impl Controller { }; let project = Project::new(config)?; - println!("Created pgd.toml in {}", project.path.display()); - println!(" Project: {}", project.name); - println!(" PostgreSQL version: {}", project.config.version); - println!(" Port: {}", project.config.port); - println!(" Password: {}", "*".repeat(project.config.password.len())); + println!( + "\n{} {}\n", + "Created pgd.toml in", + project.path.display().to_string().bright_white().bold() + ); + + let mut table = Table::new(); + table + .load_preset(UTF8_FULL) + .set_content_arrangement(ContentArrangement::Dynamic) + .set_style(comfy_table::TableComponent::MiddleIntersections, ' ') + .set_header(vec![ + Cell::new("Instance Configuration").add_attribute(Attribute::Bold), + ]); + + use comfy_table::TableComponent::*; + table.set_style(TopLeftCorner, '╭'); + table.set_style(TopRightCorner, '╮'); + table.set_style(BottomLeftCorner, '╰'); + table.set_style(BottomRightCorner, '╯'); + table.add_row(vec![ + Cell::new("Project").fg(Color::White), + Cell::new(&project.name).add_attribute(Attribute::Bold), + ]); + table.add_row(vec![ + Cell::new("PostgreSQL Version").fg(Color::White), + Cell::new(project.config.version.to_string()).add_attribute(Attribute::Bold), + ]); + table.add_row(vec![ + Cell::new("Port").fg(Color::White), + Cell::new(project.config.port.to_string()).add_attribute(Attribute::Bold), + ]); + table.add_row(vec![ + Cell::new("Password").fg(Color::White), + Cell::new("*".repeat(project.config.password.len())).fg(Color::DarkGrey), + ]); + + println!("{table}"); self.reconcile(&project).await?; - println!("\nProject initialized successfully!"); + println!("\n{}", "✓ Project initialized successfully!".green().bold()); Ok(()) } @@ -98,32 +135,45 @@ impl Controller { .is_container_running_by_id(&container_id) .await? { - println!("Container is already running"); + println!("{}", "Container is already running".white()); return Ok(()); } use indicatif::{ProgressBar, ProgressStyle}; let spinner = ProgressBar::new_spinner(); + spinner.enable_steady_tick(Duration::from_millis(100)); spinner.set_style( ProgressStyle::default_spinner() - .template("{spinner:.green} {msg}") + .template("{spinner:.cyan} {msg}") .unwrap(), ); spinner.set_message("Starting container..."); for attempt in 1..=MAX_RETRIES { - spinner.set_message(format!("Starting container (attempt {}/{})", attempt, MAX_RETRIES)); + spinner.set_message(format!( + "Starting container (attempt {}/{})", + attempt, MAX_RETRIES + )); let result = self.try_starting_container(&container_id, &spinner).await; match result { Ok(_) => { - spinner.finish_with_message("Container started successfully"); + spinner.finish_with_message(format!( + "{}", + "Container started successfully".green().bold() + )); return Ok(()); } Err(err) => { - spinner.set_message(format!("Attempt {}/{} failed: {}", attempt, MAX_RETRIES, err)); + spinner.set_message(format!( + "{} {}/{} failed: {}", + "Attempt".yellow(), + attempt, + MAX_RETRIES, + err + )); } } @@ -132,7 +182,7 @@ impl Controller { } } - spinner.finish_with_message("Failed to start container"); + spinner.finish_with_message(format!("{}", "Failed to start container".red())); miette::bail!("Failed to start container after {} attempts", MAX_RETRIES) } @@ -144,18 +194,19 @@ impl Controller { match self.docker.start_container_by_id(container_id).await { Ok(_) => { spinner.set_message(format!( - "Verifying container is running ({}s)...", + "{} ({}s)...", + "Verifying container is running".cyan(), VERIFY_DURATION_SECS )); for i in 0..VERIFY_DURATION_SECS { spinner.set_message(format!( - "Verifying container stability ({}/{}s)", + "{} ({}/{}s)", + "Verifying container stability".cyan(), i + 1, VERIFY_DURATION_SECS )); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - spinner.tick(); } if self.docker.is_container_running_by_id(container_id).await? { @@ -175,7 +226,11 @@ impl Controller { project: &Project, state: &mut StateManager, ) -> Result { - println!("Creating container {}...", project.container_name()); + println!( + "{} {}", + "Creating container".cyan(), + project.container_name().yellow() + ); let id = self .docker .create_postgres_container( @@ -185,7 +240,7 @@ impl Controller { project.config.port, ) .await?; - println!("Container created successfully"); + println!("{}", "Container created successfully".green()); state.set( project.name.clone(), crate::state::InstanceState::new( diff --git a/src/controller/docker.rs b/src/controller/docker.rs index 3378dea..3462ace 100644 --- a/src/controller/docker.rs +++ b/src/controller/docker.rs @@ -9,6 +9,7 @@ use bollard::{ }, secret::ContainerCreateBody, }; +use colored::Colorize; use indicatif::MultiProgress; use miette::{Context, IntoDiagnostic, Result}; use tracing::info; @@ -58,11 +59,11 @@ impl DockerController { let multi = MultiProgress::new(); - println!("Downloading {image}"); + println!("{} {}", "Downloading".cyan(), image.yellow()); download::perform_download(multi, download_progress).await?; - println!("Download complete!"); + println!("{}", "Download complete!".green().bold()); Ok(()) }