#[must_use]
pub fn parse_backup_from_pkgbuild(pkgbuild: &str) -> Vec<String> {
let mut backup_files = Vec::new();
let mut in_backup_array = false;
for line in pkgbuild.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if line.starts_with("backup=") || line.starts_with("backup =") {
in_backup_array = true;
if let Some(start) = line.find('(')
&& let Some(end) = line.rfind(')')
{
let array_content = &line[start + 1..end];
parse_backup_array_content(array_content, &mut backup_files);
in_backup_array = false;
} else if line.contains('(') {
if let Some(start) = line.find('(') {
let array_content = &line[start + 1..];
parse_backup_array_content(array_content, &mut backup_files);
}
}
} else if in_backup_array {
if line.contains(')') {
if let Some(end) = line.rfind(')') {
let remaining = &line[..end];
parse_backup_array_content(remaining, &mut backup_files);
}
in_backup_array = false;
} else {
parse_backup_array_content(line, &mut backup_files);
}
}
}
backup_files
}
pub fn parse_backup_array_content(content: &str, backup_files: &mut Vec<String>) {
let mut in_quotes = false;
let mut quote_char = '\0';
let mut current_file = String::new();
for ch in content.chars() {
match ch {
'\'' | '"' => {
if !in_quotes {
in_quotes = true;
quote_char = ch;
} else if ch == quote_char {
if !current_file.is_empty() {
backup_files.push(current_file.clone());
current_file.clear();
}
in_quotes = false;
quote_char = '\0';
} else {
current_file.push(ch);
}
}
_ if in_quotes => {
current_file.push(ch);
}
_ => {
}
}
}
if !current_file.is_empty() && in_quotes {
backup_files.push(current_file);
}
}
#[must_use]
pub fn parse_backup_from_srcinfo(srcinfo: &str) -> Vec<String> {
let mut backup_files = Vec::new();
for line in srcinfo.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if let Some((key, value)) = line.split_once('=') {
let key = key.trim();
let value = value.trim();
if key == "backup" && !value.is_empty() {
backup_files.push(value.to_string());
}
}
}
backup_files
}
#[must_use]
pub fn parse_install_paths_from_pkgbuild(pkgbuild: &str, pkgname: &str) -> Vec<String> {
let mut files = Vec::new();
let mut in_package_function = false;
let mut package_function_depth = 0;
for line in pkgbuild.lines() {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with('#') {
continue;
}
if trimmed.starts_with("package()") || trimmed.starts_with("package_") {
in_package_function = true;
package_function_depth = 0;
continue;
}
if in_package_function {
if trimmed.contains('{') {
package_function_depth += trimmed.matches('{').count();
}
if trimmed.contains('}') {
let closing_count = trimmed.matches('}').count();
if package_function_depth >= closing_count {
package_function_depth -= closing_count;
} else {
package_function_depth = 0;
}
if package_function_depth == 0 {
in_package_function = false;
continue;
}
}
if trimmed.contains("install") && trimmed.contains("$pkgdir") {
if let Some(pkgdir_pos) = trimmed.find("$pkgdir") {
let after_pkgdir = &trimmed[pkgdir_pos + 7..]; let path_start = after_pkgdir
.chars()
.position(|c| c != ' ' && c != '/' && c != '"' && c != '\'')
.unwrap_or(0);
let path_part = &after_pkgdir[path_start..];
let path_end = path_part
.chars()
.position(|c| c == ' ' || c == '"' || c == '\'' || c == ';')
.unwrap_or(path_part.len());
let mut path = path_part[..path_end].to_string();
if path.starts_with('/') {
path.remove(0);
}
if !path.is_empty() {
{
let path_str = &path;
files.push(format!("/{path_str}"));
}
}
}
} else if trimmed.contains("cp") && trimmed.contains("$pkgdir") {
if let Some(pkgdir_pos) = trimmed.find("$pkgdir") {
let after_pkgdir = &trimmed[pkgdir_pos + 7..];
let path_start = after_pkgdir
.chars()
.position(|c| c != ' ' && c != '/' && c != '"' && c != '\'')
.unwrap_or(0);
let path_part = &after_pkgdir[path_start..];
let path_end = path_part
.chars()
.position(|c| c == ' ' || c == '"' || c == '\'' || c == ';')
.unwrap_or(path_part.len());
let mut path = path_part[..path_end].to_string();
if path.starts_with('/') {
path.remove(0);
}
if !path.is_empty() {
{
let path_str = &path;
files.push(format!("/{path_str}"));
}
}
}
}
}
}
files.sort();
files.dedup();
if files.is_empty() {
files.push(format!("/usr/bin/{pkgname}"));
files.push(format!("/usr/share/{pkgname}"));
}
files
}