{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, Rank2Types, ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Development.Shake.Forward(
shakeForward, shakeArgsForward,
forwardOptions, forwardRule,
cache, cacheAction
) where
import Development.Shake
import Development.Shake.Rule
import Development.Shake.Command
import Development.Shake.Classes
import Development.Shake.FilePath
import Data.IORef
import Data.Either
import Data.List.Extra
import Control.Exception.Extra
import Numeric
import System.IO.Unsafe
import qualified Data.ByteString as BS
import qualified Data.HashMap.Strict as Map
{-# NOINLINE forwards #-}
forwards :: IORef (Map.HashMap ForwardQ (Action ()))
forwards = unsafePerformIO $ newIORef Map.empty
newtype ForwardQ = ForwardQ String
deriving (Hashable,Typeable,Eq,NFData,Binary)
type instance RuleResult ForwardQ = ()
instance Show ForwardQ where
show (ForwardQ x) = x
shakeForward :: ShakeOptions -> Action () -> IO ()
shakeForward opts act = shake (forwardOptions opts) (forwardRule act)
shakeArgsForward :: ShakeOptions -> Action () -> IO ()
shakeArgsForward opts act = shakeArgs (forwardOptions opts) (forwardRule act)
forwardRule :: Action () -> Rules ()
forwardRule act = do
addBuiltinRule noLint $ \k old dirty ->
case old of
Just old | not dirty -> return $ RunResult ChangedNothing old ()
_ -> do
res <- liftIO $ atomicModifyIORef forwards $ \mp -> (Map.delete k mp, Map.lookup k mp)
case res of
Nothing -> liftIO $ errorIO "Failed to find action name"
Just act -> act
return $ RunResult ChangedRecomputeSame BS.empty ()
action act
forwardOptions :: ShakeOptions -> ShakeOptions
forwardOptions opts = opts{shakeCommandOptions=[AutoDeps]}
cacheAction :: String -> Action () -> Action ()
cacheAction name action = do
let key = ForwardQ name
liftIO $ atomicModifyIORef forwards $ \mp -> (Map.insert key action mp, ())
_ :: [()] <- apply [key]
liftIO $ atomicModifyIORef forwards $ \mp -> (Map.delete key mp, ())
cache :: (forall r . CmdArguments r => r) -> Action ()
cache cmd = do
let CmdArgument args = cmd
let isDull ['-',x] = True; isDull _ = False
let name = head $ filter (not . isDull) (drop 1 $ rights args) ++ ["unknown"]
cacheAction ("command " ++ toStandard name ++ " #" ++ upper (showHex (abs $ hash $ show args) "")) cmd