pacwoman/src/main.rs

187 lines
6.2 KiB
Rust
Raw Normal View History

2025-03-10 19:31:06 -05:00
//! An alternate client for the arch linux package repositories. Stores files in a
//! separate directory from everything else and keeps everything hashed.
2025-03-09 20:26:05 -05:00
#![warn(
missing_docs,
clippy::missing_docs_in_private_items,
clippy::empty_docs
)]
2025-03-10 19:31:06 -05:00
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<String>,
/// Download and install one or more packages. This WILL NOT update the repositories if needed!
#[arg(id = "packages to sync", short = 'S')]
sync: Vec<String>,
/// 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<String>,
/// Sync repository indexes from mirrors.
#[arg(id = "repositories to sync", short = 'Y')]
sync_repos: Vec<String>,
}
/// Default mirrorlist configuration.
const DEFAULT_MIRRORLIST: &[u8] = include_bytes!("default_mirrorlist");
fn main() -> std::io::Result<()> {
2025-03-10 19:31:06 -05:00
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<pacwoman::Mirror> = 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(())
2025-03-09 20:26:05 -05:00
}