{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, TypeFamilies #-}-- | A module for parsing and using config files in a Shake build system. Config files-- consist of variable bindings, for example:---- > # This is my Config file-- > HEADERS_DIR = /path/to/dir-- > CFLAGS = -g -I${HEADERS_DIR}-- > CFLAGS = $CFLAGS -O2-- > include extra/file.cfg---- This defines the variable @HEADERS_DIR@ (equal to @\/path\/to\/dir@), and-- @CFLAGS@ (equal to @-g -I\/path\/to\/dir -O2@), and also includes the configuration-- statements in the file @extra/file.cfg@. The full lexical syntax for configuration-- files is defined here: <https://ninja-build.org/manual.html#_lexical_syntax>.-- The use of Ninja file syntax is due to convenience and the desire to reuse an-- externally-defined specification (but the choice of configuration language is mostly arbitrary).---- To use the configuration file either use 'readConfigFile' to parse the configuration file-- and use the values directly, or 'usingConfigFile' and 'getConfig' to track the configuration-- values, so they become build dependencies.moduleDevelopment.Shake.Config(readConfigFile ,readConfigFileWithEnv ,usingConfigFile ,usingConfig ,getConfig ,getConfigKeys )whereimportDevelopment.Shake importDevelopment.Shake.Classes importqualifiedDevelopment.Ninja.Parse asNinjaimportqualifiedDevelopment.Ninja.Env asNinjaimportqualifiedData.HashMap.StrictasMapimportqualifiedData.ByteString.UTF8asUTF8importControl.ApplicativeimportData.Tuple.ExtraimportData.ListimportPrelude-- | Read a config file, returning a list of the variables and their bindings.-- Config files use the Ninja lexical syntax:-- <https://ninja-build.org/manual.html#_lexical_syntax>readConfigFile::FilePath->IO(Map.HashMapStringString)readConfigFile =readConfigFileWithEnv []-- | Read a config file with an initial environment, returning a list of the variables and their bindings.-- Config files use the Ninja lexical syntax:-- <https://ninja-build.org/manual.html#_lexical_syntax>readConfigFileWithEnv::[(String,String)]->FilePath->IO(Map.HashMapStringString)readConfigFileWithEnv vars file =doenv <-Ninja.newEnv mapM_(uncurry(Ninja.addEnv env ).(UTF8.fromString***UTF8.fromString))vars Ninja.parse file env mp <-Ninja.fromEnv env return$Map.fromList$map(UTF8.toString***UTF8.toString)$Map.toListmp newtypeConfig =Config Stringderiving(Show,Typeable,Eq,Hashable,Binary,NFData)newtypeConfigKeys =ConfigKeys ()deriving(Show,Typeable,Eq,Hashable,Binary,NFData)typeinstanceRuleResult Config =MaybeStringtypeinstanceRuleResult ConfigKeys =[String]-- | Specify the file to use with 'getConfig'.usingConfigFile::FilePath->Rules ()usingConfigFile file =domp <-newCache $\()->doneed [file ]liftIO$readConfigFile file addOracle $\(Config x )->Map.lookupx <$>mp ()addOracle $\(ConfigKeys ())->sort.Map.keys<$>mp ()return()-- | Specify the values to use with 'getConfig', generally prefer-- 'usingConfigFile' unless you also need access to the values-- of variables outside 'Action'.usingConfig::Map.HashMapStringString->Rules ()usingConfig mp =doaddOracle $\(Config x )->return$Map.lookupx mp addOracle $\(ConfigKeys ())->return$sort$Map.keysmp return()-- | Obtain the value of a configuration variable, returns 'Nothing' to indicate the variable-- has no binding. Any build system using 'getConfig' /must/ call either 'usingConfigFile'-- or 'usingConfig'. The 'getConfig' function will introduce a dependency on the configuration-- variable (but not the whole configuration file), and if the configuration variable changes, the rule will be rerun.-- As an example:---- @-- 'usingConfigFile' \"myconfiguration.cfg\"-- \"*.o\" '%>' \\out -> do-- cflags <- 'getConfig' \"CFLAGS\"-- 'cmd' \"gcc\" [out '-<.>' \"c\"] (fromMaybe \"\" cflags)-- @getConfig::String->Action (MaybeString)getConfig =askOracle .Config -- | Obtain the configuration keys.-- Any build system using 'getConfigKeys' /must/ call either 'usingConfigFile' or 'usingConfig'.-- The 'getConfigKeys' function will introduce a dependency on the configuration keys-- (but not the whole configuration file), and if the configuration keys change, the rule will be rerun.-- Usually use as part of an action.-- As an example:---- @-- 'usingConfigFile' \"myconfiguration.cfg\"-- 'action' $ need =<< getConfigKeys-- @getConfigKeys::Action [String]getConfigKeys =askOracle $ConfigKeys ()