Compare commits
85
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edaf98b10d | ||
|
|
292b91d612 | ||
|
|
c8683f3d72 | ||
|
|
2cfb6fa0f0 | ||
|
|
622a6ecf79 | ||
|
|
43db437ac7 | ||
|
|
49b2a2f592 | ||
|
|
b73c457c34 | ||
|
|
4920211eec | ||
|
|
d0f3984d32 | ||
|
|
5f3b7f892b | ||
|
|
8f40262dff | ||
|
|
5aff13e419 | ||
|
|
b120daa9c7 | ||
|
|
ffabc4c2ed | ||
|
|
ad7c850ff0 | ||
|
|
bb055a5503 | ||
|
|
fc1904be60 | ||
|
|
0842f5ed61 | ||
|
|
f2cf2b3466 | ||
|
|
e73ea22e23 | ||
|
|
7ad8903393 | ||
|
|
dd8790c5d1 | ||
|
|
a187316a1a | ||
|
|
f431cea768 | ||
|
|
9fa48f1bac | ||
|
|
baa81243d3 | ||
|
|
475a23f3dd | ||
|
|
f06483194c | ||
|
|
8c5ee314d8 | ||
|
|
db83dc3224 | ||
|
|
cdeab85cf6 | ||
|
|
5b3c95ae26 | ||
|
|
d05a0e39e0 | ||
|
|
0b6db27ac2 | ||
|
|
45e1c57842 | ||
|
|
a515ee6b4f | ||
|
|
e52397f64b | ||
|
|
1abe783dfc | ||
|
|
8e95bbaabd | ||
|
|
6208dab2b7 | ||
|
|
619b3cb447 | ||
|
|
84e33d06c8 | ||
|
|
325cbdd87f | ||
|
|
e3433edb68 | ||
|
|
2aebccd914 | ||
|
|
bee43b29c1 | ||
|
|
fcd57a372d | ||
|
|
ddde786c41 | ||
|
|
8c57a06a79 | ||
|
|
7ec32ed077 | ||
|
|
c7bbc26822 | ||
|
|
3ab12b0b8f | ||
|
|
b717689ace | ||
|
|
6e97feddde | ||
|
|
011c07820d | ||
|
|
804ba35a70 | ||
|
|
ce11431cdf | ||
|
|
cddbe5b2e2 | ||
|
|
668206e5e5 | ||
|
|
b4f2d1bf0c | ||
|
|
11c754a8c1 | ||
|
|
e20759d1cb | ||
|
|
fb632c16c6 | ||
|
|
a755e546d0 | ||
|
|
87f4e5d7bf | ||
|
|
4211ff5ce0 | ||
|
|
a1c7f72d1d | ||
|
|
d6a6fb9eca | ||
|
|
b0852f781c | ||
|
|
9df79095f2 | ||
|
|
0c9f2caa2c | ||
|
|
bea039367d | ||
|
|
cd76d268e2 | ||
|
|
ea6904040a | ||
|
|
ec413f4c6f | ||
|
|
1a177abb75 | ||
|
|
6aafaeaa09 | ||
|
|
67e01c45be | ||
|
|
d1628cf6d5 | ||
|
|
647fc39054 | ||
|
|
8999fb99b3 | ||
|
|
cc78b44d41 | ||
|
|
2f5e5cefc1 | ||
|
|
c3620b487d |
+19
-24
@@ -29,7 +29,6 @@ pub struct AppImageRecord {
|
||||
pub first_seen: String,
|
||||
pub last_scanned: String,
|
||||
pub file_modified: Option<String>,
|
||||
// Phase 2 fields
|
||||
pub fuse_status: Option<String>,
|
||||
pub wayland_status: Option<String>,
|
||||
pub update_info: Option<String>,
|
||||
@@ -38,20 +37,17 @@ pub struct AppImageRecord {
|
||||
pub update_checked: Option<String>,
|
||||
pub update_url: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
// Phase 3 fields
|
||||
pub sandbox_mode: Option<String>,
|
||||
// Phase 5 fields
|
||||
pub runtime_wayland_status: Option<String>,
|
||||
pub runtime_wayland_checked: Option<String>,
|
||||
// Async analysis pipeline
|
||||
pub analysis_status: Option<String>,
|
||||
// Custom launch arguments
|
||||
pub launch_args: Option<String>,
|
||||
// Phase 6 fields
|
||||
pub tags: Option<String>,
|
||||
pub pinned: bool,
|
||||
pub avg_startup_ms: Option<i64>,
|
||||
// Phase 9 fields - extended metadata
|
||||
// extended metadata
|
||||
pub appstream_id: Option<String>,
|
||||
pub appstream_description: Option<String>,
|
||||
pub generic_name: Option<String>,
|
||||
@@ -69,7 +65,7 @@ pub struct AppImageRecord {
|
||||
pub desktop_actions: Option<String>,
|
||||
pub has_signature: bool,
|
||||
pub screenshot_urls: Option<String>,
|
||||
// Phase 11 fields - system modification tracking
|
||||
// system modification tracking
|
||||
pub previous_version_path: Option<String>,
|
||||
pub source_url: Option<String>,
|
||||
pub autostart: bool,
|
||||
@@ -346,7 +342,7 @@ impl Database {
|
||||
}
|
||||
|
||||
fn init_schema(&self) -> SqlResult<()> {
|
||||
// Phase 1 base tables
|
||||
// base tables
|
||||
self.conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS schema_version (
|
||||
version INTEGER NOT NULL
|
||||
@@ -535,8 +531,8 @@ impl Database {
|
||||
}
|
||||
|
||||
fn migrate_to_v2(&self) -> SqlResult<()> {
|
||||
// Add Phase 2 columns to appimages table
|
||||
let phase2_columns = [
|
||||
// Add columns to appimages table
|
||||
let extra_columns = [
|
||||
"fuse_status TEXT",
|
||||
"wayland_status TEXT",
|
||||
"update_info TEXT",
|
||||
@@ -546,12 +542,11 @@ impl Database {
|
||||
"update_url TEXT",
|
||||
"notes TEXT",
|
||||
];
|
||||
for col in &phase2_columns {
|
||||
for col in &extra_columns {
|
||||
let sql = format!("ALTER TABLE appimages ADD COLUMN {}", col);
|
||||
self.conn.execute_batch(&sql).ok();
|
||||
}
|
||||
|
||||
// Phase 2 tables
|
||||
self.conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS launch_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -595,7 +590,7 @@ impl Database {
|
||||
}
|
||||
|
||||
fn migrate_to_v3(&self) -> SqlResult<()> {
|
||||
// Phase 3 tables: security scanning
|
||||
// security scanning
|
||||
self.conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS bundled_libraries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -1712,7 +1707,7 @@ impl Database {
|
||||
self.conn.query_row("SELECT COUNT(*) FROM appimages", [], |row| row.get(0))
|
||||
}
|
||||
|
||||
// --- Phase 2: Status updates ---
|
||||
// --- Status updates ---
|
||||
|
||||
pub fn update_fuse_status(&self, id: i64, status: &str) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
@@ -1811,7 +1806,7 @@ impl Database {
|
||||
rows.collect()
|
||||
}
|
||||
|
||||
// --- Phase 2: Launch tracking ---
|
||||
// --- Launch tracking ---
|
||||
|
||||
pub fn record_launch(&self, appimage_id: i64, source: &str) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
@@ -1854,7 +1849,7 @@ impl Database {
|
||||
rows.collect()
|
||||
}
|
||||
|
||||
// --- Phase 2: Update history ---
|
||||
// --- Update history ---
|
||||
|
||||
pub fn record_update(
|
||||
&self,
|
||||
@@ -1874,7 +1869,7 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Phase 3: Security scanning ---
|
||||
// --- Security scanning ---
|
||||
|
||||
pub fn clear_bundled_libraries(&self, appimage_id: i64) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
@@ -2026,7 +2021,7 @@ impl Database {
|
||||
Ok(summary)
|
||||
}
|
||||
|
||||
// --- Phase 3: App data paths ---
|
||||
// --- App data paths ---
|
||||
|
||||
pub fn insert_app_data_path(
|
||||
&self,
|
||||
@@ -2106,7 +2101,7 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Phase 5: Runtime Wayland ---
|
||||
// --- Runtime Wayland ---
|
||||
|
||||
pub fn update_runtime_wayland_status(&self, id: i64, status: &str) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
@@ -2116,7 +2111,7 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Phase 5: Config Backups ---
|
||||
// --- Config Backups ---
|
||||
|
||||
pub fn insert_config_backup(
|
||||
&self,
|
||||
@@ -2186,7 +2181,7 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Phase 5: CVE Notifications ---
|
||||
// --- CVE Notifications ---
|
||||
|
||||
pub fn has_cve_been_notified(&self, appimage_id: i64, cve_id: &str) -> SqlResult<bool> {
|
||||
let count: i32 = self.conn.query_row(
|
||||
@@ -2211,7 +2206,7 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Phase 5: Sandbox Profiles ---
|
||||
// --- Sandbox Profiles ---
|
||||
|
||||
pub fn insert_sandbox_profile(
|
||||
&self,
|
||||
@@ -2281,7 +2276,7 @@ impl Database {
|
||||
rows.collect()
|
||||
}
|
||||
|
||||
// --- Phase 6: Tags, Pin, Startup Time ---
|
||||
// --- Tags, Pin, Startup Time ---
|
||||
|
||||
pub fn update_tags(&self, id: i64, tags: Option<&str>) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
@@ -2355,7 +2350,7 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Phase 5: Runtime Updates ---
|
||||
// --- Runtime Updates ---
|
||||
|
||||
pub fn record_runtime_update(
|
||||
&self,
|
||||
@@ -3259,7 +3254,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_phase2_status_updates() {
|
||||
fn test_status_updates() {
|
||||
let db = Database::open_in_memory().unwrap();
|
||||
let id = db.upsert_appimage("/path/app.AppImage", "app.AppImage", Some(2), 1000, true, None).unwrap();
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ pub fn detect_duplicates(db: &Database) -> Vec<DuplicateGroup> {
|
||||
|
||||
let mut groups = Vec::new();
|
||||
|
||||
// Phase 1: Find exact duplicates by SHA256 hash
|
||||
// Find exact duplicates by SHA256 hash
|
||||
let hash_groups = group_by_hash(&records);
|
||||
for (hash, members) in &hash_groups {
|
||||
if members.len() > 1 {
|
||||
@@ -95,7 +95,7 @@ pub fn detect_duplicates(db: &Database) -> Vec<DuplicateGroup> {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Find same app name groups (excluding already-found exact dupes)
|
||||
// Find same app name groups (excluding already-found exact dupes)
|
||||
let exact_dupe_ids: std::collections::HashSet<i64> = groups
|
||||
.iter()
|
||||
.flat_map(|g| g.members.iter().map(|m| m.record.id))
|
||||
|
||||
@@ -117,7 +117,7 @@ pub fn show_drop_dialog(
|
||||
let on_complete_ref = on_complete.clone();
|
||||
|
||||
glib::spawn_future_local(async move {
|
||||
// Phase 1: Fast registration (copy + DB upsert only)
|
||||
// Fast registration (copy + DB upsert only)
|
||||
let result = gio::spawn_blocking(move || {
|
||||
register_dropped_files(&files, copy)
|
||||
})
|
||||
@@ -143,7 +143,7 @@ pub fn show_drop_dialog(
|
||||
toast_ref.add_toast(widgets::info_toast(&msg));
|
||||
}
|
||||
|
||||
// Phase 2: Background analysis for each file
|
||||
// Background analysis for each file
|
||||
let on_complete_bg = on_complete_ref.clone();
|
||||
for reg in registered {
|
||||
let on_complete_inner = on_complete_bg.clone();
|
||||
|
||||
+7
-7
@@ -1571,11 +1571,11 @@ impl DriftwoodWindow {
|
||||
let toast_overlay = self.imp().toast_overlay.get().unwrap().clone();
|
||||
let window_weak = self.downgrade();
|
||||
|
||||
// Two-phase scan:
|
||||
// Phase 1 (fast): discover files, upsert into DB, mark pending analysis
|
||||
// Phase 2 (background): heavy analysis per file
|
||||
// Two-pass scan:
|
||||
// Fast pass: discover files, upsert into DB, mark pending analysis
|
||||
// Background pass: heavy analysis per file
|
||||
glib::spawn_future_local(async move {
|
||||
// Phase 1: Fast registration
|
||||
// Fast registration
|
||||
let result = gio::spawn_blocking(move || {
|
||||
let bg_db = Database::open().expect("Failed to open database for scan");
|
||||
let start = Instant::now();
|
||||
@@ -1646,7 +1646,7 @@ impl DriftwoodWindow {
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"Scan phase 1: {} files, {} new, {} removed, {} skipped (unchanged), took {}ms",
|
||||
"Scan: {} files, {} new, {} removed, {} skipped (unchanged), took {}ms",
|
||||
total, new_count, removed_count, skipped_count, start.elapsed().as_millis()
|
||||
);
|
||||
|
||||
@@ -1665,7 +1665,7 @@ impl DriftwoodWindow {
|
||||
.await;
|
||||
|
||||
if let Ok((total, new_count, needs_analysis)) = result {
|
||||
// Dismiss the "Scanning..." toast now that Phase 1 is done
|
||||
// Dismiss the "Scanning..." toast now that fast scan is done
|
||||
if let Some(ref toast) = scan_toast {
|
||||
toast.dismiss();
|
||||
}
|
||||
@@ -1689,7 +1689,7 @@ impl DriftwoodWindow {
|
||||
};
|
||||
toast_overlay.add_toast(widgets::info_toast(&msg));
|
||||
|
||||
// Phase 2: Background analysis per file with debounced UI refresh
|
||||
// Background analysis per file with debounced UI refresh
|
||||
let running = analysis::running_count();
|
||||
if running > 0 {
|
||||
log::info!("Analyzing {} AppImage(s) in background ({} already running)", needs_analysis.len(), running);
|
||||
|
||||
Reference in New Issue
Block a user