From dfdfad0217e731592139d52a5b41c591fb2369dd Mon Sep 17 00:00:00 2001 From: rzmk <30333942+rzmk@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:03:16 -0400 Subject: [PATCH] feat: add clap for CLI and consolidate styles --- Cargo.lock | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 80 +++++++++++++++++++++------------ 3 files changed, 179 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0526a69..b9355a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,56 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + [[package]] name = "anyhow" version = "1.0.99" @@ -43,6 +93,7 @@ name = "ckan-devstaller" version = "0.1.0" dependencies = [ "anyhow", + "clap", "inquire", "owo-colors", "rust-ini", @@ -51,6 +102,52 @@ dependencies = [ "xshell-venv", ] +[[package]] +name = "clap" +version = "4.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "const-random" version = "0.1.18" @@ -173,6 +270,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -213,6 +316,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.15" @@ -280,6 +389,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -453,6 +568,12 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "supports-color" version = "2.1.0" @@ -519,6 +640,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index a56107b..b16f6de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] anyhow = "1.0.99" +clap = { version = "4.5.45", features = ["derive"] } inquire = "0.7.5" owo-colors = { version = "4.2.2", features = ["supports-colors"] } rust-ini = "0.21.2" diff --git a/src/main.rs b/src/main.rs index 99711cc..ea1dde2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,65 @@ use anyhow::Result; +use clap::Parser; use inquire::Confirm; -use owo_colors::{OwoColorize, Stream::Stdout}; +use owo_colors::{OwoColorize, Stream::Stdout, Style}; use serde_json::json; use std::{path::PathBuf, str::FromStr}; use xshell::cmd; use xshell_venv::{Shell, VirtualEnv}; +/// ckan-devstaller CLI +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// Skip interactive steps and install CKAN with default features + #[arg(short, long)] + default: bool, +} + fn main() -> Result<()> { + let args = Args::parse(); + + // Color styles + let highlight_style = Style::new().on_blue().white(); + let important_style = Style::new().on_bright_red().white(); + let step_style = Style::new().on_magenta().white(); + let success_style = Style::new().on_green().white(); + println!("Welcome to the ckan-devstaller!"); println!( "ckan-devstaller is provided by datHere - {}\n", - "https://datHere.com".if_supports_color(Stdout, |text| text.on_blue().white()), + "https://datHere.com".if_supports_color(Stdout, |t| t.style(highlight_style)), ); println!( "This installer should assist in setting up {} from a source installation along with ckan-compose (https://github.com/tino097/ckan-compose). If you have any issues, please report them at https://github.com/dathere/ckan-devstaller/issues.", - "CKAN 2.11.3".if_supports_color(Stdout, |text| text.on_blue().white()) + "CKAN 2.11.3".if_supports_color(Stdout, |t| t.style(highlight_style)) ); println!( "{}", "This installer is only intended for a brand new installation of Ubuntu 22.04." - .if_supports_color(Stdout, |text| text.on_bright_red().white()) + .if_supports_color(Stdout, |t| t.style(important_style)) ); - let ans = Confirm::new("Would you like to begin the installation?") - .with_default(false) - .prompt()?; + + let ans = if args.default { + true + } else { + Confirm::new("Would you like to begin the installation?") + .with_default(false) + .prompt()? + }; if ans { let sh = Shell::new()?; println!( "\n{} Running {} and {}...", - "1.".if_supports_color(Stdout, |text| text.on_magenta().white()), - "sudo apt update -y".if_supports_color(Stdout, |text| text.on_blue().white()), - "sudo apt upgrade -y".if_supports_color(Stdout, |text| text.on_blue().white()) + "1.".if_supports_color(Stdout, |t| t.style(step_style)), + "sudo apt update -y".if_supports_color(Stdout, |t| t.style(highlight_style)), + "sudo apt upgrade -y".if_supports_color(Stdout, |t| t.style(highlight_style)) ); println!( "{}", "You may need to provide your sudo password." - .if_supports_color(Stdout, |text| text.on_bright_red().white()) + .if_supports_color(Stdout, |t| t.style(important_style)) ); cmd!(sh, "sudo apt update -y").run()?; // Ignoring xrdp error with .ignore_status() for now @@ -44,18 +67,18 @@ fn main() -> Result<()> { println!( "{}", "✅ 1. Successfully ran update and upgrade commands." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{} Installing curl and enabling SSH...", - "2.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "2.".if_supports_color(Stdout, |t| t.style(step_style)), ); cmd!(sh, "sudo apt install curl openssh-server -y").run()?; println!( "{}", "✅ 2. Successfully installed curl and enabled SSH." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); let username = cmd!(sh, "whoami").read()?; @@ -69,7 +92,7 @@ fn main() -> Result<()> { if !has_docker { println!( "{} Installing Docker...", - "3.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "3.".if_supports_color(Stdout, |t| t.style(step_style)), ); cmd!( sh, @@ -80,7 +103,7 @@ fn main() -> Result<()> { println!( "{}", "✅ 3. Successfully installed Docker." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); } @@ -96,7 +119,7 @@ fn main() -> Result<()> { println!( "\n{} Installing Ahoy...", - "4.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "4.".if_supports_color(Stdout, |t| t.style(step_style)), ); cmd!(sh, "sudo curl -LO https://github.com/ahoy-cli/ahoy/releases/download/v2.5.0/ahoy-bin-linux-amd64").run()?; cmd!(sh, "mv ./ahoy-bin-linux-amd64 ./ahoy").run()?; @@ -104,12 +127,12 @@ fn main() -> Result<()> { println!( "{}", "✅ 4. Successfully installed Ahoy." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{} Downloading, installing, and starting ckan-compose...", - "5.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "5.".if_supports_color(Stdout, |t| t.style(step_style)), ); sh.change_dir(format!("/home/{username}")); if !std::fs::exists(format!("/home/{username}/ckan-compose"))? { @@ -125,12 +148,12 @@ POSTGRES_PASSWORD=pass"; println!( "{}", "✅ 5. Successfully ran ckan-compose." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{} Installing CKAN 2.11.3...", - "6.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "6.".if_supports_color(Stdout, |t| t.style(step_style)), ); cmd!(sh, "sudo apt install python3-dev libpq-dev python3-pip python3-venv git-core redis-server -y").run()?; cmd!(sh, "sudo mkdir -p /usr/lib/ckan/default").run()?; @@ -170,12 +193,12 @@ POSTGRES_PASSWORD=pass"; println!( "{}", "✅ 6. Installed CKAN 2.11.3 and started running instance." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{} Enabling DataStore plugin, adding config URLs in /etc/ckan/default/ckan.ini and updating permissions...", - "7.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "7.".if_supports_color(Stdout, |t| t.style(step_style)), ); // TODO: use the ckan config-tool command instead of rust-ini let mut conf = ini::Ini::load_from_file("/etc/ckan/default/ckan.ini")?; @@ -220,12 +243,12 @@ POSTGRES_PASSWORD=pass"; println!( "{}", "✅ 7. Enabled DataStore plugin, set DataStore URLs in /etc/ckan/default/ckan.ini, and updated permissions." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{} Installing ckanext-scheming and DataPusher+ extensions...", - "8.".if_supports_color(Stdout, |text| text.on_magenta().white()), + "8.".if_supports_color(Stdout, |t| t.style(step_style)), ); cmd!( sh, @@ -357,13 +380,12 @@ ckanext.datapusher_plus.enable_form_redirect = true println!( "{}", "✅ 8. Installed ckanext-scheming and DataPusher+ extensions." - .if_supports_color(Stdout, |text| text.on_green().white()) + .if_supports_color(Stdout, |t| t.style(success_style)) ); println!( "\n{}", - "✅ 9. Running CKAN instance..." - .if_supports_color(Stdout, |text| text.on_green().white()) + "✅ 9. Running CKAN instance...".if_supports_color(Stdout, |t| t.style(success_style)) ); cmd!(sh, "ckan -c /etc/ckan/default/ckan.ini run").run()?; } @@ -381,7 +403,7 @@ fn get_config_from_prompts() -> Result { .with_help_message( format!( "This step would install {}", - "openssh-server".if_supports_color(Stdout, |text| text.on_blue().white()) + "openssh-server".if_supports_color(Stdout, |t| t.on_blue().white()) ) .as_str(), )