Add version rollback support for AppImage updates
This commit is contained in:
@@ -1744,6 +1744,24 @@ impl Database {
|
||||
Ok(self.conn.last_insert_rowid())
|
||||
}
|
||||
|
||||
// --- Version rollback ---
|
||||
|
||||
pub fn set_previous_version(&self, id: i64, path: Option<&str>) -> SqlResult<()> {
|
||||
self.conn.execute(
|
||||
"UPDATE appimages SET previous_version_path = ?2 WHERE id = ?1",
|
||||
params![id, path],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_previous_version(&self, id: i64) -> SqlResult<Option<String>> {
|
||||
self.conn.query_row(
|
||||
"SELECT previous_version_path FROM appimages WHERE id = ?1",
|
||||
params![id],
|
||||
|row| row.get(0),
|
||||
)
|
||||
}
|
||||
|
||||
// --- System modification tracking ---
|
||||
|
||||
pub fn register_modification(
|
||||
|
||||
@@ -989,6 +989,56 @@ fn build_system_tab(record: &AppImageRecord, db: &Rc<Database>, toast_overlay: &
|
||||
}
|
||||
inner.append(&integration_group);
|
||||
|
||||
// Version Rollback group
|
||||
if let Some(ref prev_path) = record.previous_version_path {
|
||||
let prev = std::path::Path::new(prev_path);
|
||||
if prev.exists() {
|
||||
let rollback_group = adw::PreferencesGroup::builder()
|
||||
.title("Version Rollback")
|
||||
.description("A previous version is available from the last update.")
|
||||
.build();
|
||||
let rollback_row = adw::ActionRow::builder()
|
||||
.title("Previous version available")
|
||||
.subtitle(prev_path.as_str())
|
||||
.build();
|
||||
let rollback_btn = gtk::Button::builder()
|
||||
.label("Rollback")
|
||||
.valign(gtk::Align::Center)
|
||||
.css_classes(["destructive-action"])
|
||||
.build();
|
||||
rollback_row.add_suffix(&rollback_btn);
|
||||
|
||||
let current_path = record.path.clone();
|
||||
let prev_path_owned = prev_path.clone();
|
||||
let record_id_rb = record.id;
|
||||
let db_rb = db.clone();
|
||||
let toast_rb = toast_overlay.clone();
|
||||
rollback_btn.connect_clicked(move |btn| {
|
||||
let current = std::path::Path::new(¤t_path);
|
||||
let prev = std::path::Path::new(&prev_path_owned);
|
||||
let temp_path = current.with_extension("AppImage.rollback-tmp");
|
||||
// Swap: current -> tmp, prev -> current, tmp -> prev
|
||||
let result = std::fs::rename(current, &temp_path)
|
||||
.and_then(|_| std::fs::rename(prev, current))
|
||||
.and_then(|_| std::fs::rename(&temp_path, prev));
|
||||
match result {
|
||||
Ok(()) => {
|
||||
db_rb.set_previous_version(record_id_rb, Some(&prev_path_owned)).ok();
|
||||
toast_rb.add_toast(adw::Toast::new("Rolled back to previous version"));
|
||||
btn.set_sensitive(false);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Rollback failed: {}", e);
|
||||
toast_rb.add_toast(adw::Toast::new("Rollback failed"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rollback_group.add(&rollback_row);
|
||||
inner.append(&rollback_group);
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime Compatibility group
|
||||
let compat_group = adw::PreferencesGroup::builder()
|
||||
.title("Compatibility")
|
||||
|
||||
@@ -184,6 +184,14 @@ fn start_update(
|
||||
dialog.set_body(&success_body);
|
||||
dialog.set_response_enabled("update", false);
|
||||
|
||||
// Save previous version path for rollback
|
||||
if let Some(ref old_path) = applied.old_path_backup {
|
||||
db_ref.set_previous_version(
|
||||
record_id,
|
||||
Some(&old_path.to_string_lossy()),
|
||||
).ok();
|
||||
}
|
||||
|
||||
// Handle old version cleanup
|
||||
if let Some(old_path) = applied.old_path_backup {
|
||||
handle_old_version_cleanup(&dialog, old_path);
|
||||
|
||||
Reference in New Issue
Block a user