Complete Rust toolkit for Arch Linux package management. Provides a unified API for interacting with Arch Linux package management, including AUR (Arch User Repository) operations, dependency resolution, package index queries, installation command building, news feeds, and security advisories.
-
AUR Operations (
aurfeature, enabled by default)- Package search via AUR RPC v5
- Detailed package information retrieval
- Package comments fetching and parsing
- PKGBUILD content retrieval
- Automatic rate limiting with exponential backoff
- Configurable retry policies with per-operation control
- Optional caching layer (memory and disk)
-
Dependency Management (
depsfeature)- Parse dependencies from PKGBUILD files (single-line and multi-line arrays)
- Parse dependencies from .SRCINFO files
- Parse dependency specifications with version constraints
- Parse pacman output for dependencies and conflicts
- Fetch .SRCINFO from AUR (requires
aurfeature) - Dependency resolution for official, AUR, and local packages
- Reverse dependency analysis for safe package removal
- Version comparison using pacman-compatible algorithm
- Package querying (installed, upgradable, versions)
- Source determination (official, AUR, local)
-
Package Index Queries (
indexfeature)- Installed package queries (
pacman -Qq) with optional caching - Explicit package tracking (all explicit or leaf-only packages)
- Official repository search (substring and optional fuzzy matching)
- Official index fetching (from
pacman -Slor the Arch Packages API) - Index persistence (save/load the official index as JSON)
- Sync and async APIs (async via
tokio::spawn_blocking)
- Installed package queries (
-
Install Command Building (
installfeature)- Pacman install/remove/update command construction (build, never execute)
- AUR helper commands with paru/yay detection and preference
- Privilege tool detection (sudo/doas) and command wrapping
- Batch planning: split mixed target lists between pacman and an AUR helper
- Removal cascade modes (
-R,-Rs,-Rns) - Strict package-name validation and POSIX shell quoting
-
News & Security Advisories (
newsfeature)- Arch Linux news RSS fetching with date normalization
- Security advisory Atom feed with severity and package extraction
- Pure parse functions (testable offline against recorded feeds)
- Cutoff-date filtering for incremental fetches
-
Build-Preflight Analysis (
sandboxfeature)- Compare a PKGBUILD/.SRCINFO's dependencies against the host
- Per-category deltas (depends, makedepends, checkdepends, optdepends)
- Installed-version and version-constraint checking
- Missing-package and ready-to-build reporting
Add arch-toolkit to your Cargo.toml:
[dependencies]
arch-toolkit = "0.2"aur(default): AUR search, package info, comments, and PKGBUILD fetchingdeps: Dependency parsing from PKGBUILD, .SRCINFO, and pacman outputindex: Package database queries (installed, explicit, official repositories) and index persistenceinstall: Installation command building (pacman, AUR helpers, batch planning; enablesdeps)news: Arch news RSS and security advisoriessandbox: Build-preflight dependency analysis (enablesdeps)fuzzy-search: Fuzzy matching for official index search (used withindex)cache-disk: Enable disk-based caching for persistence across restarts
To disable default features:
arch-toolkit = { version = "0.2", default-features = false, features = ["aur"] }To enable dependency parsing:
arch-toolkit = { version = "0.2", features = ["deps"] }To enable disk caching:
arch-toolkit = { version = "0.2", features = ["cache-disk"] }To enable package index queries:
arch-toolkit = { version = "0.2", features = ["index"] }use arch_toolkit::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Create a client with default settings
let client = ArchClient::new()?;
// Search for packages
let packages = client.aur().search("yay").await?;
println!("Found {} packages", packages.len());
// Get detailed package information
let details = client.aur().info(&["yay", "paru"]).await?;
for pkg in details {
println!("{}: {}", pkg.name, pkg.description);
}
Ok(())
}use arch_toolkit::ArchClient;
use std::time::Duration;
let client = ArchClient::builder()
.timeout(Duration::from_secs(60))
.user_agent("my-app/1.0")
.max_retries(5)
.build()?;Or configure via environment variables (perfect for CI/CD):
export ARCH_TOOLKIT_TIMEOUT=60
export ARCH_TOOLKIT_USER_AGENT="my-app/1.0"
export ARCH_TOOLKIT_MAX_RETRIES=5let client = ArchClient::builder()
.from_env() // Load configuration from environment
.build()?;use arch_toolkit::ArchClient;
use arch_toolkit::client::RetryPolicy;
let retry_policy = RetryPolicy {
max_retries: 5,
initial_delay_ms: 2000,
max_delay_ms: 60_000,
jitter_max_ms: 1000,
enabled: true,
retry_search: true,
retry_info: true,
retry_comments: true,
retry_pkgbuild: false,
};
let client = ArchClient::builder()
.retry_policy(retry_policy)
.build()?;Enable caching to reduce network requests:
use arch_toolkit::ArchClient;
use arch_toolkit::cache::CacheConfigBuilder;
use std::time::Duration;
let cache_config = CacheConfigBuilder::new()
.enable_search(true)
.search_ttl(Duration::from_secs(300)) // 5 minutes
.enable_info(true)
.info_ttl(Duration::from_secs(900)) // 15 minutes
.enable_comments(true)
.comments_ttl(Duration::from_secs(600)) // 10 minutes
.memory_cache_size(200)
.build();
let client = ArchClient::builder()
.cache_config(cache_config)
.build()?;With disk caching (requires cache-disk feature):
let cache_config = CacheConfigBuilder::new()
.enable_search(true)
.search_ttl(Duration::from_secs(300))
.enable_disk_cache(true) // Persist across restarts
.build();let comments = client.aur().comments("yay").await?;
for comment in comments.iter().take(5) {
println!("{}: {}", comment.author, comment.content);
}let pkgbuild = client.aur().pkgbuild("yay").await?;
println!("PKGBUILD:\n{}", pkgbuild);Parse dependencies from PKGBUILD or .SRCINFO files:
use arch_toolkit::deps::{parse_pkgbuild_deps, parse_srcinfo_deps};
// Parse PKGBUILD
let pkgbuild = r"depends=('glibc' 'python>=3.10')";
let (depends, makedepends, checkdepends, optdepends) = parse_pkgbuild_deps(pkgbuild);
// Parse .SRCINFO
let srcinfo = r"depends = glibc\ndepends = python>=3.10";
let (depends, makedepends, checkdepends, optdepends) = parse_srcinfo_deps(srcinfo);Resolve dependencies for packages:
use arch_toolkit::deps::{DependencyResolver, PackageRef, PackageSource};
let resolver = DependencyResolver::new();
let packages = vec![
PackageRef {
name: "firefox".into(),
version: "121.0".into(),
source: PackageSource::Official {
repo: "extra".into(),
arch: "x86_64".into(),
},
},
];
let result = resolver.resolve(&packages)?;
println!("Found {} dependencies", result.dependencies.len());
for dep in result.dependencies {
println!(" {}: {:?}", dep.name, dep.status);
}Find all packages that depend on packages being removed:
use arch_toolkit::deps::{ReverseDependencyAnalyzer, PackageRef, PackageSource};
let analyzer = ReverseDependencyAnalyzer::new();
let packages = vec![
PackageRef {
name: "qt5-base".into(),
version: "5.15.10".into(),
source: PackageSource::Official {
repo: "extra".into(),
arch: "x86_64".into(),
},
},
];
let report = analyzer.analyze(&packages)?;
println!("{} packages would be affected", report.dependents.len());Compare package versions:
use arch_toolkit::deps::{compare_versions, version_satisfies};
// Compare versions
use std::cmp::Ordering;
assert_eq!(compare_versions("1.2.3", "1.2.4"), Ordering::Less);
// Check if version satisfies requirement
assert!(version_satisfies("2.0", ">=1.5"));
assert!(!version_satisfies("1.0", ">=1.5"));Query installed and upgradable packages:
use arch_toolkit::deps::{
get_installed_packages, get_upgradable_packages,
get_installed_version, get_available_version,
};
// Get installed packages
let installed = get_installed_packages()?;
println!("Found {} installed packages", installed.len());
// Get upgradable packages
let upgradable = get_upgradable_packages()?;
println!("Found {} upgradable packages", upgradable.len());
// Get installed version
if let Ok(version) = get_installed_version("pacman") {
println!("Installed pacman version: {}", version);
}
// Get available version
if let Some(version) = get_available_version("pacman") {
println!("Available pacman version: {}", version);
}Determine where a package comes from:
use arch_toolkit::deps::{determine_dependency_source, is_system_package};
use std::collections::HashSet;
let installed = get_installed_packages()?;
let (source, is_core) = determine_dependency_source("glibc", &installed);
println!("Source: {:?}, Is core: {}", source, is_core);
if is_system_package("glibc") {
println!("glibc is a critical system package");
}Query installed packages and search official repositories (requires index feature):
use arch_toolkit::index::{
fetch_official_index, get_installed_packages, is_installed, load_from_disk, save_to_disk,
search_official,
};
use std::path::Path;
// Query installed packages
let installed = get_installed_packages()?;
if is_installed("vim", Some(&installed)) {
println!("vim is installed");
}
// Load a cached official index, falling back to a fresh fetch
let path = Path::new("official_index.json");
let index = load_from_disk(path).or_else(|_| fetch_official_index())?;
// Search the official index
for result in search_official(&index, "ripgrep", false) {
println!("{}/{} {}", result.package.repo, result.package.name, result.package.version);
}
// Persist the index for the next session
save_to_disk(&index, path)?;Build (never execute) pacman and AUR helper commands (requires install feature):
use arch_toolkit::install::{
build_batch_install, build_remove_command, detect_aur_helper, detect_privilege_tool,
with_privilege,
};
use arch_toolkit::types::install::{CascadeMode, InstallOptions};
use arch_toolkit::PackageRef;
// Plan a mixed batch: official packages via pacman, AUR packages via paru/yay
let targets = vec![
PackageRef::official("ripgrep", "14.0.0", "extra", "x86_64"),
PackageRef::aur("yay-bin", "12.0.0"),
];
let plan = build_batch_install(
&targets,
detect_aur_helper(),
detect_privilege_tool(),
&InstallOptions::default(),
None::<&std::collections::HashSet<String>>,
)?;
for command in &plan.commands {
println!("Would run: {command}"); // dry run = display, not execute
// command.to_command().status()?; // or actually run it (argv, no shell)
}
// Removal with cascade control
let remove = with_privilege(
detect_privilege_tool().expect("sudo or doas required"),
build_remove_command(&["old-package"], CascadeMode::CascadeWithConfigs, true)?,
);
println!("{remove}"); // sudo pacman -Rns --noconfirm old-packageFetch Arch news and advisories (requires news feature):
use arch_toolkit::news::{fetch_arch_news, fetch_security_advisories};
let client = reqwest::Client::new();
// Latest news, dates normalized to YYYY-MM-DD
for item in fetch_arch_news(&client, 10, None).await? {
println!("{} {}", item.date, item.title);
}
// Advisories since a date, with severity and affected packages
for advisory in fetch_security_advisories(&client, 20, Some("2026-01-01")).await? {
println!("{} [{}] {:?}", advisory.date, advisory.severity, advisory.packages);
}Check what an AUR package would need before building (requires sandbox feature):
use arch_toolkit::deps::{get_installed_packages, get_provided_packages};
use arch_toolkit::sandbox::analyze_pkgbuild;
let installed = get_installed_packages().unwrap_or_default();
let provided = get_provided_packages(&installed);
let info = analyze_pkgbuild("my-package", &pkgbuild_text, &installed, &provided);
if !info.is_ready_to_build() {
println!("Missing build deps: {:?}", info.missing_packages());
}Monitor AUR service status:
// Quick health check
let is_healthy = client.health_check().await?;
// Detailed status with latency
let status = client.health_status().await?;
println!("Status: {:?}, Latency: {:?}", status.status, status.latency);See the examples/ directory for comprehensive examples:
examples/aur_example.rs: Complete AUR operations demonstrationexamples/with_caching.rs: Caching layer usageexamples/env_config.rs: Environment variable configurationexamples/health_check.rs: Health check functionalityexamples/pkgbuild_example.rs: PKGBUILD dependency parsingexamples/srcinfo_example.rs: .SRCINFO parsing and fetchingexamples/deps_example.rs: Comprehensive dependency module examplesexamples/parse_example.rs: Dependency specification parsingexamples/query_example.rs: Package querying examplesexamples/resolve_example.rs: Dependency resolution examplesexamples/reverse_example.rs: Reverse dependency analysis examplesexamples/source_example.rs: Source determination examplesexamples/version_example.rs: Version comparison examplesexamples/index_example.rs: Package index queries and persistence examplesexamples/install_example.rs: Install command building and batch planning examplesexamples/news_example.rs: Arch news and security advisory examplesexamples/sandbox_example.rs: Build-preflight dependency analysis examples
Run examples with:
cargo run --example aur_example
cargo run --example with_caching
cargo run --example env_config
cargo run --example health_check
cargo run --example pkgbuild_example --features deps
cargo run --example srcinfo_example --features deps
cargo run --example deps_example --features deps
cargo run --example parse_example --features deps
cargo run --example query_example --features deps
cargo run --example resolve_example --features deps
cargo run --example reverse_example --features deps
cargo run --example source_example --features deps
cargo run --example version_example --features deps
cargo run --example index_example --features index
cargo run --example install_example --features install
cargo run --example news_example --features news
cargo run --example sandbox_example --features sandboxFull API documentation is available at docs.rs/arch-toolkit or build locally:
cargo doc --openarch-toolkit automatically implements rate limiting for archlinux.org requests:
- Minimum 200ms delay between requests
- Exponential backoff on failures
- Serialized requests (one at a time) to prevent overwhelming the server
- Configurable retry policies
All operations return Result<T, ArchToolkitError>. Common error types:
ArchToolkitError::Network: HTTP request failuresArchToolkitError::Parse: JSON/HTML parsing errorsArchToolkitError::InvalidInput: Invalid parameters or URLsArchToolkitError::Timeout: Request timeoutArchToolkitError::EmptyInput: Empty input provided (with input validation)ArchToolkitError::InvalidPackageName: Invalid package name format
Input validation is enabled by default and validates package names and search queries against Arch Linux standards.
- Rust 1.91 or later (edition 2024,
Duration::from_mins) - Tokio runtime (for async operations)
MIT