{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Distribution.Nixpkgs.Haskell.FromCabal.Configuration ( Configuration(..), readConfiguration, assertConsistency ) where import Prelude hiding ( fail ) import Control.DeepSeq import Control.Exception ( throwIO ) import Control.Lens import Control.Monad hiding ( fail ) import Control.Monad.Fail import Data.Aeson import Data.Map as Map import Data.Set as Set import Data.Text as T import Data.Yaml import Distribution.Compiler import Distribution.Nixpkgs.Haskell.Constraint import Distribution.Package import Distribution.System import GHC.Generics ( Generic ) import Language.Nix.Identifier data Configuration = Configuration { -- |Target compiler. Used by 'finalizePackageDescription' to choose -- appropriate flags and dependencies. compilerInfo :: CompilerInfo -- |Compiler core packages that are also found on Hackage. , corePackages :: Set PackageIdentifier -- |These packages replace the latest respective version during -- dependency resolution. , defaultPackageOverrides :: [Constraint] -- |These packages are added to the generated set, but the play no -- role during dependency resolution. , extraPackages :: [Constraint] -- |This information is used by the @hackage2nix@ utility to determine the -- 'maintainers' for a given Haskell package. , packageMaintainers :: Map Identifier (Set PackageName) -- |These packages (by design) don't support certain platforms. , unsupportedPlatforms :: Map PackageName (Set Platform) -- |These packages cannot be distributed by Hydra, i.e. because they have an -- unfree license or depend on other tools that cannot be distributed for -- some reason. , dontDistributePackages :: Set PackageName -- |We know that these packages won't compile, so we mark them as broken and -- also disable their meta.hydraPlatforms attribute to avoid cluttering our -- Hydra job with lots of failure messages. , brokenPackages :: [Constraint] } deriving (Show, Generic) instance NFData Configuration instance FromJSON Configuration where parseJSON (Object o) = Configuration <$> o .:? "compiler" .!= unknownCompilerInfo buildCompilerId NoAbiTag <*> o .:? "core-packages" .!= mempty <*> o .:? "default-package-overrides" .!= mempty <*> o .:? "extra-packages" .!= mempty <*> o .:? "package-maintainers" .!= mempty <*> o .:? "unsupported-platforms" .!= mempty <*> o .:? "dont-distribute-packages" .!= mempty <*> o .:? "broken-packages" .!= mempty parseJSON _ = error "invalid Configuration" instance FromJSON Identifier where parseJSON (String s) = pure (review ident (T.unpack s)) parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Nix identifier") instance FromJSONKey Identifier where fromJSONKey = FromJSONKeyText parseKey instance FromJSONKey PackageName where fromJSONKey = FromJSONKeyText parseKey parseKey :: FromJSON k => Text -> k parseKey s = either error id (parseEither parseJSON (String s)) readConfiguration :: FilePath -> IO Configuration readConfiguration path = decodeFileEither path >>= either throwIO assertConsistency assertConsistency :: MonadFail m => Configuration -> m Configuration assertConsistency cfg@Configuration {..} = do let report msg = fail ("*** configuration error: " ++ msg) maintainedPackages = Set.unions (Map.elems packageMaintainers) disabledPackages = dontDistributePackages `Set.union` Set.fromList (depPkgName <$> brokenPackages) disabledMaintainedPackages = maintainedPackages `Set.intersection` disabledPackages unless (Set.null disabledMaintainedPackages) $ report ("disabled packages that have a maintainer: " ++ show disabledMaintainedPackages) return cfg