summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/List.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Propellor/Property/List.hs')
-rw-r--r--src/Propellor/Property/List.hs63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/Propellor/Property/List.hs b/src/Propellor/Property/List.hs
new file mode 100644
index 00000000..283c5ec7
--- /dev/null
+++ b/src/Propellor/Property/List.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Propellor.Property.List (
+ PropertyList(..),
+ PropertyListType,
+) where
+
+import Propellor.Types
+import Propellor.Engine
+import Propellor.PropAccum
+
+import Data.Monoid
+
+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 propigate 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 "foo" $ props
+ -- > & someproperty
+ -- > ! oldproperty
+ -- > & otherproperty
+ 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 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 PropList where
+ propertyList desc = propertyList desc . getProperties
+ combineProperties desc = combineProperties desc . getProperties
+
+combineSatisfy :: [Property i] -> Result -> Propellor Result
+combineSatisfy [] rs = return rs
+combineSatisfy (l:ls) rs = do
+ r <- ensureProperty $ ignoreInfo l
+ case r of
+ FailedChange -> return FailedChange
+ _ -> combineSatisfy ls (r <> rs)