b9-0.5.65: src/lib/B9/Shake/SharedImageRules.hs
-- | A crude, unsafe and preliminary solution to building B9 'SharedImage's
-- from Shake.
module B9.Shake.SharedImageRules
( customSharedImageAction
, needSharedImage
, enableSharedImageRules
) where
import B9
import qualified Data.Binary as Binary
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Builder as Builder
import Data.ByteString.Builder (stringUtf8)
import qualified Data.ByteString.Lazy as LazyByteString
import Development.Shake
import Development.Shake.Classes
import Development.Shake.Rule
-- | In order to use 'needSharedImage' and 'customSharedImageAction' you need to
-- call this action before using any of the aforementioned 'Rules'.
enableSharedImageRules :: B9ConfigOverride -> Rules ()
enableSharedImageRules b9inv = addBuiltinRule noLint sharedImageIdentity go
where
sharedImageIdentity :: BuiltinIdentity SharedImageName SharedImageBuildId
sharedImageIdentity (SharedImageName k) (SharedImageBuildId v) =
Just (LazyByteString.toStrict (Builder.toLazyByteString (stringUtf8 k <> stringUtf8 v)))
go :: BuiltinRun SharedImageName SharedImageBuildId
go nameQ mOldBIdBinary dependenciesChanged = do
mCurrentBId <- getImgBuildId
case mCurrentBId of
Just currentBId ->
let currentBIdBinary = encodeBuildId currentBId
in if dependenciesChanged == RunDependenciesChanged && mOldBIdBinary == Just currentBIdBinary
then return $ RunResult ChangedNothing currentBIdBinary currentBId
else rebuild (Just currentBIdBinary)
_ -> rebuild Nothing
where
getImgBuildId = liftIO (runB9ConfigActionWithOverrides (runLookupLocalSharedImage nameQ) b9inv)
encodeBuildId :: SharedImageBuildId -> ByteString.ByteString
encodeBuildId = LazyByteString.toStrict . Binary.encode
rebuild :: Maybe ByteString.ByteString -> Action (RunResult SharedImageBuildId)
rebuild mCurrentBIdBinary = do
(_, act) <- getUserRuleOne nameQ (const Nothing) imgMatch
act b9inv
mNewBId <- getImgBuildId
newBId <-
maybe
(error ("failed to get SharedImageBuildId for " ++ show nameQ ++ " in context of " ++ show b9inv))
return
mNewBId
let newBIdBinary = encodeBuildId newBId
let change =
if Just newBIdBinary == mCurrentBIdBinary
then ChangedRecomputeSame
else ChangedRecomputeDiff
return $ RunResult change newBIdBinary newBId
where
imgMatch (SharedImageCustomActionRule name mkImage) =
if name == nameQ
then Just mkImage
else Nothing
-- | Add a dependency to the creation of a 'SharedImage'. The build action
-- for the shared image must have been supplied by e.g. 'customSharedImageAction'.
-- NOTE: You must call 'enableSharedImageRules' before this action works.
needSharedImage :: SharedImageName -> Action SharedImageBuildId
needSharedImage = apply1
-- | Specify an arbitrary action that is supposed to build the given shared
-- image identified by a 'SharedImageName'.
-- NOTE: You must call 'enableSharedImageRules' before this action works.
customSharedImageAction :: SharedImageName -> Action () -> Rules ()
customSharedImageAction b9img customAction = addUserRule (SharedImageCustomActionRule b9img customAction')
where
customAction' b9inv = do
customAction
mCurrentBuildId <- liftIO (runB9ConfigActionWithOverrides (runLookupLocalSharedImage b9img) b9inv)
putLoud (printf "Finished custom action, for %s, build-id is: %s" (show b9img) (show mCurrentBuildId))
maybe (errorSharedImageNotFound b9img) return mCurrentBuildId
type instance RuleResult SharedImageName = SharedImageBuildId
data SharedImageCustomActionRule =
SharedImageCustomActionRule SharedImageName
(B9ConfigOverride -> Action SharedImageBuildId)
deriving (Typeable)
errorSharedImageNotFound :: Monad m => SharedImageName -> m a
errorSharedImageNotFound = fail . printf "Error: %s not found." . show