//! An alternate client for the arch linux package repositories. Stores files in a //! separate directory from everything else and keeps everything hashed. #![warn( missing_docs, clippy::missing_docs_in_private_items, clippy::empty_docs )] use clap::Parser; /// Parser for command line arguments #[derive(Parser)] #[command(version, about, long_about = None, name = "pacwoman")] struct Cli { /// Whether to operate as a user or not. In most cases, running as system will /// require running as root. #[arg(short, long, default_value_t = false)] user: bool, /// Initalize the GPG keyring and create skeleton directories. This will also add /// a default configuration for the mirrors. #[arg(long, default_value_t = false)] initalize: bool, /// Download one or more packages. This WILL NOT install them to your bin directory! #[arg(id = "packages to download", short = 'D')] download: Vec, /// Download and install one or more packages. This WILL NOT update the repositories if needed! #[arg(id = "packages to sync", short = 'S')] sync: Vec, /// Remove a package. Because I'm lazy, this will only remove the store entry, leaving a bunch /// of dangling symlinks. #[arg(id = "packages to remove", short = 'R')] remove: Vec, /// Sync repository indexes from mirrors. #[arg(id = "repositories to sync", short = 'Y')] sync_repos: Vec, } /// Default mirrorlist configuration. const DEFAULT_MIRRORLIST: &[u8] = include_bytes!("default_mirrorlist"); fn main() -> std::io::Result<()> { let args = Cli::parse(); if args.initalize { pacwoman::create_directories(!args.user)?; pacwoman::init_gpg()?; std::fs::write( pacwoman::config_directory(!args.user)?.join("mirrors"), DEFAULT_MIRRORLIST, )?; } let regex = regex::Regex::new(r"(?m)#.*$").unwrap(); let mirrors: Vec = regex .replace_all( &(std::fs::read_to_string(pacwoman::config_directory(!args.user)?.join("mirrors"))?), "", ) .split("\n") .filter(|item| item.trim() != "") .map(|item| pacwoman::Mirror::new(url::Url::parse(item).unwrap())) .collect(); if !args.sync_repos.is_empty() { for repo in &args.sync_repos { let mut ok = false; for mirror in &mirrors { if pacwoman::populate_index( mirror.clone(), pacwoman::RepoDescriptor::new() .set_repo(repo.clone()) .set_arch(std::env::consts::ARCH.to_string()) .clone(), ).is_ok() { ok = true; break; } } if !ok { println!(" [ERR] Cannot download repo {repo}!"); println!(" [TIP] Check the spelling and your mirrors."); drop(mirrors); drop(args); std::process::exit(1); } } } if !args.download.is_empty() { for package in &args.download { let results = pacwoman::locate_package(package.clone())?; if results.is_empty() { println!(" [ERR] Cannot locate packages for {package}!"); println!(" [TIP] Try adding a repository to the index."); drop(mirrors); drop(args); std::process::exit(1); } for result in results { let mut ok = false; for mirror in &mirrors { if pacwoman::recieve_package_and_dependencies( mirror.clone(), result.1.clone(), result.0.clone(), !args.user, ) .is_ok() { ok = true; break; } } if !ok { println!(" [ERR] Cannot download package {}!", result.0); println!(" [TIP] Check the spelling and try syncing repos."); drop(mirrors); drop(args); std::process::exit(1); } } } } if !args.sync.is_empty() { for package in &args.sync { let results = pacwoman::locate_package(package.clone())?; if results.is_empty() { println!(" [ERR] Cannot locate packages for {package}!"); println!(" [TIP] Try adding a repository to the index."); drop(mirrors); drop(args); std::process::exit(1); } for result in results { let mut ok = false; for mirror in &mirrors { if pacwoman::install_package( mirror.clone(), result.1.clone(), result.0.clone(), !args.user, ) .is_ok() { ok = true; break; } } if !ok { println!(" [ERR] Cannot sync package {}!", result.0); println!(" [TIP] Check the spelling and try syncing repos."); drop(mirrors); drop(args); std::process::exit(1); } } } } if !args.remove.is_empty() { for package in &args.remove { let results = pacwoman::locate_package(package.clone())?; if results.is_empty() { println!(" [ERR] Cannot locate packages for {package}!"); println!(" [TIP] Try adding a repository to the index."); drop(mirrors); drop(args); std::process::exit(1); } for result in results { pacwoman::remove_package(result.0, !args.user, result.1)?; } } } Ok(()) }