fix: cubl AUR search on Linux, graceful pkgutils fallback

- search now queries AUR directly on Linux (skips pkgutils repo)
- install -S offers AUR fetch + recipe conversion on Linux
- update-all, remove, query-* show helpful error on Linux
- host_only_notice() helper for consistent messaging
This commit is contained in:
2026-05-08 00:47:51 +01:00
parent 44ed766291
commit 2b984db9a1
@@ -369,6 +369,27 @@ fn new_pkg_callback() -> Rc<RefCell<IndicatifCallback>> {
}
fn install_package(context: &AppContext, package: &str) -> Result<(), Box<dyn std::error::Error>> {
if cfg!(not(target_os = "redox")) {
println!("Searching AUR for {package}...");
let client = AurClient::new();
let results = client.search(package, Some("name"))?;
if results.is_empty() {
return Err(format!("{package} not found in AUR").into());
}
let pkg = &results[0];
println!("Found: {}/{}{}", pkg.name, pkg.version, pkg.description);
println!("Would you like to fetch this package from AUR into ~/.cub/? [y/N]");
let mut answer = String::new();
io::stdin().read_line(&mut answer)?;
if answer.trim().to_ascii_lowercase().starts_with('y') {
fetch_aur_to_store(&pkg.name)?;
println!("Recipe saved to ~/.cub/recipes/{}/", pkg.name);
println!("Build with: cubl -B ~/.cub/recipes/{}/", pkg.name);
}
return Ok(());
}
let package_name = PackageName::new(package.to_string())?;
let mut library = context.open_library()?;
@@ -394,22 +415,21 @@ fn install_package(context: &AppContext, package: &str) -> Result<(), Box<dyn st
}
fn search_packages(context: &AppContext, query: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut library = context.open_library()?;
let official_matches = library.search(query)?;
let bur_matches = search_cached_bur(query)?;
if official_matches.is_empty() {
println!("Official repo: no matches for {query:?}");
} else {
println!("Official repo:");
for (name, score) in official_matches {
println!(" {} ({score:.2})", name);
if cfg!(target_os = "redox") {
let mut library = context.open_library()?;
let official_matches = library.search(query)?;
if official_matches.is_empty() {
println!("Official repo: no matches for {query:?}");
} else {
println!("Official repo:");
for (name, score) in official_matches {
println!(" {} ({score:.2})", name);
}
}
}
if bur_matches.is_empty() {
println!("Cached BUR: no matches for {query:?}");
} else {
let bur_matches = search_cached_bur(query)?;
if !bur_matches.is_empty() {
println!("Cached BUR:");
for entry in bur_matches {
if let Some(description) = &entry.description {
@@ -420,6 +440,23 @@ fn search_packages(context: &AppContext, query: &str) -> Result<(), Box<dyn std:
}
}
match AurClient::new().search(query, None) {
Ok(aur_packages) if !aur_packages.is_empty() => {
println!("AUR:");
for pkg in aur_packages {
let desc = if pkg.description.len() > 60 {
format!("{}...", &pkg.description[..57])
} else {
pkg.description.clone()
};
println!(" {}/{} ({}) [votes: {}]",
pkg.name, pkg.version, desc, pkg.num_votes);
}
}
Ok(_) => println!("AUR: no matches for {query:?}"),
Err(e) => eprintln!("AUR search failed: {e}"),
}
Ok(())
}
@@ -467,6 +504,7 @@ fn sync_sources() -> Result<(), Box<dyn std::error::Error>> {
}
fn system_upgrade(context: &AppContext) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("system-upgrade")?;
sync_sources()?;
update_all(context)
}
@@ -805,6 +843,7 @@ fn import_aur_target(target: &str) -> Result<(), Box<dyn std::error::Error>> {
}
fn update_all(context: &AppContext) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("update-all")?;
let mut library = context.open_library()?;
library.update(Vec::new())?;
let applied = apply_library_changes(&mut library)?;
@@ -813,6 +852,7 @@ fn update_all(context: &AppContext) -> Result<(), Box<dyn std::error::Error>> {
}
fn remove_package(context: &AppContext, package: &str) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("remove")?;
let package_name = PackageName::new(package.to_string())?;
let mut library = context.open_library()?;
library.uninstall(vec![package_name])?;
@@ -822,6 +862,7 @@ fn remove_package(context: &AppContext, package: &str) -> Result<(), Box<dyn std
}
fn query_local_packages(context: &AppContext) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("query")?;
let library = context.open_library()?;
let mut packages = library.get_installed_packages()?;
packages.sort();
@@ -839,6 +880,7 @@ fn query_local_packages(context: &AppContext) -> Result<(), Box<dyn std::error::
}
fn query_local_info(context: &AppContext, package: &str) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("query-info")?;
let mut library = context.open_library()?;
let info = library.info(PackageName::new(package.to_string())?)?;
print_local_package_info(package, &info);
@@ -849,6 +891,7 @@ fn query_local_files(
context: &AppContext,
package: &str,
) -> Result<(), Box<dyn std::error::Error>> {
host_only_notice("query-list")?;
let package_name = PackageName::new(package.to_string())?;
let library = context.open_library()?;
let installed_packages = library.get_installed_packages()?;
@@ -924,6 +967,20 @@ fn apply_library_changes(library: &mut Library) -> Result<usize, Box<dyn std::er
}
}
fn host_only_notice(command: &str) -> Result<(), Box<dyn std::error::Error>> {
if cfg!(not(target_os = "redox")) {
return Err(format!(
"'cubl {command}' requires Red Bear OS package database.\n\
On Linux, use:\n \
cubl search <query> — search AUR\n \
cubl -G <pkg> — fetch and convert AUR PKGBUILD\n \
cubl -B <dir> — cook recipe with host cross-compiler\n \
cubl -Si <pkg> — show AUR package info"
).into());
}
Ok(())
}
fn print_aur_package(package: &AurPackage) {
println!("Repository : AUR");
println!("Name : {}", package.name);