Add AppImage metadata extraction, display, and bug fixes

This commit is contained in:
2026-02-27 18:31:07 +02:00
parent 4211ff5ce0
commit 87f4e5d7bf
13 changed files with 1239 additions and 24 deletions

View File

@@ -46,6 +46,23 @@ pub struct AppImageRecord {
pub tags: Option<String>,
pub pinned: bool,
pub avg_startup_ms: Option<i64>,
// extended metadata
pub appstream_id: Option<String>,
pub appstream_description: Option<String>,
pub generic_name: Option<String>,
pub license: Option<String>,
pub homepage_url: Option<String>,
pub bugtracker_url: Option<String>,
pub donation_url: Option<String>,
pub help_url: Option<String>,
pub vcs_url: Option<String>,
pub keywords: Option<String>,
pub mime_types: Option<String>,
pub content_rating: Option<String>,
pub project_group: Option<String>,
pub release_history: Option<String>,
pub desktop_actions: Option<String>,
pub has_signature: bool,
}
#[derive(Debug, Clone)]
@@ -339,6 +356,10 @@ impl Database {
self.migrate_to_v8()?;
}
if current_version < 9 {
self.migrate_to_v9()?;
}
// Ensure all expected columns exist (repairs DBs where a migration
// was updated after it had already run on this database)
self.ensure_columns()?;
@@ -677,6 +698,44 @@ impl Database {
Ok(())
}
fn migrate_to_v9(&self) -> SqlResult<()> {
let new_columns = [
"appstream_id TEXT",
"appstream_description TEXT",
"generic_name TEXT",
"license TEXT",
"homepage_url TEXT",
"bugtracker_url TEXT",
"donation_url TEXT",
"help_url TEXT",
"vcs_url TEXT",
"keywords TEXT",
"mime_types TEXT",
"content_rating TEXT",
"project_group TEXT",
"release_history TEXT",
"desktop_actions TEXT",
"has_signature INTEGER NOT NULL DEFAULT 0",
];
for col in &new_columns {
let sql = format!("ALTER TABLE appimages ADD COLUMN {}", col);
match self.conn.execute(&sql, []) {
Ok(_) => {}
Err(e) => {
let msg = e.to_string();
if !msg.contains("duplicate column") {
return Err(e);
}
}
}
}
self.conn.execute(
"UPDATE schema_version SET version = ?1",
params![9],
)?;
Ok(())
}
pub fn upsert_appimage(
&self,
path: &str,
@@ -742,6 +801,68 @@ impl Database {
Ok(())
}
pub fn update_appstream_metadata(
&self,
id: i64,
appstream_id: Option<&str>,
appstream_description: Option<&str>,
generic_name: Option<&str>,
license: Option<&str>,
homepage_url: Option<&str>,
bugtracker_url: Option<&str>,
donation_url: Option<&str>,
help_url: Option<&str>,
vcs_url: Option<&str>,
keywords: Option<&str>,
mime_types: Option<&str>,
content_rating: Option<&str>,
project_group: Option<&str>,
release_history: Option<&str>,
desktop_actions: Option<&str>,
has_signature: bool,
) -> SqlResult<()> {
self.conn.execute(
"UPDATE appimages SET
appstream_id = ?2,
appstream_description = ?3,
generic_name = ?4,
license = ?5,
homepage_url = ?6,
bugtracker_url = ?7,
donation_url = ?8,
help_url = ?9,
vcs_url = ?10,
keywords = ?11,
mime_types = ?12,
content_rating = ?13,
project_group = ?14,
release_history = ?15,
desktop_actions = ?16,
has_signature = ?17
WHERE id = ?1",
params![
id,
appstream_id,
appstream_description,
generic_name,
license,
homepage_url,
bugtracker_url,
donation_url,
help_url,
vcs_url,
keywords,
mime_types,
content_rating,
project_group,
release_history,
desktop_actions,
has_signature,
],
)?;
Ok(())
}
pub fn update_sha256(&self, id: i64, sha256: &str) -> SqlResult<()> {
self.conn.execute(
"UPDATE appimages SET sha256 = ?2 WHERE id = ?1",
@@ -777,7 +898,11 @@ impl Database {
fuse_status, wayland_status, update_info, update_type,
latest_version, update_checked, update_url, notes, sandbox_mode,
runtime_wayland_status, runtime_wayland_checked, analysis_status,
launch_args, tags, pinned, avg_startup_ms";
launch_args, tags, pinned, avg_startup_ms,
appstream_id, appstream_description, generic_name, license,
homepage_url, bugtracker_url, donation_url, help_url, vcs_url,
keywords, mime_types, content_rating, project_group,
release_history, desktop_actions, has_signature";
fn row_to_record(row: &rusqlite::Row) -> rusqlite::Result<AppImageRecord> {
Ok(AppImageRecord {
@@ -818,6 +943,22 @@ impl Database {
tags: row.get(34).unwrap_or(None),
pinned: row.get::<_, bool>(35).unwrap_or(false),
avg_startup_ms: row.get(36).unwrap_or(None),
appstream_id: row.get(37).unwrap_or(None),
appstream_description: row.get(38).unwrap_or(None),
generic_name: row.get(39).unwrap_or(None),
license: row.get(40).unwrap_or(None),
homepage_url: row.get(41).unwrap_or(None),
bugtracker_url: row.get(42).unwrap_or(None),
donation_url: row.get(43).unwrap_or(None),
help_url: row.get(44).unwrap_or(None),
vcs_url: row.get(45).unwrap_or(None),
keywords: row.get(46).unwrap_or(None),
mime_types: row.get(47).unwrap_or(None),
content_rating: row.get(48).unwrap_or(None),
project_group: row.get(49).unwrap_or(None),
release_history: row.get(50).unwrap_or(None),
desktop_actions: row.get(51).unwrap_or(None),
has_signature: row.get::<_, bool>(52).unwrap_or(false),
})
}
@@ -1691,13 +1832,13 @@ mod tests {
fn test_fresh_database_creates_at_latest_version() {
let db = Database::open_in_memory().unwrap();
// Verify schema_version is at the latest (8)
// Verify schema_version is at the latest (9)
let version: i32 = db.conn.query_row(
"SELECT version FROM schema_version LIMIT 1",
[],
|row| row.get(0),
).unwrap();
assert_eq!(version, 8);
assert_eq!(version, 9);
// All tables that should exist after the full v1-v7 migration chain
let expected_tables = [