From 79a39e98c93f691892faabebfb59ed23e4be79a4 Mon Sep 17 00:00:00 2001
From: George Kiagiadakis <george.kiagiadakis@collabora.com>
Date: Sun, 29 Mar 2020 12:36:19 +0300
Subject: [PATCH] transition: call execute_step() with _STEP_ERROR in error
 conditions

This allows the implementation to rollback changes, cancel jobs, etc
---
 lib/wp/session-item.c       | 19 +++++++++++++++++--
 lib/wp/transition.c         |  9 +++++++++
 modules/module-si-adapter.c |  4 +++-
 tests/wp/transition.c       | 12 ++++++++----
 4 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/lib/wp/session-item.c b/lib/wp/session-item.c
index d23c806e..f2e2d6d1 100644
--- a/lib/wp/session-item.c
+++ b/lib/wp/session-item.c
@@ -125,6 +125,21 @@ wp_session_item_default_get_next_step (WpSessionItem * self,
   return WP_TRANSITION_STEP_NONE;
 }
 
+static void
+wp_session_item_default_execute_step (WpSessionItem * self,
+    WpTransition * transition, guint step)
+{
+  switch (step) {
+  case WP_TRANSITION_STEP_NONE:
+    break;
+  case WP_TRANSITION_STEP_ERROR:
+    wp_session_item_reset (self);
+    break;
+  default:
+    g_return_if_reached ();
+  }
+}
+
 static void
 wp_session_item_default_reset (WpSessionItem * self)
 {
@@ -222,9 +237,9 @@ wp_session_item_class_init (WpSessionItemClass * klass)
   object_class->dispose = wp_session_item_dispose;
   object_class->finalize = wp_session_item_finalize;
 
-  klass->reset = wp_session_item_default_reset;
-
   klass->get_next_step = wp_session_item_default_get_next_step;
+  klass->execute_step = wp_session_item_default_execute_step;
+  klass->reset = wp_session_item_default_reset;
   klass->export = wp_session_item_default_export;
   klass->export_finish = wp_session_item_default_export_finish;
   klass->unexport = wp_session_item_default_unexport;
diff --git a/lib/wp/transition.c b/lib/wp/transition.c
index 24311893..03e8d15c 100644
--- a/lib/wp/transition.c
+++ b/lib/wp/transition.c
@@ -367,6 +367,10 @@ wp_transition_return (WpTransition * self, WpTransitionPrivate *priv)
  * When #WpTransitionClass.get_next_step() returns %WP_TRANSITION_STEP_ERROR,
  * this function calls wp_transition_return_error(), unless it has already been
  * called directly by #WpTransitionClass.get_next_step().
+ *
+ * In error conditions, #WpTransitionClass.execute_step() is called once with
+ * @step being %WP_TRANSITION_STEP_ERROR, allowing the implementation to
+ * rollback any changes or cancel underlying jobs, if necessary.
  */
 void
 wp_transition_advance (WpTransition * self)
@@ -434,6 +438,11 @@ wp_transition_return_error (WpTransition * self, GError * error)
 
   priv->step = WP_TRANSITION_STEP_ERROR;
   priv->error = error;
+
+  /* allow the implementation to rollback changes */
+  if (WP_TRANSITION_GET_CLASS (self)->execute_step)
+    WP_TRANSITION_GET_CLASS (self)->execute_step (self, priv->step);
+
   wp_transition_return (self, priv);
 }
 
diff --git a/modules/module-si-adapter.c b/modules/module-si-adapter.c
index 221f2601..dc3698d1 100644
--- a/modules/module-si-adapter.c
+++ b/modules/module-si-adapter.c
@@ -341,7 +341,9 @@ si_adapter_execute_step (WpSessionItem * item, WpTransition * transition,
       break;
     }
     default:
-      g_return_if_reached ();
+      WP_SESSION_ITEM_GET_CLASS (si_adapter_parent_class)->execute_step (item,
+          transition, step);
+      break;
   }
 }
 
diff --git a/tests/wp/transition.c b/tests/wp/transition.c
index 5b173641..949cb636 100644
--- a/tests/wp/transition.c
+++ b/tests/wp/transition.c
@@ -102,8 +102,10 @@ wp_test_transition_execute_step (WpTransition * transition, guint step)
   WpTestTransition * self = WP_TEST_TRANSITION (transition);
   struct data *d = wp_transition_get_data (transition);
 
-  g_assert_cmpint (step, >=, STEP_FIRST);
-  g_assert_cmpint (step, <=, STEP_FINISH);
+  if (step != WP_TRANSITION_STEP_ERROR) {
+    g_assert_cmpint (step, >=, STEP_FIRST);
+    g_assert_cmpint (step, <=, STEP_FINISH);
+  }
 
   g_assert_nonnull (d);
   g_assert_cmpint (d->ste_i, <, 10);
@@ -115,7 +117,8 @@ wp_test_transition_execute_step (WpTransition * transition, guint step)
     return;
   }
 
-  g_idle_add (advance_on_idle, transition);
+  if (step != WP_TRANSITION_STEP_ERROR)
+    g_idle_add (advance_on_idle, transition);
 }
 
 static void
@@ -260,7 +263,8 @@ test_transition_error (void)
   g_assert_cmpint (data.ste[0], ==, STEP_FIRST);
   g_assert_cmpint (data.ste[1], ==, STEP_SECOND);
   g_assert_cmpint (data.ste[2], ==, STEP_THIRD);
-  g_assert_cmpint (data.ste_i, ==, 3);
+  g_assert_cmpint (data.ste[3], ==, WP_TRANSITION_STEP_ERROR);
+  g_assert_cmpint (data.ste_i, ==, 4);
   g_assert_true (data.destroyed);
 }
 
-- 
GitLab