use crate::args::i18n;
fn is_official_package_search(package_name: &str) -> bool {
use std::process::{Command, Stdio};
match Command::new("pacman")
.args(["-Ss", package_name])
.stdin(Stdio::null())
.output()
{
Ok(output) => {
if !output.status.success() {
return false;
}
let output_str = String::from_utf8_lossy(&output.stdout);
output_str.lines().any(|line| {
line.split_whitespace().next().is_some_and(|pkg_line| {
let pkg_part = pkg_line.split('/').next_back().unwrap_or(pkg_line);
pkg_part == package_name
})
})
}
Err(_) => false,
}
}
fn is_official_package(package_name: &str) -> bool {
use std::process::{Command, Stdio};
match Command::new("pacman")
.args(["-Si", package_name])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.output()
{
Ok(output) => output.status.success(),
Err(_) => false,
}
}
fn is_aur_package_search(package_name: &str, helper: &str) -> bool {
use std::process::{Command, Stdio};
match Command::new(helper)
.args(["-Ss", package_name])
.stdin(Stdio::null())
.output()
{
Ok(output) => {
if !output.status.success() {
return false;
}
let output_str = String::from_utf8_lossy(&output.stdout);
output_str.lines().any(|line| {
line.split_whitespace().next().is_some_and(|pkg_line| {
let pkg_part = pkg_line.split('/').next_back().unwrap_or(pkg_line);
pkg_part == package_name
})
})
}
Err(_) => false,
}
}
fn is_aur_package(package_name: &str, helper: &str) -> bool {
use std::process::{Command, Stdio};
match Command::new(helper)
.args(["-Si", package_name])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.output()
{
Ok(output) => output.status.success(),
Err(_) => false,
}
}
pub fn validate_and_categorize_packages(
package_names: &[String],
aur_helper: Option<&str>,
) -> (Vec<String>, Vec<String>, Vec<String>) {
let mut official_packages = Vec::new();
let mut aur_packages = Vec::new();
let mut invalid_packages = Vec::new();
for pkg in package_names {
if is_official_package(pkg) {
official_packages.push(pkg.clone());
} else if let Some(helper) = aur_helper {
if is_aur_package(pkg, helper) {
aur_packages.push(pkg.clone());
} else {
invalid_packages.push(pkg.clone());
}
} else {
invalid_packages.push(pkg.clone());
}
}
(official_packages, aur_packages, invalid_packages)
}
pub fn validate_and_categorize_packages_search(
package_names: &[String],
aur_helper: Option<&str>,
) -> (Vec<String>, Vec<String>, Vec<String>) {
let mut official_packages = Vec::new();
let mut aur_packages = Vec::new();
let mut invalid_packages = Vec::new();
for pkg in package_names {
if is_official_package_search(pkg) {
official_packages.push(pkg.clone());
} else if let Some(helper) = aur_helper {
if is_aur_package_search(pkg, helper) {
aur_packages.push(pkg.clone());
} else {
invalid_packages.push(pkg.clone());
}
} else {
invalid_packages.push(pkg.clone());
}
}
(official_packages, aur_packages, invalid_packages)
}
pub fn handle_invalid_packages(
invalid_packages: &[String],
aur_helper: Option<&str>,
official_packages: &[String],
aur_packages: &[String],
) -> bool {
use crate::args::utils;
if invalid_packages.is_empty() {
return true;
}
eprintln!("\n{}", i18n::t("app.cli.package.packages_not_found"));
for pkg in invalid_packages {
eprintln!(" - {pkg}");
}
if aur_helper.is_none() && !invalid_packages.is_empty() {
eprintln!("\n{}", i18n::t("app.cli.package.no_aur_helper_note"));
eprintln!("{}", i18n::t("app.cli.package.install_aur_helper"));
}
eprintln!();
if official_packages.is_empty() && aur_packages.is_empty() {
eprintln!("{}", i18n::t("app.cli.package.no_valid_packages"));
tracing::error!("All packages are invalid");
std::process::exit(1);
}
utils::prompt_user("Do you want to continue installing the remaining packages?")
}