From 83f7e1ccb34001cbc3c60ba5a6693f65e7abc880 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 13 Jul 2017 20:28:45 -0400 Subject: idea --- ...differential_update_via_RevertableProperty.mdwn | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 doc/todo/differential_update_via_RevertableProperty.mdwn diff --git a/doc/todo/differential_update_via_RevertableProperty.mdwn b/doc/todo/differential_update_via_RevertableProperty.mdwn new file mode 100644 index 00000000..79afebe4 --- /dev/null +++ b/doc/todo/differential_update_via_RevertableProperty.mdwn @@ -0,0 +1,93 @@ +Long ago, nomeata pointed out that RevertableProperty required the user to +keep track of different versions of a Host, in a way that should be able to +be automated. When the user decides to revert a RevertableProperty, they +have to keep the reverted property on the Host until propellor runs there, +and only then can remove it. + +What if instead, there was a way to store the old version of a Host +somewhere. Let's not worry about where or how, but assume we have +`(old, new) :: (Host, Host)` + +Propellor could compare `old` and `new`, and if it finds a +RevertableProperty in `old` that is not in `new`, add it in reverted form +to `new'`. + +Also, if propellor finds a Property in `old` that is not in `new`, it can +tell the user that this Property needs to be reverted, but cannot be, so +`new` won't fully describe the state of the host. --[[Joey]] + +---- + +There are a lot of ways such a capability could be used, especially if +there were a way to pull the old version of a Host out of a previous +version of config.hs or something like that. But leaving aside such magic, +here are some nice use cases: + +* Suppose we want to generate several disk images, which are somewhat + similar, but differ in some properties. Rather than building a separate + chroot for each, we can build a chroot for the first, update the first + disk image, compare that with the second and update the chroot + accordingly, and so on. +* When propellor is used to build a OS installer disk image, that installer + could know the properties used to create it, and the properties of the + system that is desired to be installed. To install, it can rsync the + installer disk contents to `/target` and then run propellor in `/target`, + differentially updating it as needed. + +---- + +Here's the catch: It can't be implemented currently! The comparison of +properties needs an `Eq` instance for Property (and RevertableProperty). +But, a property contains an action in the IO monad, which can't have an +`Eq` instance, and so there's no good way to compare properties. + +Making propellor use an ESDL could get us `Eq`. But it would make it rather +clumsy to write properties, something like this. + +
+appendfoo f = WriteFile f (ListAppend "foo" (ReadFile f))
+
+ +(Perhaps a deeply embedded DSL would be better.) + +Could a Free monad get us `Eq`? Well, there can apparently be free monads that +have an `Eq` instance, but I tried building one for a simple teletype, and +failed, which does not bode well. Here's the code; this fails to compile +because of a missing instance `(Eq1 ((->) String))`, and of course comparing +functions for equality is not generally feasible. + +
+{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
+
+import Control.Monad.Free
+import Prelude.Extras
+
+data TeletypeF x
+        = PutStrLn String x
+        | GetLine (String -> x)
+
+instance Functor TeletypeF where
+        fmap f (PutStrLn str x) = PutStrLn str (f x)
+        fmap f (GetLine k) = GetLine (f . k)
+
+instance (Eq1 ((->) String)) => Eq1 TeletypeF  where
+        PutStrLn a x ==# PutStrLn b y = a == b && x == y
+        GetLine a ==# GetLine b = a ==# b
+
+type Teletype = Free TeletypeF
+
+putStrLn' :: String -> Teletype ()
+putStrLn' str = liftF $ PutStrLn str ()
+
+getLine' :: Teletype String
+getLine' = liftF $ GetLine id
+
+foo :: Teletype ()
+foo = do
+        putStrLn' "name?"
+        name <- getLine'
+        putStrLn' ("hello, " ++ name)
+
+fooisfoo :: Bool
+fooisfoo = foo ==# foo
+
-- cgit v1.2.3