From: Iustin Pop <ius...@google.com> This started from the fact that recent QuickCheck declares itself an arbitrary instance "(Arbitrary a) => Arbitrary (Set a)", which conflicts with our slightly more specific instance. The easiest way to fix this is (especially since this is test code) an OverlappingInstances language extension, but that is deprecated in GHC 7.10 :(
The solution is then to change this to a proper type, instead of an alias. In the exercise, I found out that we were not really using TagSet, but instead directly using Set, which is not nice. Plus many redefinitions at the call site of the same arbitrary instance! Not happy with type synonims since they're just smoke and mirrors… Signed-off-by: Iustin Pop <ius...@google.com> --- src/Ganeti/Objects.hs | 12 ++++++------ src/Ganeti/Objects/Lens.hs | 3 +-- src/Ganeti/THH/Field.hs | 18 ++++++++++++++---- src/Ganeti/Types.hs | 5 ++--- src/Ganeti/WConfd/Ssconf.hs | 2 +- test/hs/Test/Ganeti/Objects.hs | 12 ++++++------ test/hs/Test/Ganeti/Query/Instance.hs | 3 +-- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/Ganeti/Objects.hs b/src/Ganeti/Objects.hs index 603f809..00bb7a2 100644 --- a/src/Ganeti/Objects.hs +++ b/src/Ganeti/Objects.hs @@ -80,11 +80,12 @@ module Ganeti.Objects , Cluster(..) , ConfigData(..) , TimeStampObject(..) -- re-exported from Types - , UuidObject(..) -- re-exported from Types - , SerialNoObject(..) -- re-exported from Types - , TagsObject(..) -- re-exported from Types - , DictObject(..) -- re-exported from THH - , TagSet -- re-exported from THH + , UuidObject(..) -- re-exported from Types + , SerialNoObject(..) -- re-exported from Types + , TagsObject(..) -- re-exported from Types + , DictObject(..) -- re-exported from THH + , TagSet(..) -- re-exported from THH + , emptyTagSet -- re-exported from THH , Network(..) , AddressPool(..) , Ip4Address() @@ -749,4 +750,3 @@ $(buildObject "MasterNetworkParameters" "masterNetworkParameters" , simpleField "netdev" [t| String |] , simpleField "ip_family" [t| IpFamily |] ]) - diff --git a/src/Ganeti/Objects/Lens.hs b/src/Ganeti/Objects/Lens.hs index 3f27981..8b8da74 100644 --- a/src/Ganeti/Objects/Lens.hs +++ b/src/Ganeti/Objects/Lens.hs @@ -40,7 +40,6 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.UTF8 as UTF8 import Control.Lens (Simple) import Control.Lens.Iso (Iso, iso) -import qualified Data.Set as Set import System.Time (ClockTime(..)) import Ganeti.Lens (makeCustomLenses, Lens') @@ -64,7 +63,7 @@ class SerialNoObject a => SerialNoObjectL a where -- | Class of objects that have tags. class TagsObject a => TagsObjectL a where - tagsL :: Lens' a (Set.Set String) + tagsL :: Lens' a (TagSet) $(makeCustomLenses ''AddressPool) diff --git a/src/Ganeti/THH/Field.hs b/src/Ganeti/THH/Field.hs index 6047ca4..2dea7f7 100644 --- a/src/Ganeti/THH/Field.hs +++ b/src/Ganeti/THH/Field.hs @@ -43,7 +43,8 @@ module Ganeti.THH.Field , timeStampFields , uuidFields , serialFields - , TagSet + , TagSet(..) + , emptyTagSet , tagsFields , fileModeAsIntField , processIdField @@ -121,12 +122,21 @@ serialFields = uuidFields :: [Field] uuidFields = [ presentInForthcoming $ simpleField "uuid" [t| BS.ByteString |] ] --- | Tag set type alias. -type TagSet = Set.Set String +-- | Tag set type. +newtype TagSet = TagSet { fromTagSet :: Set.Set String } + deriving (Show, Eq) + +instance JSON.JSON TagSet where + readJSON = liftM TagSet . JSON.readJSON + showJSON = JSON.showJSON . fromTagSet + +-- | The empty tag set. +emptyTagSet :: TagSet +emptyTagSet = TagSet Set.empty -- | Tag field description. tagsFields :: [Field] -tagsFields = [ defaultField [| Set.empty |] $ +tagsFields = [ defaultField [| emptyTagSet |] $ simpleField "tags" [t| TagSet |] ] -- ** Fields related to POSIX data types diff --git a/src/Ganeti/Types.hs b/src/Ganeti/Types.hs index 437e62a..c332ba0 100644 --- a/src/Ganeti/Types.hs +++ b/src/Ganeti/Types.hs @@ -197,12 +197,12 @@ import Control.Monad (liftM) import qualified Text.JSON as JSON import Text.JSON (JSON, readJSON, showJSON) import Data.Ratio (numerator, denominator) -import qualified Data.Set as Set import System.Time (ClockTime) import qualified Ganeti.ConstantUtils as ConstantUtils import Ganeti.JSON import qualified Ganeti.THH as THH +import qualified Ganeti.THH.Field as THH (TagSet) import Ganeti.Utils -- * Generic types @@ -1071,5 +1071,4 @@ class SerialNoObject a where -- | Class of objects that have tags. class TagsObject a where - tagsOf :: a -> Set.Set String - + tagsOf :: a -> THH.TagSet diff --git a/src/Ganeti/WConfd/Ssconf.hs b/src/Ganeti/WConfd/Ssconf.hs index b8c83c0..941733d 100644 --- a/src/Ganeti/WConfd/Ssconf.hs +++ b/src/Ganeti/WConfd/Ssconf.hs @@ -88,7 +88,7 @@ mkSSConfHvparams cluster = map (id &&& hvparams) [minBound..maxBound] mkSSConf :: ConfigData -> SSConf mkSSConf cdata = SSConf . M.fromList $ [ (SSClusterName, return $ clusterClusterName cluster) - , (SSClusterTags, toList $ tagsOf cluster) + , (SSClusterTags, toList . fromTagSet $ tagsOf cluster) , (SSFileStorageDir, return $ clusterFileStorageDir cluster) , (SSSharedFileStorageDir, return $ clusterSharedFileStorageDir cluster) , (SSGlusterStorageDir, return $ clusterGlusterStorageDir cluster) diff --git a/test/hs/Test/Ganeti/Objects.hs b/test/hs/Test/Ganeti/Objects.hs index ea17bc0..49cfb64 100644 --- a/test/hs/Test/Ganeti/Objects.hs +++ b/test/hs/Test/Ganeti/Objects.hs @@ -127,7 +127,7 @@ instance Arbitrary Node where <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> fmap UTF8.fromString genUUID <*> arbitrary - <*> (Set.fromList <$> genTags) + <*> arbitrary -- TagSet $(genArbitrary ''BlockDriver) @@ -218,7 +218,7 @@ instance Arbitrary ForthcomingInstanceData where -- serial <*> arbitrary -- tags - <*> (Set.fromList <$> genTags) + <*> arbitrary instance Arbitrary RealInstanceData where arbitrary = @@ -259,7 +259,7 @@ instance Arbitrary RealInstanceData where -- serial <*> arbitrary -- tags - <*> (Set.fromList <$> genTags) + <*> arbitrary instance Arbitrary Instance where arbitrary = frequency [ (1, ForthcomingInstance <$> arbitrary) @@ -367,7 +367,7 @@ instance Arbitrary ClusterBeParams where arbitrary = (GenericContainer . Map.fromList) <$> arbitrary instance Arbitrary TagSet where - arbitrary = Set.fromList <$> genTags + arbitrary = TagSet . Set.fromList <$> genTags instance Arbitrary IAllocatorParams where arbitrary = return $ GenericContainer Map.empty @@ -462,7 +462,7 @@ genValidNetwork = do ctime <- arbitrary mtime <- arbitrary let n = Network name mac_prefix (mkIp4Network net netmask) net6 gateway - gateway6 res ext_res uuid ctime mtime 0 Set.empty + gateway6 res ext_res uuid ctime mtime 0 emptyTagSet return n -- | Generate an arbitrary string consisting of '0' and '1' of the given length. @@ -706,7 +706,7 @@ genNodeGroup = do mtime <- arbitrary uuid <- genFQDN `suchThat` (/= name) serial <- arbitrary - tags <- Set.fromList <$> genTags + tags <- arbitrary let group = NodeGroup name members ndparams alloc_policy ipolicy diskparams net_map hv_state disk_state ctime mtime (UTF8.fromString uuid) serial tags diff --git a/test/hs/Test/Ganeti/Query/Instance.hs b/test/hs/Test/Ganeti/Query/Instance.hs index 6a961c4..b095ba8 100644 --- a/test/hs/Test/Ganeti/Query/Instance.hs +++ b/test/hs/Test/Ganeti/Query/Instance.hs @@ -40,7 +40,6 @@ module Test.Ganeti.Query.Instance import qualified Data.ByteString.UTF8 as UTF8 import qualified Data.Map as Map -import qualified Data.Set as Set import System.Time (ClockTime(..)) import Ganeti.JSON @@ -64,7 +63,7 @@ createInstance name pnodeUuid adminState adminStateSource = (PartialBeParams Nothing Nothing Nothing Nothing Nothing Nothing) (GenericContainer Map.empty) (GenericContainer Map.empty) adminState adminStateSource [] [] False Nothing epochTime epochTime - (UTF8.fromString "") 0 Set.empty + (UTF8.fromString "") 0 emptyTagSet where epochTime = TOD 0 0 -- | A fake InstanceInfo to be used to check values. -- 2.8.1