This commit is contained in:
Joey Hess 2014-12-07 18:49:42 -04:00
parent f692e1ceb2
commit 19a1d6b7ed
1 changed files with 50 additions and 21 deletions

View File

@ -1,7 +1,7 @@
Currently, Info about a Host's Properties is manually gathered and Currently, Info about a Host's Properties is manually gathered and
propigated. propertyList combines the Info of the Properties in the list. propigated. propertyList combines the Info of the Properties in the list;
Docker.docked extracts relevant Info from the Properties of the container Docker.docked extracts relevant Info from the Properties of the container
(but not al of it, intentionally!). (but not al of it, intentionally!); etc.
This works, but it's error-prone. Consider this example: This works, but it's error-prone. Consider this example:
@ -9,26 +9,55 @@ This works, but it's error-prone. Consider this example:
(Just (System (Debian Unstable) _)) -> ensureProperty foo (Just (System (Debian Unstable) _)) -> ensureProperty foo
_ -> ensureProperty bar _ -> ensureProperty bar
Here, the Info of `foo` is not propigated out. Nor is `bar`'s Info. Here, the Info of `foo` is not propigated out. Nor is `bar`'s Info. Of
Of course, only one of them will be run, and only its info should be propigated course, only one of them will be run, and only its info should be
out.. propigated out..
This commonly afflicts eg, privData. For example, `User.hasPassword'`
used to have this problem, which prevented --list-fields from listing privdata
that's not set from that property. (That was worked around.)
One approach might be to make the Propellor monad be able to be run in two One approach might be to make the Propellor monad be able to be run in two
modes. In one mode, it actually perform IO, etc. In the other mode, all 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 liftIO is a no-op, but all Info encountered is accumulated using a Reader.
monad. This might need two separate monad definitions. This might need two separate monad definitions.
That is surely doable, but the withOS example above shows a problem with it -- That is surely doable, but consider this example:
the OS is itself part of a Host's info, so won't be known until all its
properties have been examined for info!
Perhaps that can be finessed. We don't really need to propigate out OS info. property "demo" = do
Just DNS and PrivDataField Info. So info could be collected in 2 passes, needfoo <- liftIO checkFoo
first as it's done now by static propertyInfo values. Then take that if needfoo
and use it as the Info when running the Properties in the Reader monad. then ensureProperty foo
Combine what the Reader accumulates with the static info to get the full else ensureProperty bar
info.
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.
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
----
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..