From b11271cf82607b86329caf4cd6a6878129c7f879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czy=C5=BC?= Date: Wed, 24 Jul 2024 18:58:11 +0200 Subject: [PATCH] package upgrade, refacror --- Cargo.toml | 2 +- src/cli.rs | 60 ++++++++++++++++++++++++++++------------- src/file.rs | 23 ++++++++++++++++ src/main.rs | 22 ++++++++++----- src/packages.rs | 38 -------------------------- src/packages/find.rs | 24 +++++++++++++++++ src/packages/install.rs | 6 +++++ src/packages/mod.rs | 34 +++++++++++++++++++++++ src/packages/rebuild.rs | 52 +++++++++++++++++++++++++++++++++++ src/packages/remove.rs | 6 +++++ src/packages/sync.rs | 48 +++++++++++++++++++++++++++++++++ src/packages/upgrade.rs | 27 +++++++++++++++++++ 12 files changed, 277 insertions(+), 65 deletions(-) create mode 100644 src/file.rs delete mode 100644 src/packages.rs create mode 100644 src/packages/find.rs create mode 100644 src/packages/install.rs create mode 100644 src/packages/mod.rs create mode 100644 src/packages/rebuild.rs create mode 100644 src/packages/remove.rs create mode 100644 src/packages/sync.rs create mode 100644 src/packages/upgrade.rs diff --git a/Cargo.toml b/Cargo.toml index f8b90ad..1d394e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] clap = { version = "4.5.10", features = ["derive"] } -colored = "2.1.0" +colored = "2.1.0" \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs index 939f33f..dce097d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,27 +1,49 @@ -use clap::{Parser, Subcommand, Args}; +use clap::{Args, Parser, Subcommand}; -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] +#[derive(Parser)] +#[command( + name = "ah", + author = "Michał Czyż", + version = "0.1.0", + about = "A declarative package manager for Arch Linux", + long_about = "Arch Helper is a declarative package management tool for Arch Linux. It leverages paru or other package managers for seamless integration.")] pub struct Cli { #[command(subcommand)] - pub command: Option, + pub command: Option, } -#[derive(Subcommand, Debug)] -pub enum SubCommands { - #[command(alias = "i")] - Install(PackageArg), - #[command(alias = "u")] - Upgrade {}, - #[command(alias = "s")] - Sync {}, - #[command(alias = "r")] - Remove(PackageArg), - #[command(alias = "f")] - Find(PackageArg), +#[derive(Subcommand)] +pub enum Commands { + #[command(about = "Install packages")] + Install(PackageList), + + #[command(about = "Upgrade packages")] + Upgrade { + #[arg(help = "Don't prompt for confirmation", default_value_t = false)] + noconfirm: bool + }, + + #[command(about = "Synchronize packages")] + Sync { + #[arg(help = "Don't prompt for confirmation", default_value_t = false)] + noconfirm: bool + }, + + #[command(about = "Remove packages")] + Remove(PackageList), + + #[command(about = "Find packages")] + Find(Query), } -#[derive(Args, Debug)] -pub struct PackageArg { - pub package: String, +#[derive(Args)] +pub struct PackageList { + #[arg(help = "Name(s) of the package(s), separated by spaces")] + pub packages: Vec, +} + +#[derive(Args)] +pub struct Query { + #[arg(help = "Search term for finding packages")] + pub query: Vec, } \ No newline at end of file diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..e4c75e1 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,23 @@ +use std::{ + fs::File, + io::{prelude::*, BufReader}, path::PathBuf, +}; + +// pub fn read_config(path: &str) -> Vec { +// todo!(); +// } + +// pub fn write_config(path: &str, content: &str) { +// todo!(); +// } + +pub fn read_packages(path: PathBuf) -> Vec { + let file = File::open(path).expect("Failed to open file"); + let buf = BufReader::new(file); + + buf.lines().map(|l| l.expect("Failed to read line")).collect() +} + +// pub fn write_packages(path: &str, content: &str) { +// todo!(); +// } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a08591f..7fe59ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,25 @@ use clap::Parser; +use cli::{PackageList, Query}; +use colored::Colorize; mod cli; mod packages; +mod file; fn main() { let cli = cli::Cli::parse(); - match cli.command { - Some(cli::SubCommands::Install(arg)) => packages::install(&arg.package), - Some(cli::SubCommands::Upgrade {}) => packages::upgrade(), - Some(cli::SubCommands::Sync {}) => packages::sync(), - Some(cli::SubCommands::Remove(arg)) => packages::remove(&arg.package), - Some(cli::SubCommands::Find(arg)) => packages::find(&arg.package), - None => packages::sync(), + let result = match cli.command { + Some(cli::Commands::Install(PackageList { packages })) => packages::install(packages), + Some(cli::Commands::Upgrade { noconfirm }) => packages::upgrade(noconfirm), + Some(cli::Commands::Sync { noconfirm }) => packages::sync(noconfirm), + Some(cli::Commands::Remove(PackageList { packages })) => packages::remove(packages), + Some(cli::Commands::Find(Query { query })) => packages::find(query), + None => packages::rebuild(true), + }; + + if let Err(err) = result { + eprintln!("{} {}", "::".bold().red(), err.to_string().bold()); + std::process::exit(1); } } diff --git a/src/packages.rs b/src/packages.rs deleted file mode 100644 index 5834ef2..0000000 --- a/src/packages.rs +++ /dev/null @@ -1,38 +0,0 @@ -use colored::Colorize; -use std::process::Command; - -const PACKAGE_MANAGER: &str = "paru"; - -pub fn sync() { - println!("{} {}", "::".bold().green(), "Syncing packages...".bold()); - todo!(); -} - -pub fn upgrade() { - println!("{} {}", "::".bold().green(), "Upgrading packages...".bold()); - todo!(); -} - -pub fn install(package: &str) { - println!("{} {}", "::".bold().green(), "Installing packages...".bold()); - todo!(); -} - -pub fn remove(package: &str) { - println!("{} {}", "::".bold().green(), "Removing packages...".bold()); - todo!(); -} - -pub fn find(package: &str) { - println!("{} {}", "::".bold().green(), "Looking for package...".bold()); - - let output = Command::new(PACKAGE_MANAGER) - .arg("--color") - .arg("always") - .arg("-Ss") - .arg(package) - .output() - .expect("Failed to execute command"); - - print!("{}", String::from_utf8_lossy(&output.stdout)); -} \ No newline at end of file diff --git a/src/packages/find.rs b/src/packages/find.rs new file mode 100644 index 0000000..4fc213b --- /dev/null +++ b/src/packages/find.rs @@ -0,0 +1,24 @@ +use colored::Colorize; +use std::process::Command; + +const PACKAGE_MANAGER: &str = "paru"; + +pub fn find(query: Vec) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Looking for package...".bold()); + + if query.is_empty() { + return Err("No query provided".into()); + } + + let output = Command::new(PACKAGE_MANAGER) + .arg("--color") + .arg("always") + .arg("-Ss") + .args(query) + .output() + .expect("Failed to execute command"); + + print!("{}", String::from_utf8_lossy(&output.stdout)); + + Ok(()) +} \ No newline at end of file diff --git a/src/packages/install.rs b/src/packages/install.rs new file mode 100644 index 0000000..9ca4d52 --- /dev/null +++ b/src/packages/install.rs @@ -0,0 +1,6 @@ +use colored::Colorize; + +pub fn install(_package: Vec) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Installing packages...".bold()); + todo!(); +} \ No newline at end of file diff --git a/src/packages/mod.rs b/src/packages/mod.rs new file mode 100644 index 0000000..af0344a --- /dev/null +++ b/src/packages/mod.rs @@ -0,0 +1,34 @@ +use colored::Colorize; +use std::path::PathBuf; +use std::io::{self, Write}; + +pub mod rebuild; +pub mod sync; +pub mod upgrade; +pub mod install; +pub mod remove; +pub mod find; + +pub use rebuild::rebuild; +pub use sync::sync; +pub use upgrade::upgrade; +pub use install::install; +pub use remove::remove; +pub use find::find; + +fn get_package_path() -> PathBuf { + let home_dir = std::env::var("HOME").unwrap(); + + PathBuf::from(home_dir).join("packages") +} + +fn ask_confirmation() -> Result { + print!("{} {}", "::".bold().blue(), "Do you want to continue? [Y/n] "); + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + + let input = input.trim().to_lowercase(); + Ok(input.is_empty() || input == "y") +} \ No newline at end of file diff --git a/src/packages/rebuild.rs b/src/packages/rebuild.rs new file mode 100644 index 0000000..e26f1fc --- /dev/null +++ b/src/packages/rebuild.rs @@ -0,0 +1,52 @@ +use colored::Colorize; +use std::process::{Command, Stdio}; +use std::io::Write; + +use crate::file; +use crate::packages::{ask_confirmation, get_package_path}; + +const PACKAGE_MANAGER: &str = "paru"; + +pub fn rebuild(noconfirm: bool) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Upgrading & syncing packages...".bold()); + + if !ask_confirmation()? { + return Err("Operation aborted".into()); + } + + let packages = file::read_packages(get_package_path()); + + let packages = packages.into_iter() + .filter(|p| !p.contains("#") && !p.is_empty()) + .collect::>(); + + let noconfirm = if noconfirm { "--noconfirm" } else { "--confirm" }; + + let mut child = Command::new(PACKAGE_MANAGER) + .arg("--color") + .arg("always") + .arg("-Syu") + .arg("--needed") + .arg(noconfirm) + .arg("-") + .stdin(Stdio::piped()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() + .expect("Failed to execute command"); + + if let Some(mut stdin) = child.stdin.take() { + for package in packages { + writeln!(stdin, "{}", package).unwrap(); + } + } + + let status = child.wait().expect("Failed to wait on child"); + + if !status.success() { + return Err("Failed to upgrade & sync packages".into()); + } + + println!("{} {}", "::".bold().green(), "Packages upgraded & synced".bold()); + Ok(()) +} diff --git a/src/packages/remove.rs b/src/packages/remove.rs new file mode 100644 index 0000000..47deffc --- /dev/null +++ b/src/packages/remove.rs @@ -0,0 +1,6 @@ +use colored::Colorize; + +pub fn remove(_package: Vec) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Removing packages...".bold()); + todo!(); +} \ No newline at end of file diff --git a/src/packages/sync.rs b/src/packages/sync.rs new file mode 100644 index 0000000..a8e0255 --- /dev/null +++ b/src/packages/sync.rs @@ -0,0 +1,48 @@ +use colored::Colorize; +use std::process::{Command, Stdio}; +use std::io::Write; + +use crate::file; +use crate::packages::get_package_path; + +const PACKAGE_MANAGER: &str = "paru"; + +pub fn sync(noconfirm: bool) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Syncing packages...".bold()); + + let packages = file::read_packages(get_package_path()); + + let packages = packages.into_iter() + .filter(|p| !p.contains("#") && !p.is_empty()) + .collect::>(); + + let noconfirm = if noconfirm { "--noconfirm" } else { "--confirm" }; + + let mut child = Command::new(PACKAGE_MANAGER) + .arg("--color") + .arg("always") + .arg("-S") + .arg("--needed") + .arg(noconfirm) + .arg("-") + .stdin(Stdio::piped()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() + .expect("Failed to execute command"); + + if let Some(mut stdin) = child.stdin.take() { + for package in packages { + writeln!(stdin, "{}", package).unwrap(); + } + } + + let status = child.wait().expect("Failed to wait on child"); + + if !status.success() { + return Err("Failed to sync packages".into()); + } + + println!("{} {}", "::".bold().green(), "Packages synced".bold()); + Ok(()) +} \ No newline at end of file diff --git a/src/packages/upgrade.rs b/src/packages/upgrade.rs new file mode 100644 index 0000000..ff1d5c8 --- /dev/null +++ b/src/packages/upgrade.rs @@ -0,0 +1,27 @@ +use colored::Colorize; +use std::process::Command; + +const PACKAGE_MANAGER: &str = "paru"; + +pub fn upgrade(noconfirm: bool) -> Result<(), Box> { + println!("{} {}", "::".bold().green(), "Upgrading packages...".bold()); + + let noconfirm = if noconfirm { "--noconfirm" } else { "--confirm" }; + + let mut child = Command::new(PACKAGE_MANAGER) + .arg("--color") + .arg("always") + .arg("-Syu") + .arg(noconfirm) + .spawn() + .expect("Failed to execute command"); + + let status = child.wait().expect("Failed to wait on child"); + + if !status.success() { + return Err("Failed to upgrade packages".into()); + } + + println!("{} {}", "::".bold().green(), "Packages upgraded".bold()); + Ok(()) +} \ No newline at end of file