Add version rollback support for AppImage updates
This commit is contained in:
@@ -1744,6 +1744,24 @@ impl Database {
|
|||||||
Ok(self.conn.last_insert_rowid())
|
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 ---
|
// --- System modification tracking ---
|
||||||
|
|
||||||
pub fn register_modification(
|
pub fn register_modification(
|
||||||
|
|||||||
@@ -989,6 +989,56 @@ fn build_system_tab(record: &AppImageRecord, db: &Rc<Database>, toast_overlay: &
|
|||||||
}
|
}
|
||||||
inner.append(&integration_group);
|
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
|
// Runtime Compatibility group
|
||||||
let compat_group = adw::PreferencesGroup::builder()
|
let compat_group = adw::PreferencesGroup::builder()
|
||||||
.title("Compatibility")
|
.title("Compatibility")
|
||||||
|
|||||||
@@ -184,6 +184,14 @@ fn start_update(
|
|||||||
dialog.set_body(&success_body);
|
dialog.set_body(&success_body);
|
||||||
dialog.set_response_enabled("update", false);
|
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
|
// Handle old version cleanup
|
||||||
if let Some(old_path) = applied.old_path_backup {
|
if let Some(old_path) = applied.old_path_backup {
|
||||||
handle_old_version_cleanup(&dialog, old_path);
|
handle_old_version_cleanup(&dialog, old_path);
|
||||||
|
|||||||
Reference in New Issue
Block a user