diff options
| -rw-r--r-- | doc/todo/differential_update_via_RevertableProperty.mdwn | 93 |
1 files changed, 93 insertions, 0 deletions
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. + +<pre> +appendfoo f = WriteFile f (ListAppend "foo" (ReadFile f)) +</pre> + +(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. + +<pre> +{-# 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 +</pre> |
