{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveDataTypeable, ScopedTypeVariables #-}-- Allows the user to violate the functional dependency, but it has a runtime check so still safe{-# LANGUAGE UndecidableInstances #-}{-# LANGUAGE CPP #-}#if __GLASGOW_HASKELL__ >= 704{-# LANGUAGE ConstraintKinds #-}#endifmoduleDevelopment.Shake.Oracle(addOracle,askOracle,askOracleWith)whereimportDevelopment.Shake.CoreimportDevelopment.Shake.Classes-- Use should type names, since the names appear in the Haddock, and are too long if they are in fullnewtypeOracleQquestion=OracleQquestionderiving(Show,Typeable,Eq,Hashable,Binary,NFData)newtypeOracleAanswer=OracleAanswerderiving(Show,Typeable,Eq,Hashable,Binary,NFData)instance(#if __GLASGOW_HASKELL__ >= 704ShakeValueq,ShakeValuea#elseShowq,Typeableq,Eqq,Hashableq,Binaryq,NFDataq,Showa,Typeablea,Eqa,Hashablea,Binarya,NFDataa#endif)=>Rule(OracleQq)(OracleAa)wherestoredValue_=returnNothing-- | Add extra information which rules can depend on.-- An oracle is a function from a question type @q@, to an answer type @a@.-- As an example, we can define an oracle allowing you to depend on the current version of GHC:---- @-- newtype GhcVersion = GhcVersion () deriving (Show,Typeable,Eq,Hashable,Binary,NFData)-- rules = do-- 'addOracle' $ \\(GhcVersion _) -> fmap (last . words . fst) $ 'Development.Shake.systemOutput' \"ghc\" [\"--version\"]-- ... rules ...-- @---- If a rule calls @'askOracle' (GhcVersion ())@, that rule will be rerun whenever the GHC version changes.-- Some notes:---- * We define @GhcVersion@ with a @newtype@ around @()@, allowing the use of @GeneralizedNewtypeDeriving@.-- All the necessary type classes are exported from "Development.Shake.Classes".---- * Each call to 'addOracle' must use a different type of question.---- * Actions passed to 'addOracle' will be run in every build they are required,-- but if their value does not change they will not invalidate any rules depending on them.-- To get a similar behaviour using data stored in files, see 'Development.Shake.alwaysRerun'.---- * If the value returned by 'askOracle' is ignored then 'askOracleWith' may help avoid ambiguous type messages.-- Alternatively, use the result of 'addOracle', which is 'askOracle' restricted to the correct type.---- As a more complex example, consider tracking Haskell package versions:---- @--newtype GhcPkgList = GhcPkgList () deriving (Show,Typeable,Eq,Hashable,Binary,NFData)--newtype GhcPkgVersion = GhcPkgVersion String deriving (Show,Typeable,Eq,Hashable,Binary,NFData)----rules = do-- getPkgList \<- 'addOracle' $ \\GhcPkgList{} -> do-- (out,_) <- 'Development.Shake.systemOutput' \"ghc-pkg\" [\"list\",\"--simple-output\"]-- return [(reverse b, reverse a) | x <- words out, let (a,_:b) = break (== \'-\') $ reverse x]-- ---- getPkgVersion \<- 'addOracle' $ \\(GhcPkgVersion pkg) -> do-- pkgs <- getPkgList $ GhcPkgList ()-- return $ lookup pkg pkgs-- ---- \"myrule\" *> \\_ -> do-- getPkgVersion $ GhcPkgVersion \"shake\"-- ... rule using the shake version ...-- @---- Using these definitions, any rule depending on the version of @shake@-- should call @getPkgVersion $ GhcPkgVersion \"shake\"@ to rebuild when @shake@ is upgraded.addOracle::(#if __GLASGOW_HASKELL__ >= 704ShakeValueq,ShakeValuea#elseShowq,Typeableq,Eqq,Hashableq,Binaryq,NFDataq,Showa,Typeablea,Eqa,Hashablea,Binarya,NFDataa#endif)=>(q->Actiona)->Rules(q->Actiona)addOracleact=dorule$\(OracleQq)->Just$fmapOracleA$actqreturnaskOracle-- | Get information previously added with 'addOracle'. The question/answer types must match those provided-- to 'addOracle'.askOracle::(#if __GLASGOW_HASKELL__ >= 704ShakeValueq,ShakeValuea#elseShowq,Typeableq,Eqq,Hashableq,Binaryq,NFDataq,Showa,Typeablea,Eqa,Hashablea,Binarya,NFDataa#endif)=>q->ActionaaskOraclequestion=doOracleAanswer<-apply1$OracleQquestion;returnanswer-- | Get information previously added with 'addOracle'. The second argument is not used, but can-- be useful to fix the answer type, avoiding ambiguous type error messages.askOracleWith::(#if __GLASGOW_HASKELL__ >= 704ShakeValueq,ShakeValuea#elseShowq,Typeableq,Eqq,Hashableq,Binaryq,NFDataq,Showa,Typeablea,Eqa,Hashablea,Binarya,NFDataa#endif)=>q->a->ActionaaskOracleWithquestion_=askOraclequestion