use crate::logic::sandbox::parse::parse_pkgbuild_deps;
use crate::logic::sandbox::parse::parse_srcinfo_deps;
use crate::logic::sandbox::types::{DependencyDelta, SandboxInfo};
use std::collections::HashSet;
use std::process::{Command, Stdio};
pub(super) fn analyze_package_from_srcinfo(
package_name: &str,
srcinfo_text: &str,
installed: &HashSet<String>,
provided: &HashSet<String>,
) -> SandboxInfo {
let (depends, makedepends, checkdepends, optdepends) = parse_srcinfo_deps(srcinfo_text);
let depends_delta = analyze_dependencies(&depends, installed, provided);
let makedepends_delta = analyze_dependencies(&makedepends, installed, provided);
let checkdepends_delta = analyze_dependencies(&checkdepends, installed, provided);
let optdepends_delta = analyze_dependencies(&optdepends, installed, provided);
SandboxInfo {
package_name: package_name.to_string(),
depends: depends_delta,
makedepends: makedepends_delta,
checkdepends: checkdepends_delta,
optdepends: optdepends_delta,
}
}
pub(super) fn analyze_package_from_pkgbuild(
package_name: &str,
pkgbuild_text: &str,
installed: &HashSet<String>,
provided: &HashSet<String>,
) -> SandboxInfo {
let (depends, makedepends, checkdepends, optdepends) = parse_pkgbuild_deps(pkgbuild_text);
let depends_delta = analyze_dependencies(&depends, installed, provided);
let makedepends_delta = analyze_dependencies(&makedepends, installed, provided);
let checkdepends_delta = analyze_dependencies(&checkdepends, installed, provided);
let optdepends_delta = analyze_dependencies(&optdepends, installed, provided);
SandboxInfo {
package_name: package_name.to_string(),
depends: depends_delta,
makedepends: makedepends_delta,
checkdepends: checkdepends_delta,
optdepends: optdepends_delta,
}
}
pub(super) fn analyze_dependencies(
deps: &[String],
installed: &HashSet<String>,
provided: &HashSet<String>,
) -> Vec<DependencyDelta> {
deps.iter()
.filter_map(|dep_spec| {
let pkg_name = extract_package_name(dep_spec);
let is_installed = crate::logic::deps::is_package_installed_or_provided(
&pkg_name, installed, provided,
);
if is_installed && is_local_package(&pkg_name) {
return None;
}
let installed_version = if is_installed {
crate::logic::deps::get_installed_version(&pkg_name).ok()
} else {
None
};
let version_satisfied = installed_version
.as_ref()
.is_some_and(|version| crate::logic::deps::version_satisfies(version, dep_spec));
Some(DependencyDelta {
name: dep_spec.clone(),
is_installed,
installed_version,
version_satisfied,
})
})
.collect()
}
#[must_use]
pub fn extract_package_name(dep_spec: &str) -> String {
let name = dep_spec
.find(':')
.map_or_else(|| dep_spec, |colon_pos| &dep_spec[..colon_pos]);
name.trim()
.split(">=")
.next()
.unwrap_or(name)
.split("<=")
.next()
.unwrap_or(name)
.split("==")
.next()
.unwrap_or(name)
.split('>')
.next()
.unwrap_or(name)
.split('<')
.next()
.unwrap_or(name)
.trim()
.to_string()
}
fn is_local_package(name: &str) -> bool {
let output = Command::new("pacman")
.args(["-Qi", name])
.env("LC_ALL", "C")
.env("LANG", "C")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output();
match output {
Ok(output) if output.status.success() => {
let text = String::from_utf8_lossy(&output.stdout);
for line in text.lines() {
if line.starts_with("Repository")
&& let Some(colon_pos) = line.find(':')
{
let repo = line[colon_pos + 1..].trim().to_lowercase();
return repo == "local" || repo.is_empty();
}
}
}
_ => {
return false;
}
}
false
}
pub(super) fn get_installed_packages() -> std::collections::HashSet<String> {
crate::logic::deps::get_installed_packages()
}