mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-10-14 14:26:48 -04:00
Linux: report undetected-package fallback as a system binary (#99 follow-up)
When dpkg/rpm don't list the app, the launcher can't know which package manager installed it, so label it a system binary (open it, leave update and removal to whatever installed it) instead of Deb/Rpm with a guessed package name. Require the binary itself; fix clippy and rustfmt. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
797071e591
commit
633f09c7cc
2 files changed
+13
-67
No files matched your search
+12
-64
@@ -276,60 +276,19 @@ pub mod linux {
|
||||
detect_system_install(app)
|
||||
}
|
||||
|
||||
/// When package manager queries don't report the package (e.g. timeout, unlisted name,
|
||||
/// running inside a container sandbox, or lock conflicts), detect the app from its desktop
|
||||
/// entry or system binary.
|
||||
/// When the package managers don't report the app (a query timed out or was locked, an
|
||||
/// unlisted package name, or a sandbox that can't see them) but its binary is there. It is
|
||||
/// reported as a system binary: the launcher can open it but leaves updating and removing it
|
||||
/// to whatever installed it, since it can't tell which package manager that was.
|
||||
fn detect_system_install(app: &CraftApp) -> Option<Installed> {
|
||||
let bin = find_binary(app.id);
|
||||
let desktop = find_desktop_file(app);
|
||||
if bin.is_none() && desktop.is_none() {
|
||||
return None;
|
||||
}
|
||||
let bin_path = bin.unwrap_or_else(|| PathBuf::from("/usr/bin").join(app.id));
|
||||
let version = binary_version(&bin_path, app.id);
|
||||
let source = if Path::new("/usr/bin/dpkg").is_file() || which("dpkg").is_some() {
|
||||
InstallSource::Deb
|
||||
} else if Path::new("/usr/bin/rpm").is_file() || which("rpm").is_some() {
|
||||
InstallSource::Rpm
|
||||
} else {
|
||||
InstallSource::Binary
|
||||
};
|
||||
Some(Installed {
|
||||
version,
|
||||
source,
|
||||
location: bin_path.display().to_string(),
|
||||
package: Some(app.id.to_string()),
|
||||
})
|
||||
let bin = find_binary(app.id)?;
|
||||
Some(Installed { version: binary_version(&bin, app.id), source: InstallSource::Binary, location: bin.display().to_string(), package: None })
|
||||
}
|
||||
|
||||
fn find_binary(id: &str) -> Option<PathBuf> {
|
||||
if let Some(path) = std::env::var_os("PATH") {
|
||||
if let Some(p) = std::env::split_paths(&path).map(|d| d.join(id)).find(|p| p.is_file()) {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
for dir in ["/usr/bin", "/usr/local/bin"] {
|
||||
let p = PathBuf::from(dir).join(id);
|
||||
if p.is_file() {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
let p = home.join(".local/bin").join(id);
|
||||
if p.is_file() {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn find_desktop_file(app: &CraftApp) -> Option<PathBuf> {
|
||||
let mut dirs = vec![PathBuf::from("/usr/share/applications"), PathBuf::from("/usr/local/share/applications")];
|
||||
if let Some(data) = dirs::data_dir() {
|
||||
dirs.push(data.join("applications"));
|
||||
}
|
||||
let names = [format!("{}.desktop", app.bundle_id()), format!("{}.desktop", app.id)];
|
||||
dirs.into_iter().flat_map(|d| names.iter().map(move |n| d.join(n))).find(|p| p.is_file())
|
||||
let on_path = std::env::var_os("PATH").and_then(|path| std::env::split_paths(&path).map(|d| d.join(id)).find(|p| p.is_file()));
|
||||
let usual = ["/usr/bin", "/usr/local/bin"].into_iter().map(PathBuf::from).chain(dirs::home_dir().map(|h| h.join(".local/bin")));
|
||||
on_path.or_else(|| usual.map(|d| d.join(id)).find(|p| p.is_file()))
|
||||
}
|
||||
|
||||
pub(crate) fn binary_version(bin: &Path, id: &str) -> Option<version::Version> {
|
||||
@@ -337,11 +296,6 @@ pub mod linux {
|
||||
let rest = out.trim().strip_prefix(id)?.trim_start();
|
||||
version::parse(rest.split_whitespace().next()?)
|
||||
}
|
||||
|
||||
fn which(name: &str) -> Option<PathBuf> {
|
||||
let path = std::env::var_os("PATH")?;
|
||||
std::env::split_paths(&path).map(|d| d.join(name)).find(|p| p.is_file())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
@@ -367,12 +321,11 @@ pub mod freebsd {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, target_os = "linux"))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn ours_filter_matches_rpm_packages() {
|
||||
let ours = |name: &str| {
|
||||
artcraft_launcher_core::SUITE.iter().any(|a| {
|
||||
@@ -387,19 +340,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn reads_binary_version_from_cli() {
|
||||
let photo = CraftApp::by_id("photocraft").unwrap();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let bin = temp_dir.path().join("photocraft");
|
||||
std::fs::write(&bin, "#!/bin/sh\necho 'photocraft 0.6.0 (0c72d9542, 2026-10-10)'\n").unwrap();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
}
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
let ver = linux::binary_version(&bin, photo.id);
|
||||
assert_eq!(ver.unwrap().to_string(), "0.6.0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,7 @@ pub fn candidate_names(app: &CraftApp, manager: InstallSource) -> Vec<String> {
|
||||
InstallSource::Pacman => {
|
||||
app.stems().flat_map(|s| [s.to_string(), format!("{s}-bin"), format!("{s}-git")]).chain(std::iter::once(app.bundle_id())).collect()
|
||||
}
|
||||
InstallSource::Deb | InstallSource::Rpm => {
|
||||
app.stems().map(str::to_string).chain(std::iter::once(app.bundle_id())).collect()
|
||||
}
|
||||
InstallSource::Deb | InstallSource::Rpm => app.stems().map(str::to_string).chain(std::iter::once(app.bundle_id())).collect(),
|
||||
_ => app.stems().map(str::to_string).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user