propellor/doc/todo/info_propigation_out_of_nes...

106 lines
3.3 KiB
Plaintext
Raw Normal View History

2014-07-07 03:39:32 +00:00
Currently, Info about a Host's Properties is manually gathered and
2014-12-07 22:49:42 +00:00
propigated. propertyList combines the Info of the Properties in the list;
2014-07-07 03:39:32 +00:00
Docker.docked extracts relevant Info from the Properties of the container
2014-12-07 22:49:42 +00:00
(but not al of it, intentionally!); etc.
2014-07-07 03:39:32 +00:00
This works, but it's error-prone. Consider this example:
withOS desc $ \o -> case o of
(Just (System (Debian Unstable) _)) -> ensureProperty foo
_ -> ensureProperty bar
2014-12-07 22:49:42 +00:00
Here, the Info of `foo` is not propigated out. Nor is `bar`'s Info. Of
course, only one of them will be run, and only its info should be
propigated out..
2014-12-08 00:31:22 +00:00
2014-12-07 23:20:02 +00:00
----
Currently, ensureProperty detects if it's called on a property with a
non-empty Info, and prints a warning. Would prefer to handle this at the
type level though..
----
2014-12-06 20:15:08 +00:00
2014-07-07 03:39:32 +00:00
One approach might be to make the Propellor monad be able to be run in two
2014-12-07 22:49:42 +00:00
modes. In run mode, it actually performs IO, etc. In introspection mode, all
liftIO is a no-op, but all Info encountered is accumulated using a Reader.
This might need two separate monad definitions.
That is surely doable, but consider this example:
property "demo" = do
needfoo <- liftIO checkFoo
if needfoo
then ensureProperty foo
else ensureProperty bar
In introspection mode, the liftIO is a no-op, but needs to return a Bool.
That seems unlikely (how to pick which?), but even if some defaulting is
used, only one of foo or bar's info will be seen.
2014-12-07 23:20:02 +00:00
----
2014-12-07 22:49:42 +00:00
Another approach could be something like this:
withInfoFrom foo $ \callfoo ->
withInfoFrom bar $ \callbar ->
property "demo" = do
needfoo <- liftIO checkFoo
if needfoo
then callfoo
else callbar
Here withInfoFrom is able to add foo and bar's Info to the info of the
property that (may) call them.
This approach is not fully type safe; it would be possible to call
withInfoFrom in a way that didn't let it propigate the info.
Also it has the problem that it doesn't support this:
property "demo" = do
needfoo <- liftIO checkFoo
if needfoo
then do
foop <- liftIO getFooParam
ensureProperty (foo foop)
else ensureProperty bar
----
2014-12-07 23:20:02 +00:00
Another approach would be to add a new SimpleProperty, which is a property
that has no Info. Only allow calling ensureProperty on this new type.
(Or, remove propertyInfo from Property, and add a new InfoProperty that
has the info.)
2014-12-08 00:31:22 +00:00
But, propertyList can only contain one type at a time,
2014-12-07 23:20:02 +00:00
not a mixed list of Property and SimpleProperty.
Could a GADT be used instead?
{-# LANGUAGE GADTs #-}
{-# LANGUAGE EmptyDataDecls #-}
data HasInfo
data NoInfo
2014-12-08 00:31:22 +00:00
data Property = IProperty (GProperty HasInfo) | SProperty (GProperty NoInfo)
data GProperty i where
GIProperty :: Desc -> Propellor Result -> Info -> GProperty HasInfo
GSProperty :: Desc -> Propellor Result -> GProperty NoInfo
ensureProperty :: GProperty NoInfo -> Propellor Result
ensureProperty (GSProperty d r) = r
That works. I made a `gadtwip` git branch that elaborated on that,
to the point that Property.File compiles, but is otherwise
unfinished. Most definitions of `Property` need to be changed to
`GProperty NoInfo`, so that ensureProperty can call them. It's a big,
intrusive change, and it may complicate propellor too much.
2014-12-07 23:20:02 +00:00
2014-12-08 00:31:22 +00:00
(I may need to make instances of Prop for `GProperty NoInfo` and `GProperty
HasInfo`, if that's possible, and make more Property combinators work on
Prop.)