diff options
| author | Joey Hess <joeyh@joeyh.name> | 2016-03-28 05:53:38 -0400 |
|---|---|---|
| committer | Joey Hess <joeyh@joeyh.name> | 2016-03-28 05:55:48 -0400 |
| commit | a1655d24bbb1db9caccdf93eae8110d746389ae2 (patch) | |
| tree | 66b6890d852c19daec2306920fecf9108e055273 /src/Propellor/Property/List.hs | |
| parent | ebf30061d8f8a251330070e69c2710fe4a8fd9da (diff) | |
type safe targets for properties
* Property types have been improved to indicate what systems they target.
This prevents using eg, Property FreeBSD on a Debian system.
Transition guide for this sweeping API change:
- Change "host name & foo & bar"
to "host name $ props & foo & bar"
- Similarly, `propertyList` and `combineProperties` need `props`
to be used to combine together properties; they no longer accept
lists of properties. (If you have such a list, use `toProps`.)
- And similarly, Chroot, Docker, and Systemd container need `props`
to be used to combine together the properies used inside them.
- The `os` property is removed. Instead use `osDebian`, `osBuntish`,
or `osFreeBSD`. These tell the type checker the target OS of a host.
- Change "Property NoInfo" to "Property UnixLike"
- Change "Property HasInfo" to "Property (HasInfo + UnixLike)"
- Change "RevertableProperty NoInfo" to
"RevertableProperty UnixLike UnixLike"
- Change "RevertableProperty HasInfo" to
"RevertableProperty (HasInfo + UnixLike) UnixLike"
- GHC needs {-# LANGUAGE TypeOperators #-} to use these fancy types.
This is enabled by default for all modules in propellor.cabal. But
if you are using propellor as a library, you may need to enable it
manually.
- If you know a property only works on a particular OS, like Debian
or FreeBSD, use that instead of "UnixLike". For example:
"Property Debian"
- It's also possible make a property support a set of OS's, for example:
"Property (Debian + FreeBSD)"
- Removed `infoProperty` and `simpleProperty` constructors, instead use
`property` to construct a Property.
- Due to the polymorphic type returned by `property`, additional type
signatures tend to be needed when using it. For example, this will
fail to type check, because the type checker cannot guess what type
you intend the intermediate property "go" to have:
foo :: Property UnixLike
foo = go `requires` bar
where
go = property "foo" (return NoChange)
To fix, specify the type of go:
go :: Property UnixLike
- `ensureProperty` now needs to be passed a witness to the type of the
property it's used in.
change this: foo = property desc $ ... ensureProperty bar
to this: foo = property' desc $ \w -> ... ensureProperty w bar
- General purpose properties like cmdProperty have type "Property UnixLike".
When using that to run a command only available on Debian, you can
tighten the type to only the OS that your more specific property works on.
For example:
upgraded :: Property Debian
upgraded = tightenTargets (cmdProperty "apt-get" ["upgrade"])
- Several utility functions have been renamed:
getInfo to fromInfo
propertyInfo to getInfo
propertyDesc to getDesc
propertyChildren to getChildren
* The new `pickOS` property combinator can be used to combine different
properties, supporting different OS's, into one Property that chooses
which to use based on the Host's OS.
* Re-enabled -O0 in propellor.cabal to reign in ghc's memory use handling
these complex new types.
* Added dependency on concurrent-output; removed embedded copy.
Diffstat (limited to 'src/Propellor/Property/List.hs')
| -rw-r--r-- | src/Propellor/Property/List.hs | 107 |
1 files changed, 40 insertions, 67 deletions
diff --git a/src/Propellor/Property/List.hs b/src/Propellor/Property/List.hs index 74aa6ca6..0eec04c7 100644 --- a/src/Propellor/Property/List.hs +++ b/src/Propellor/Property/List.hs @@ -1,86 +1,59 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE ScopedTypeVariables #-} module Propellor.Property.List ( props, - PropertyList(..), - PropertyListType, - PropList(..), + Props, + toProps, + propertyList, + combineProperties, ) where import Propellor.Types -import Propellor.Engine +import Propellor.Types.Core +import Propellor.Types.MetaTypes import Propellor.PropAccum +import Propellor.Engine +import Propellor.Exception import Data.Monoid --- | Starts accumulating a list of properties. +toProps :: [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes) +toProps ps = Props (map toChildProperty ps) + +-- | Combines a list of properties, resulting in a single property +-- that when run will run each property in the list in turn, +-- and print out the description of each as it's run. Does not stop +-- on failure; does propagate overall success/failure. +-- +-- For example: -- -- > propertyList "foo" $ props --- > & someproperty --- > ! oldproperty --- > & otherproperty -props :: PropList -props = PropList [] - -data PropList = PropList [Property HasInfo] - -instance PropAccum PropList where - PropList l `addProp` p = PropList (toProp p : l) - PropList l `addPropFront` p = PropList (l ++ [toProp p]) - getProperties (PropList l) = reverse l - -class PropertyList l where - -- | Combines a list of properties, resulting in a single property - -- that when run will run each property in the list in turn, - -- and print out the description of each as it's run. Does not stop - -- on failure; does propagate overall success/failure. - -- - -- Note that Property HasInfo and Property NoInfo are not the same - -- type, and so cannot be mixed in a list. To make a list of - -- mixed types, which can also include RevertableProperty, - -- use `props` - propertyList :: Desc -> l -> Property (PropertyListType l) - - -- | Combines a list of properties, resulting in one property that - -- ensures each in turn. Stops if a property fails. - combineProperties :: Desc -> l -> Property (PropertyListType l) - --- | Type level function to calculate whether a PropertyList has Info. -type family PropertyListType t -type instance PropertyListType [Property HasInfo] = HasInfo -type instance PropertyListType [Property NoInfo] = NoInfo -type instance PropertyListType [RevertableProperty NoInfo] = NoInfo -type instance PropertyListType [RevertableProperty HasInfo] = HasInfo -type instance PropertyListType PropList = HasInfo - -instance PropertyList [Property NoInfo] where - propertyList desc ps = simpleProperty desc (ensureProperties ps) ps - combineProperties desc ps = simpleProperty desc (combineSatisfy ps NoChange) ps - -instance PropertyList [Property HasInfo] where - -- It's ok to use ignoreInfo here, because the ps are made the - -- child properties of the property, and so their info is visible - -- that way. - propertyList desc ps = infoProperty desc (ensureProperties $ map ignoreInfo ps) mempty ps - combineProperties desc ps = infoProperty desc (combineSatisfy ps NoChange) mempty ps - -instance PropertyList [RevertableProperty HasInfo] where - propertyList desc ps = propertyList desc (map setupRevertableProperty ps) - combineProperties desc ps = combineProperties desc (map setupRevertableProperty ps) - -instance PropertyList [RevertableProperty NoInfo] where - propertyList desc ps = propertyList desc (map setupRevertableProperty ps) - combineProperties desc ps = combineProperties desc (map setupRevertableProperty ps) +-- > & bar +-- > & baz +propertyList :: SingI metatypes => Desc -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes) +propertyList desc (Props ps) = + property desc (ensureChildProperties cs) + `addChildren` cs + where + cs = map toChildProperty ps -instance PropertyList PropList where - propertyList desc = propertyList desc . getProperties - combineProperties desc = combineProperties desc . getProperties +-- | Combines a list of properties, resulting in one property that +-- ensures each in turn. Stops if a property fails. +combineProperties :: SingI metatypes => Desc -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes) +combineProperties desc (Props ps) = + property desc (combineSatisfy cs NoChange) + `addChildren` cs + where + cs = map toChildProperty ps -combineSatisfy :: [Property i] -> Result -> Propellor Result +combineSatisfy :: [ChildProperty] -> Result -> Propellor Result combineSatisfy [] rs = return rs -combineSatisfy (l:ls) rs = do - r <- ensureProperty $ ignoreInfo l +combineSatisfy (p:ps) rs = do + r <- catchPropellor $ getSatisfy p case r of FailedChange -> return FailedChange - _ -> combineSatisfy ls (r <> rs) + _ -> combineSatisfy ps (r <> rs) |
