From d98892b0452499284fc577388cf8045af0ffa071 Mon Sep 17 00:00:00 2001
From: renoseven <dev@renoseven.net>
Date: Thu, 17 Oct 2024 22:24:21 +0800
Subject: [PATCH] syscared: support saving & restoring patch status by
 operation order

Signed-off-by: renoseven <dev@renoseven.net>
---
 syscared/Cargo.toml           |  2 +-
 syscared/src/patch/manager.rs | 84 ++++++++++++-----------------------
 2 files changed, 30 insertions(+), 56 deletions(-)

diff --git a/syscared/Cargo.toml b/syscared/Cargo.toml
index 1bfd43f..2eecea8 100644
--- a/syscared/Cargo.toml
+++ b/syscared/Cargo.toml
@@ -16,7 +16,7 @@ clap               = { version = "3.2", features = ["cargo", "derive"] }
 daemonize          = { version = "0.5" }
 flexi_logger       = { version = "0.24", features = ["compress"] }
 inotify            = { version = "0.9" }
-indexmap           = { version = "1.9" }
+indexmap           = { version = "1.9", features = ["serde"] }
 jsonrpc-core       = { version = "18.0" }
 jsonrpc-derive     = { version = "18.0" }
 jsonrpc-ipc-server = { version = "18.0" }
diff --git a/syscared/src/patch/manager.rs b/syscared/src/patch/manager.rs
index a17703c..48c583a 100644
--- a/syscared/src/patch/manager.rs
+++ b/syscared/src/patch/manager.rs
@@ -13,8 +13,6 @@
  */
 
 use std::{
-    cmp::Ordering,
-    collections::HashMap,
     path::{Path, PathBuf},
     str::FromStr,
     sync::Arc,
@@ -221,19 +219,16 @@ impl PatchManager {
     pub fn save_patch_status(&mut self) -> Result<()> {
         info!("Saving all patch status...");
 
-        debug!("Updating all patch status...");
+        debug!("Updating patch status...");
         for patch in self.get_patch_list() {
-            debug!("Update patch '{}' status", patch);
             self.get_patch_status(&patch)?;
         }
 
-        let mut status_map = HashMap::new();
+        debug!("Writing patch status...");
         for (uuid, status) in &self.status_map {
-            status_map.insert(uuid, status);
+            debug!("Patch '{}' status: {}", uuid, status);
         }
-
-        debug!("Writing patch status file");
-        serde::serialize(&status_map, &self.patch_status_file)
+        serde::serialize(&self.status_map, &self.patch_status_file)
             .context("Failed to write patch status file")?;
 
         fs::sync();
@@ -244,57 +239,35 @@ impl PatchManager {
 
     pub fn restore_patch_status(&mut self, accepted_only: bool) -> Result<()> {
         info!("Restoring all patch status...");
+        if !self.patch_status_file.exists() {
+            return Ok(());
+        }
 
         debug!("Reading patch status...");
-        let status_file = &self.patch_status_file;
-        let status_map: HashMap<Uuid, PatchStatus> = if status_file.exists() {
-            serde::deserialize(status_file).context("Failed to read patch status")?
-        } else {
-            warn!("Cannot find patch status file");
-            return Ok(());
-        };
+        let status_map: IndexMap<Uuid, PatchStatus> =
+            serde::deserialize(&self.patch_status_file).context("Failed to read patch status")?;
+        for (uuid, status) in &status_map {
+            debug!("Patch '{}' status: {}", uuid, status);
+        }
 
-        /*
-         * To ensure that we won't load multiple patches for same target at the same time,
-         * we take a sort operation of the status to make sure do REMOVE operation at first
-         */
-        let mut restore_list = status_map
+        let restore_list = status_map
             .into_iter()
-            .filter_map(|(uuid, status)| match self.find_patch_by_uuid(&uuid) {
+            .filter(|(_, status)| !accepted_only || (*status == PatchStatus::Accepted));
+        for (uuid, status) in restore_list {
+            match self.find_patch_by_uuid(&uuid) {
                 Ok(patch) => {
-                    if accepted_only && (status != PatchStatus::Accepted) {
-                        debug!(
-                            "Skipped patch '{}', status is not '{}'",
-                            patch,
-                            PatchStatus::Accepted
-                        );
-                        return None;
+                    debug!("Restore patch '{}' status to '{}'", patch, status);
+                    if let Err(e) = self.do_status_transition(&patch, status, PatchOpFlag::Force) {
+                        error!("{}", e);
                     }
-                    Some((patch, status))
                 }
                 Err(e) => {
-                    error!("{:?}", e);
-                    None
+                    error!("{}", e);
                 }
-            })
-            .collect::<Vec<_>>();
-
-        restore_list.sort_by(|(lhs_patch, lhs_status), (rhs_patch, rhs_status)| {
-            match lhs_status.cmp(rhs_status) {
-                Ordering::Less => Ordering::Less,
-                Ordering::Equal => lhs_patch.cmp(rhs_patch),
-                Ordering::Greater => Ordering::Greater,
-            }
-        });
-
-        for (patch, target_status) in restore_list {
-            debug!("Restore patch '{}' status to '{}'", patch, target_status);
-            if let Err(e) = self.do_status_transition(&patch, target_status, PatchOpFlag::Force) {
-                error!("{}", e);
             }
         }
-        info!("All patch status were restored");
 
+        info!("All patch status were restored");
         Ok(())
     }
 
@@ -426,13 +399,14 @@ impl PatchManager {
             bail!("Cannot set patch '{}' status to '{}'", patch, value);
         }
 
-        let status_map = &mut self.status_map;
-        match status_map.get_mut(patch.uuid()) {
-            Some(status) => {
-                *status = value;
-            }
-            None => {
-                status_map.insert(*patch.uuid(), value);
+        let (index, _) = self.status_map.insert_full(*patch.uuid(), value);
+        if let Some(last_index) = self
+            .status_map
+            .last()
+            .and_then(|(key, _)| self.status_map.get_index_of(key))
+        {
+            if index != last_index {
+                self.status_map.move_index(index, last_index);
             }
         }
 
-- 
2.34.1

