{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
module Clash.Driver.Manifest where
import Control.Exception (tryJust)
import Control.Monad (guard, forM)
import Control.Monad.State (evalState)
import qualified Crypto.Hash.SHA256 as Sha256
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Encode.Pretty as Aeson
import Data.Aeson
(ToJSON(toJSON), FromJSON(parseJSON), KeyValue ((.=)), (.:), (.:?))
import Data.Aeson.Types (Parser)
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Lazy as ByteStringLazy
import Data.ByteString (ByteString)
import Data.Hashable (hash)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Maybe (catMaybes)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.Text.Lazy as LText
import qualified Data.Text.Lazy.Encoding as LText
import Data.Text (Text)
import Data.Text.Prettyprint.Doc.Extra (renderOneLine)
import Data.Time (UTCTime)
import qualified Data.Set as Set
import Data.Semigroup.Monad (getMon)
import Data.String (IsString)
import System.IO.Error (isDoesNotExistError)
import System.FilePath (takeDirectory, (</>))
import System.Directory (listDirectory, doesFileExist)
import Text.Read (readMaybe)
import Clash.Annotations.TopEntity.Extra ()
import Clash.Backend (Backend (hdlType), Usage (External))
import Clash.Driver.Types
import Clash.Primitives.Types
import Clash.Core.Var (Id)
import Clash.Netlist.Types
(TopEntityT, Component(..), HWType (Clock), hwTypeDomain)
import qualified Clash.Netlist.Types as Netlist
import qualified Clash.Netlist.Id as Id
import Clash.Netlist.Util (typeSize)
import Clash.Primitives.Util (hashCompiledPrimMap)
import Clash.Signal (VDomainConfiguration(..))
import Clash.Util.Graph (callGraphBindings)
#if MIN_VERSION_ghc(9,0,0)
import GHC.Utils.Misc (OverridingBool(..))
#else
import Util (OverridingBool(..))
#endif
data ManifestPort = ManifestPort
{ ManifestPort -> Text
mpName :: Text
, ManifestPort -> Text
mpTypeName :: Text
, ManifestPort -> Int
mpWidth :: Int
, ManifestPort -> Bool
mpIsClock :: Bool
, ManifestPort -> Maybe Text
mpDomain :: Maybe Text
} deriving (Int -> ManifestPort -> ShowS
[ManifestPort] -> ShowS
ManifestPort -> String
(Int -> ManifestPort -> ShowS)
-> (ManifestPort -> String)
-> ([ManifestPort] -> ShowS)
-> Show ManifestPort
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ManifestPort] -> ShowS
$cshowList :: [ManifestPort] -> ShowS
show :: ManifestPort -> String
$cshow :: ManifestPort -> String
showsPrec :: Int -> ManifestPort -> ShowS
$cshowsPrec :: Int -> ManifestPort -> ShowS
Show,ReadPrec [ManifestPort]
ReadPrec ManifestPort
Int -> ReadS ManifestPort
ReadS [ManifestPort]
(Int -> ReadS ManifestPort)
-> ReadS [ManifestPort]
-> ReadPrec ManifestPort
-> ReadPrec [ManifestPort]
-> Read ManifestPort
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ManifestPort]
$creadListPrec :: ReadPrec [ManifestPort]
readPrec :: ReadPrec ManifestPort
$creadPrec :: ReadPrec ManifestPort
readList :: ReadS [ManifestPort]
$creadList :: ReadS [ManifestPort]
readsPrec :: Int -> ReadS ManifestPort
$creadsPrec :: Int -> ReadS ManifestPort
Read,ManifestPort -> ManifestPort -> Bool
(ManifestPort -> ManifestPort -> Bool)
-> (ManifestPort -> ManifestPort -> Bool) -> Eq ManifestPort
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ManifestPort -> ManifestPort -> Bool
$c/= :: ManifestPort -> ManifestPort -> Bool
== :: ManifestPort -> ManifestPort -> Bool
$c== :: ManifestPort -> ManifestPort -> Bool
Eq)
instance ToJSON ManifestPort where
toJSON :: ManifestPort -> Value
toJSON (ManifestPort{Bool
Int
Maybe Text
Text
mpDomain :: Maybe Text
mpIsClock :: Bool
mpWidth :: Int
mpTypeName :: Text
mpName :: Text
mpDomain :: ManifestPort -> Maybe Text
mpIsClock :: ManifestPort -> Bool
mpWidth :: ManifestPort -> Int
mpTypeName :: ManifestPort -> Text
mpName :: ManifestPort -> Text
..}) =
[Pair] -> Value
Aeson.object ([Pair] -> Value) -> [Pair] -> Value
forall a b. (a -> b) -> a -> b
$
[ Text
"name" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
mpName
, Text
"type_name" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
mpTypeName
, Text
"width" Text -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Int
mpWidth
, Text
"is_clock" Text -> Bool -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
mpIsClock
] [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<>
(case Maybe Text
mpDomain of
Just Text
dom -> [Text
"domain" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
dom]
Maybe Text
Nothing -> [] )
instance FromJSON ManifestPort where
parseJSON :: Value -> Parser ManifestPort
parseJSON = String
-> (Object -> Parser ManifestPort) -> Value -> Parser ManifestPort
forall a. String -> (Object -> Parser a) -> Value -> Parser a
Aeson.withObject String
"ManifestPort" ((Object -> Parser ManifestPort) -> Value -> Parser ManifestPort)
-> (Object -> Parser ManifestPort) -> Value -> Parser ManifestPort
forall a b. (a -> b) -> a -> b
$ \Object
v ->
Text -> Text -> Int -> Bool -> Maybe Text -> ManifestPort
ManifestPort
(Text -> Text -> Int -> Bool -> Maybe Text -> ManifestPort)
-> Parser Text
-> Parser (Text -> Int -> Bool -> Maybe Text -> ManifestPort)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"
Parser (Text -> Int -> Bool -> Maybe Text -> ManifestPort)
-> Parser Text
-> Parser (Int -> Bool -> Maybe Text -> ManifestPort)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"type_name"
Parser (Int -> Bool -> Maybe Text -> ManifestPort)
-> Parser Int -> Parser (Bool -> Maybe Text -> ManifestPort)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Int
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"width"
Parser (Bool -> Maybe Text -> ManifestPort)
-> Parser Bool -> Parser (Maybe Text -> ManifestPort)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Bool
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"is_clock"
Parser (Maybe Text -> ManifestPort)
-> Parser (Maybe Text) -> Parser ManifestPort
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"domain"
data Manifest
= Manifest
{ Manifest -> Int
manifestHash :: Int
, Manifest -> (Int, Int, Bool)
successFlags :: (Int,Int,Bool)
, Manifest -> [ManifestPort]
inPorts :: [ManifestPort]
, Manifest -> [ManifestPort]
outPorts :: [ManifestPort]
, Manifest -> [Text]
componentNames :: [Text]
, Manifest -> Text
topComponent :: Text
, Manifest -> [(String, ByteString)]
fileNames :: [(FilePath, ByteString)]
, Manifest -> HashMap Text VDomainConfiguration
domains :: HashMap Text VDomainConfiguration
} deriving (Int -> Manifest -> ShowS
[Manifest] -> ShowS
Manifest -> String
(Int -> Manifest -> ShowS)
-> (Manifest -> String) -> ([Manifest] -> ShowS) -> Show Manifest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Manifest] -> ShowS
$cshowList :: [Manifest] -> ShowS
show :: Manifest -> String
$cshow :: Manifest -> String
showsPrec :: Int -> Manifest -> ShowS
$cshowsPrec :: Int -> Manifest -> ShowS
Show,ReadPrec [Manifest]
ReadPrec Manifest
Int -> ReadS Manifest
ReadS [Manifest]
(Int -> ReadS Manifest)
-> ReadS [Manifest]
-> ReadPrec Manifest
-> ReadPrec [Manifest]
-> Read Manifest
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Manifest]
$creadListPrec :: ReadPrec [Manifest]
readPrec :: ReadPrec Manifest
$creadPrec :: ReadPrec Manifest
readList :: ReadS [Manifest]
$creadList :: ReadS [Manifest]
readsPrec :: Int -> ReadS Manifest
$creadsPrec :: Int -> ReadS Manifest
Read,Manifest -> Manifest -> Bool
(Manifest -> Manifest -> Bool)
-> (Manifest -> Manifest -> Bool) -> Eq Manifest
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Manifest -> Manifest -> Bool
$c/= :: Manifest -> Manifest -> Bool
== :: Manifest -> Manifest -> Bool
$c== :: Manifest -> Manifest -> Bool
Eq)
instance ToJSON Manifest where
toJSON :: Manifest -> Value
toJSON (Manifest{Int
[(String, ByteString)]
[Text]
[ManifestPort]
(Int, Int, Bool)
Text
HashMap Text VDomainConfiguration
domains :: HashMap Text VDomainConfiguration
fileNames :: [(String, ByteString)]
topComponent :: Text
componentNames :: [Text]
outPorts :: [ManifestPort]
inPorts :: [ManifestPort]
successFlags :: (Int, Int, Bool)
manifestHash :: Int
domains :: Manifest -> HashMap Text VDomainConfiguration
fileNames :: Manifest -> [(String, ByteString)]
topComponent :: Manifest -> Text
componentNames :: Manifest -> [Text]
outPorts :: Manifest -> [ManifestPort]
inPorts :: Manifest -> [ManifestPort]
successFlags :: Manifest -> (Int, Int, Bool)
manifestHash :: Manifest -> Int
..}) =
[Pair] -> Value
Aeson.object
[ Text
"version" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"unstable" :: Text)
, Text
"hash" Text -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Int
manifestHash
, Text
"flags" Text -> (Int, Int, Bool) -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Int, Int, Bool)
successFlags
, Text
"components" Text -> [Text] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Text]
componentNames
, Text
"top_component" Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Pair] -> Value
Aeson.object
[ Text
"name" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
topComponent
, Text
"ports_flat" Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Pair] -> Value
Aeson.object
[ Text
"in" Text -> [ManifestPort] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ManifestPort]
inPorts
, Text
"out" Text -> [ManifestPort] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ManifestPort]
outPorts ]
]
, Text
"files" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.=
[ [Pair] -> Value
Aeson.object
[ Text
"name" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String
fName
, Text
"sha256" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ByteString -> Text
Text.decodeUtf8 (ByteString -> ByteString
Base16.encode ByteString
fHash)
]
| (String
fName, ByteString
fHash) <- [(String, ByteString)]
fileNames]
, Text
"domains" Text -> Object -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Pair] -> Object
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
[ ( Text
domNm
, [Pair] -> Value
Aeson.object
[ Text
"period" Text -> Natural -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Natural
vPeriod
, Text
"active_edge" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ActiveEdge -> String
forall a. Show a => a -> String
show ActiveEdge
vActiveEdge
, Text
"reset_kind" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ResetKind -> String
forall a. Show a => a -> String
show ResetKind
vResetKind
, Text
"init_behavior" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= InitBehavior -> String
forall a. Show a => a -> String
show InitBehavior
vInitBehavior
, Text
"reset_polarity" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ResetPolarity -> String
forall a. Show a => a -> String
show ResetPolarity
vResetPolarity
]
)
| (Text
domNm, VDomainConfiguration{Natural
String
ActiveEdge
InitBehavior
ResetKind
ResetPolarity
vResetPolarity :: VDomainConfiguration -> ResetPolarity
vResetKind :: VDomainConfiguration -> ResetKind
vPeriod :: VDomainConfiguration -> Natural
vName :: VDomainConfiguration -> String
vInitBehavior :: VDomainConfiguration -> InitBehavior
vActiveEdge :: VDomainConfiguration -> ActiveEdge
vName :: String
vResetPolarity :: ResetPolarity
vInitBehavior :: InitBehavior
vResetKind :: ResetKind
vActiveEdge :: ActiveEdge
vPeriod :: Natural
..}) <- HashMap Text VDomainConfiguration -> [(Text, VDomainConfiguration)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap Text VDomainConfiguration
domains ]
]
instance FromJSON Manifest where
parseJSON :: Value -> Parser Manifest
parseJSON = String -> (Object -> Parser Manifest) -> Value -> Parser Manifest
forall a. String -> (Object -> Parser a) -> Value -> Parser a
Aeson.withObject String
"Manifest" ((Object -> Parser Manifest) -> Value -> Parser Manifest)
-> (Object -> Parser Manifest) -> Value -> Parser Manifest
forall a b. (a -> b) -> a -> b
$ \Object
v ->
let
topComponent :: Parser Object
topComponent = Object
v Object -> Text -> Parser Object
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"top_component"
portsFlat :: Parser Object
portsFlat = Parser Object
topComponent Parser Object -> (Object -> Parser Object) -> Parser Object
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Text -> Parser Object
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"ports_flat")
in
Int
-> (Int, Int, Bool)
-> [ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest
Manifest
(Int
-> (Int, Int, Bool)
-> [ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser Int
-> Parser
((Int, Int, Bool)
-> [ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Text -> Parser Int
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"hash"
Parser
((Int, Int, Bool)
-> [ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser (Int, Int, Bool)
-> Parser
([ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser (Int, Int, Bool)
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"flags"
Parser
([ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser [ManifestPort]
-> Parser
([ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (Parser Object
portsFlat Parser Object
-> (Object -> Parser [ManifestPort]) -> Parser [ManifestPort]
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Text -> Parser [ManifestPort]
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"in"))
Parser
([ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser [ManifestPort]
-> Parser
([Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (Parser Object
portsFlat Parser Object
-> (Object -> Parser [ManifestPort]) -> Parser [ManifestPort]
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Text -> Parser [ManifestPort]
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"out"))
Parser
([Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser [Text]
-> Parser
(Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser [Text]
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"components"
Parser
(Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest)
-> Parser Text
-> Parser
([(String, ByteString)]
-> HashMap Text VDomainConfiguration -> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (Parser Object
topComponent Parser Object -> (Object -> Parser Text) -> Parser Text
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"))
Parser
([(String, ByteString)]
-> HashMap Text VDomainConfiguration -> Manifest)
-> Parser [(String, ByteString)]
-> Parser (HashMap Text VDomainConfiguration -> Manifest)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> do
[Object]
files <- Object
v Object -> Text -> Parser [Object]
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"files"
[Object]
-> (Object -> Parser (String, ByteString))
-> Parser [(String, ByteString)]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Object]
files ((Object -> Parser (String, ByteString))
-> Parser [(String, ByteString)])
-> (Object -> Parser (String, ByteString))
-> Parser [(String, ByteString)]
forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
String
fName <- Object
obj Object -> Text -> Parser String
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"
Text
sha256 <- Object
obj Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"sha256"
#if MIN_VERSION_base16_bytestring(1,0,0)
(String, ByteString) -> Parser (String, ByteString)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (String
fName, ByteString -> ByteString
Base16.decodeLenient (Text -> ByteString
Text.encodeUtf8 Text
sha256))
#else
pure (fName, fst (Base16.decode (Text.encodeUtf8 sha256)))
#endif
Parser (HashMap Text VDomainConfiguration -> Manifest)
-> Parser (HashMap Text VDomainConfiguration) -> Parser Manifest
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (Object
v Object -> Text -> Parser (HashMap Text Object)
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"domains" Parser (HashMap Text Object)
-> (HashMap Text Object
-> Parser (HashMap Text VDomainConfiguration))
-> Parser (HashMap Text VDomainConfiguration)
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Text -> Object -> Parser VDomainConfiguration)
-> HashMap Text Object
-> Parser (HashMap Text VDomainConfiguration)
forall (f :: Type -> Type) k v1 v2.
Applicative f =>
(k -> v1 -> f v2) -> HashMap k v1 -> f (HashMap k v2)
HashMap.traverseWithKey Text -> Object -> Parser VDomainConfiguration
parseDomain)
where
parseDomain :: Text -> Aeson.Object -> Parser VDomainConfiguration
parseDomain :: Text -> Object -> Parser VDomainConfiguration
parseDomain Text
nm Object
v =
String
-> Natural
-> ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration
VDomainConfiguration
(String
-> Natural
-> ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration)
-> Parser String
-> Parser
(Natural
-> ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Parser String
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Text -> String
Text.unpack Text
nm)
Parser
(Natural
-> ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration)
-> Parser Natural
-> Parser
(ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (Object
v Object -> Text -> Parser Natural
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"period")
Parser
(ActiveEdge
-> ResetKind
-> InitBehavior
-> ResetPolarity
-> VDomainConfiguration)
-> Parser ActiveEdge
-> Parser
(ResetKind
-> InitBehavior -> ResetPolarity -> VDomainConfiguration)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Text -> Object -> Parser ActiveEdge
forall a. Read a => Text -> Object -> Parser a
parseWithRead Text
"active_edge" Object
v
Parser
(ResetKind
-> InitBehavior -> ResetPolarity -> VDomainConfiguration)
-> Parser ResetKind
-> Parser (InitBehavior -> ResetPolarity -> VDomainConfiguration)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Text -> Object -> Parser ResetKind
forall a. Read a => Text -> Object -> Parser a
parseWithRead Text
"reset_kind" Object
v
Parser (InitBehavior -> ResetPolarity -> VDomainConfiguration)
-> Parser InitBehavior
-> Parser (ResetPolarity -> VDomainConfiguration)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Text -> Object -> Parser InitBehavior
forall a. Read a => Text -> Object -> Parser a
parseWithRead Text
"init_behavior" Object
v
Parser (ResetPolarity -> VDomainConfiguration)
-> Parser ResetPolarity -> Parser VDomainConfiguration
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Text -> Object -> Parser ResetPolarity
forall a. Read a => Text -> Object -> Parser a
parseWithRead Text
"reset_polarity" Object
v
parseWithRead :: Read a => Text -> Aeson.Object -> Parser a
parseWithRead :: Text -> Object -> Parser a
parseWithRead Text
field Object
obj = do
Maybe String
v <- Object
obj Object -> Text -> Parser (Maybe String)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
field
case String -> Maybe a
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe a) -> Maybe String -> Maybe a
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe String
v of
Just a
a -> a -> Parser a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure a
a
Maybe a
Nothing -> String -> Parser a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> Parser a) -> String -> Parser a
forall a b. (a -> b) -> a -> b
$ String
"Could not read field: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack Text
field
data UnexpectedModification
= Modified FilePath
| Added FilePath
| Removed FilePath
deriving (Int -> UnexpectedModification -> ShowS
[UnexpectedModification] -> ShowS
UnexpectedModification -> String
(Int -> UnexpectedModification -> ShowS)
-> (UnexpectedModification -> String)
-> ([UnexpectedModification] -> ShowS)
-> Show UnexpectedModification
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnexpectedModification] -> ShowS
$cshowList :: [UnexpectedModification] -> ShowS
show :: UnexpectedModification -> String
$cshow :: UnexpectedModification -> String
showsPrec :: Int -> UnexpectedModification -> ShowS
$cshowsPrec :: Int -> UnexpectedModification -> ShowS
Show)
mkManifestPort ::
Backend backend =>
backend ->
Id.Identifier ->
HWType ->
ManifestPort
mkManifestPort :: backend -> Identifier -> HWType -> ManifestPort
mkManifestPort backend
backend Identifier
portId HWType
portType = ManifestPort :: Text -> Text -> Int -> Bool -> Maybe Text -> ManifestPort
ManifestPort{Bool
Int
Maybe Text
Text
mpTypeName :: Text
mpDomain :: Maybe Text
mpIsClock :: Bool
mpWidth :: Int
mpName :: Text
mpDomain :: Maybe Text
mpIsClock :: Bool
mpWidth :: Int
mpTypeName :: Text
mpName :: Text
..}
where
mpName :: Text
mpName = Identifier -> Text
Id.toText Identifier
portId
mpWidth :: Int
mpWidth = HWType -> Int
typeSize HWType
portType
mpIsClock :: Bool
mpIsClock = case HWType
portType of {Clock Text
_ -> Bool
True; HWType
_ -> Bool
False}
mpDomain :: Maybe Text
mpDomain = HWType -> Maybe Text
hwTypeDomain HWType
portType
mpTypeName :: Text
mpTypeName = (State backend Text -> backend -> Text)
-> backend -> State backend Text -> Text
forall a b c. (a -> b -> c) -> b -> a -> c
flip State backend Text -> backend -> Text
forall s a. State s a -> s -> a
evalState backend
backend (State backend Text -> Text) -> State backend Text -> Text
forall a b. (a -> b) -> a -> b
$ Mon (State backend) Text -> State backend Text
forall (f :: Type -> Type) m. Mon f m -> f m
getMon (Mon (State backend) Text -> State backend Text)
-> Mon (State backend) Text -> State backend Text
forall a b. (a -> b) -> a -> b
$ do
Text -> Text
LText.toStrict (Text -> Text) -> (Doc () -> Text) -> Doc () -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc () -> Text
forall ann. Doc ann -> Text
renderOneLine (Doc () -> Text)
-> Mon (State backend) (Doc ()) -> Mon (State backend) Text
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Usage -> HWType -> Mon (State backend) (Doc ())
forall state.
Backend state =>
Usage -> HWType -> Mon (State state) (Doc ())
hdlType (Text -> Usage
External Text
mpName) HWType
portType
manifestFilename :: IsString a => a
manifestFilename :: a
manifestFilename = a
"clash-manifest.json"
mkManifest ::
Backend backend =>
backend ->
HashMap Text VDomainConfiguration ->
ClashOpts ->
Component ->
[Component] ->
[(FilePath, ByteString)] ->
Int ->
Manifest
mkManifest :: backend
-> HashMap Text VDomainConfiguration
-> ClashOpts
-> Component
-> [Component]
-> [(String, ByteString)]
-> Int
-> Manifest
mkManifest backend
backend HashMap Text VDomainConfiguration
domains ClashOpts{Bool
Int
[String]
Maybe String
Maybe (Maybe Int)
Maybe Text
Word
Set String
OverridingBool
PreserveCase
HdlSyn
DebugLevel
opt_edalize :: ClashOpts -> Bool
opt_inlineWFCacheLimit :: ClashOpts -> Word
opt_aggressiveXOptBB :: ClashOpts -> Bool
opt_aggressiveXOpt :: ClashOpts -> Bool
opt_checkIDir :: ClashOpts -> Bool
opt_forceUndefined :: ClashOpts -> Maybe (Maybe Int)
opt_ultra :: ClashOpts -> Bool
opt_lowerCaseBasicIds :: ClashOpts -> PreserveCase
opt_escapedIds :: ClashOpts -> Bool
opt_newInlineStrat :: ClashOpts -> Bool
opt_componentPrefix :: ClashOpts -> Maybe Text
opt_importPaths :: ClashOpts -> [String]
opt_floatSupport :: ClashOpts -> Bool
opt_errorExtra :: ClashOpts -> Bool
opt_hdlSyn :: ClashOpts -> HdlSyn
opt_hdlDir :: ClashOpts -> Maybe String
opt_intWidth :: ClashOpts -> Int
opt_color :: ClashOpts -> OverridingBool
opt_primWarn :: ClashOpts -> Bool
opt_clear :: ClashOpts -> Bool
opt_cachehdl :: ClashOpts -> Bool
opt_dbgRewriteHistoryFile :: ClashOpts -> Maybe String
opt_dbgTransformationsLimit :: ClashOpts -> Int
opt_dbgTransformationsFrom :: ClashOpts -> Int
opt_dbgTransformations :: ClashOpts -> Set String
opt_dbgLevel :: ClashOpts -> DebugLevel
opt_evaluatorFuelLimit :: ClashOpts -> Word
opt_inlineConstantLimit :: ClashOpts -> Word
opt_inlineFunctionLimit :: ClashOpts -> Word
opt_specLimit :: ClashOpts -> Int
opt_inlineLimit :: ClashOpts -> Int
opt_edalize :: Bool
opt_inlineWFCacheLimit :: Word
opt_aggressiveXOptBB :: Bool
opt_aggressiveXOpt :: Bool
opt_checkIDir :: Bool
opt_forceUndefined :: Maybe (Maybe Int)
opt_ultra :: Bool
opt_lowerCaseBasicIds :: PreserveCase
opt_escapedIds :: Bool
opt_newInlineStrat :: Bool
opt_componentPrefix :: Maybe Text
opt_importPaths :: [String]
opt_floatSupport :: Bool
opt_errorExtra :: Bool
opt_hdlSyn :: HdlSyn
opt_hdlDir :: Maybe String
opt_intWidth :: Int
opt_color :: OverridingBool
opt_primWarn :: Bool
opt_clear :: Bool
opt_cachehdl :: Bool
opt_dbgRewriteHistoryFile :: Maybe String
opt_dbgTransformationsLimit :: Int
opt_dbgTransformationsFrom :: Int
opt_dbgTransformations :: Set String
opt_dbgLevel :: DebugLevel
opt_evaluatorFuelLimit :: Word
opt_inlineConstantLimit :: Word
opt_inlineFunctionLimit :: Word
opt_specLimit :: Int
opt_inlineLimit :: Int
..} Component{[(Identifier, HWType)]
[(WireOrReg, (Identifier, HWType), Maybe Expr)]
[Declaration]
Identifier
declarations :: Component -> [Declaration]
outputs :: Component -> [(WireOrReg, (Identifier, HWType), Maybe Expr)]
inputs :: Component -> [(Identifier, HWType)]
componentName :: Component -> Identifier
declarations :: [Declaration]
outputs :: [(WireOrReg, (Identifier, HWType), Maybe Expr)]
inputs :: [(Identifier, HWType)]
componentName :: Identifier
..} [Component]
components [(String, ByteString)]
files Int
topHash = Manifest :: Int
-> (Int, Int, Bool)
-> [ManifestPort]
-> [ManifestPort]
-> [Text]
-> Text
-> [(String, ByteString)]
-> HashMap Text VDomainConfiguration
-> Manifest
Manifest
{ manifestHash :: Int
manifestHash = Int
topHash
, inPorts :: [ManifestPort]
inPorts = [backend -> Identifier -> HWType -> ManifestPort
forall backend.
Backend backend =>
backend -> Identifier -> HWType -> ManifestPort
mkManifestPort backend
backend Identifier
pName HWType
pType | (Identifier
pName, HWType
pType) <- [(Identifier, HWType)]
inputs]
, outPorts :: [ManifestPort]
outPorts = [backend -> Identifier -> HWType -> ManifestPort
forall backend.
Backend backend =>
backend -> Identifier -> HWType -> ManifestPort
mkManifestPort backend
backend Identifier
pName HWType
pType | (WireOrReg
_, (Identifier
pName, HWType
pType), Maybe Expr
_) <- [(WireOrReg, (Identifier, HWType), Maybe Expr)]
outputs]
, componentNames :: [Text]
componentNames = (Identifier -> Text) -> [Identifier] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Identifier -> Text
Id.toText [Identifier]
compNames
, topComponent :: Text
topComponent = Identifier -> Text
Id.toText Identifier
componentName
, fileNames :: [(String, ByteString)]
fileNames = [(String, ByteString)]
files
, successFlags :: (Int, Int, Bool)
successFlags = (Int
opt_inlineLimit, Int
opt_specLimit, Bool
opt_floatSupport)
, domains :: HashMap Text VDomainConfiguration
domains = HashMap Text VDomainConfiguration
domains
}
where
compNames :: [Identifier]
compNames = (Component -> Identifier) -> [Component] -> [Identifier]
forall a b. (a -> b) -> [a] -> [b]
map Component -> Identifier
Netlist.componentName [Component]
components
pprintUnexpectedModification :: UnexpectedModification -> String
pprintUnexpectedModification :: UnexpectedModification -> String
pprintUnexpectedModification = \case
Modified String
p -> String
"Unexpected modification in " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
p
Added String
p -> String
"Unexpected extra file " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
p
Removed String
p -> String
"Unexpected removed file " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
p
pprintUnexpectedModifications :: Int -> [UnexpectedModification] -> String
pprintUnexpectedModifications :: Int -> [UnexpectedModification] -> String
pprintUnexpectedModifications Int
0 [UnexpectedModification]
us = Int -> [UnexpectedModification] -> String
pprintUnexpectedModifications Int
forall a. Bounded a => a
maxBound [UnexpectedModification]
us
pprintUnexpectedModifications Int
_ [] = []
pprintUnexpectedModifications Int
_ [UnexpectedModification
u] = String
"* " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> UnexpectedModification -> String
pprintUnexpectedModification UnexpectedModification
u
pprintUnexpectedModifications Int
1 (UnexpectedModification
u:[UnexpectedModification]
us) =
String
"* and " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show ([UnexpectedModification] -> Int
forall (t :: Type -> Type) a. Foldable t => t a -> Int
length (UnexpectedModification
uUnexpectedModification
-> [UnexpectedModification] -> [UnexpectedModification]
forall a. a -> [a] -> [a]
:[UnexpectedModification]
us)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" more unexpected changes"
pprintUnexpectedModifications Int
n (UnexpectedModification
u:[UnexpectedModification]
us) =
String
"* " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> UnexpectedModification -> String
pprintUnexpectedModification UnexpectedModification
u
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"\n" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> [UnexpectedModification] -> String
pprintUnexpectedModifications (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) [UnexpectedModification]
us
readFreshManifest ::
[TopEntityT] ->
(BindingMap, Id) ->
CompiledPrimMap ->
ClashOpts ->
UTCTime ->
FilePath ->
IO (Maybe [UnexpectedModification], Maybe Manifest, Int)
readFreshManifest :: [TopEntityT]
-> (BindingMap, Id)
-> CompiledPrimMap
-> ClashOpts
-> UTCTime
-> String
-> IO (Maybe [UnexpectedModification], Maybe Manifest, Int)
readFreshManifest [TopEntityT]
tops (BindingMap
bindingsMap, Id
topId) CompiledPrimMap
primMap opts :: ClashOpts
opts@(ClashOpts{Bool
Int
[String]
Maybe String
Maybe (Maybe Int)
Maybe Text
Word
Set String
OverridingBool
PreserveCase
HdlSyn
DebugLevel
opt_edalize :: Bool
opt_inlineWFCacheLimit :: Word
opt_aggressiveXOptBB :: Bool
opt_aggressiveXOpt :: Bool
opt_checkIDir :: Bool
opt_forceUndefined :: Maybe (Maybe Int)
opt_ultra :: Bool
opt_lowerCaseBasicIds :: PreserveCase
opt_escapedIds :: Bool
opt_newInlineStrat :: Bool
opt_componentPrefix :: Maybe Text
opt_importPaths :: [String]
opt_floatSupport :: Bool
opt_errorExtra :: Bool
opt_hdlSyn :: HdlSyn
opt_hdlDir :: Maybe String
opt_intWidth :: Int
opt_color :: OverridingBool
opt_primWarn :: Bool
opt_clear :: Bool
opt_cachehdl :: Bool
opt_dbgRewriteHistoryFile :: Maybe String
opt_dbgTransformationsLimit :: Int
opt_dbgTransformationsFrom :: Int
opt_dbgTransformations :: Set String
opt_dbgLevel :: DebugLevel
opt_evaluatorFuelLimit :: Word
opt_inlineConstantLimit :: Word
opt_inlineFunctionLimit :: Word
opt_specLimit :: Int
opt_inlineLimit :: Int
opt_edalize :: ClashOpts -> Bool
opt_inlineWFCacheLimit :: ClashOpts -> Word
opt_aggressiveXOptBB :: ClashOpts -> Bool
opt_aggressiveXOpt :: ClashOpts -> Bool
opt_checkIDir :: ClashOpts -> Bool
opt_forceUndefined :: ClashOpts -> Maybe (Maybe Int)
opt_ultra :: ClashOpts -> Bool
opt_lowerCaseBasicIds :: ClashOpts -> PreserveCase
opt_escapedIds :: ClashOpts -> Bool
opt_newInlineStrat :: ClashOpts -> Bool
opt_componentPrefix :: ClashOpts -> Maybe Text
opt_importPaths :: ClashOpts -> [String]
opt_floatSupport :: ClashOpts -> Bool
opt_errorExtra :: ClashOpts -> Bool
opt_hdlSyn :: ClashOpts -> HdlSyn
opt_hdlDir :: ClashOpts -> Maybe String
opt_intWidth :: ClashOpts -> Int
opt_color :: ClashOpts -> OverridingBool
opt_primWarn :: ClashOpts -> Bool
opt_clear :: ClashOpts -> Bool
opt_cachehdl :: ClashOpts -> Bool
opt_dbgRewriteHistoryFile :: ClashOpts -> Maybe String
opt_dbgTransformationsLimit :: ClashOpts -> Int
opt_dbgTransformationsFrom :: ClashOpts -> Int
opt_dbgTransformations :: ClashOpts -> Set String
opt_dbgLevel :: ClashOpts -> DebugLevel
opt_evaluatorFuelLimit :: ClashOpts -> Word
opt_inlineConstantLimit :: ClashOpts -> Word
opt_inlineFunctionLimit :: ClashOpts -> Word
opt_specLimit :: ClashOpts -> Int
opt_inlineLimit :: ClashOpts -> Int
..}) UTCTime
clashModDate String
path = do
Maybe Manifest
manifestM <- String -> IO (Maybe Manifest)
readManifest String
path
Maybe [UnexpectedModification]
modificationsM <- (Manifest -> IO [UnexpectedModification])
-> Maybe Manifest -> IO (Maybe [UnexpectedModification])
forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (String -> Manifest -> IO [UnexpectedModification]
isUserModified String
path) Maybe Manifest
manifestM
(Maybe [UnexpectedModification], Maybe Manifest, Int)
-> IO (Maybe [UnexpectedModification], Maybe Manifest, Int)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
( Maybe [UnexpectedModification]
modificationsM
, Manifest -> Maybe Manifest
checkManifest (Manifest -> Maybe Manifest) -> Maybe Manifest -> Maybe Manifest
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< if Bool
opt_cachehdl then Maybe Manifest
manifestM else Maybe Manifest
forall a. Maybe a
Nothing
, Int
topHash
)
where
optsHash :: Int
optsHash = ClashOpts -> Int
forall a. Hashable a => a -> Int
hash ClashOpts
opts {
opt_dbgLevel :: DebugLevel
opt_dbgLevel = DebugLevel
DebugNone
, opt_dbgTransformations :: Set String
opt_dbgTransformations = Set String
forall a. Set a
Set.empty
, opt_dbgRewriteHistoryFile :: Maybe String
opt_dbgRewriteHistoryFile = Maybe String
forall a. Maybe a
Nothing
, opt_cachehdl :: Bool
opt_cachehdl = Bool
True
, opt_primWarn :: Bool
opt_primWarn = Bool
True
, opt_color :: OverridingBool
opt_color = OverridingBool
Auto
, opt_errorExtra :: Bool
opt_errorExtra = Bool
False
, opt_checkIDir :: Bool
opt_checkIDir = Bool
True
, opt_edalize :: Bool
opt_edalize = Bool
False
, opt_inlineLimit :: Int
opt_inlineLimit = Int
20
, opt_specLimit :: Int
opt_specLimit = Int
20
, opt_floatSupport :: Bool
opt_floatSupport = Bool
False
, opt_hdlDir :: Maybe String
opt_hdlDir = Maybe String
forall a. Maybe a
Nothing
}
topHash :: Int
topHash = ([TopEntityT], Int, String, [Term], Int) -> Int
forall a. Hashable a => a -> Int
hash
( [TopEntityT]
tops
, CompiledPrimMap -> Int
hashCompiledPrimMap CompiledPrimMap
primMap
, UTCTime -> String
forall a. Show a => a -> String
show UTCTime
clashModDate
, BindingMap -> Id -> [Term]
callGraphBindings BindingMap
bindingsMap Id
topId
, Int
optsHash
)
checkManifest :: Manifest -> Maybe Manifest
checkManifest manifest :: Manifest
manifest@Manifest{Int
manifestHash :: Int
manifestHash :: Manifest -> Int
manifestHash,(Int, Int, Bool)
successFlags :: (Int, Int, Bool)
successFlags :: Manifest -> (Int, Int, Bool)
successFlags}
| (Int
cachedInline, Int
cachedSpec, Bool
cachedFloat) <- (Int, Int, Bool)
successFlags
, Int
cachedInline Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
opt_inlineLimit
, Int
cachedSpec Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
opt_specLimit
, ((Bool
cachedFloat Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
opt_floatSupport) Bool -> Bool -> Bool
|| (Bool
cachedFloat Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
opt_floatSupport))
, Int
manifestHash Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
topHash
= Manifest -> Maybe Manifest
forall a. a -> Maybe a
Just Manifest
manifest
| Bool
otherwise = Maybe Manifest
forall a. Maybe a
Nothing
isUserModified :: FilePath -> Manifest -> IO [UnexpectedModification]
isUserModified :: String -> Manifest -> IO [UnexpectedModification]
isUserModified (ShowS
takeDirectory -> String
topDir) Manifest{[(String, ByteString)]
fileNames :: [(String, ByteString)]
fileNames :: Manifest -> [(String, ByteString)]
fileNames} = do
let
manifestFiles :: Set String
manifestFiles = [String] -> Set String
forall a. Ord a => [a] -> Set a
Set.fromList (((String, ByteString) -> String)
-> [(String, ByteString)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, ByteString) -> String
forall a b. (a, b) -> a
fst [(String, ByteString)]
fileNames)
Set String
currentFiles <- (String -> Set String -> Set String
forall a. Ord a => a -> Set a -> Set a
Set.delete String
forall a. IsString a => a
manifestFilename (Set String -> Set String)
-> ([String] -> Set String) -> [String] -> Set String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Set String
forall a. Ord a => [a] -> Set a
Set.fromList) ([String] -> Set String) -> IO [String] -> IO (Set String)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
listDirectory String
topDir
let
removedFiles :: [String]
removedFiles = Set String -> [String]
forall a. Set a -> [a]
Set.toList (Set String
manifestFiles Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set String
currentFiles)
addedFiles :: [String]
addedFiles = Set String -> [String]
forall a. Set a -> [a]
Set.toList (Set String
currentFiles Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set String
manifestFiles)
[String]
changedFiles <- [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe String] -> [String]) -> IO [Maybe String] -> IO [String]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ((String, ByteString) -> IO (Maybe String))
-> [(String, ByteString)] -> IO [Maybe String]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String, ByteString) -> IO (Maybe String)
detectModification [(String, ByteString)]
fileNames
[UnexpectedModification] -> IO [UnexpectedModification]
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
( (String -> UnexpectedModification)
-> [String] -> [UnexpectedModification]
forall a b. (a -> b) -> [a] -> [b]
map String -> UnexpectedModification
Removed [String]
removedFiles
[UnexpectedModification]
-> [UnexpectedModification] -> [UnexpectedModification]
forall a. Semigroup a => a -> a -> a
<> (String -> UnexpectedModification)
-> [String] -> [UnexpectedModification]
forall a b. (a -> b) -> [a] -> [b]
map String -> UnexpectedModification
Added [String]
addedFiles
[UnexpectedModification]
-> [UnexpectedModification] -> [UnexpectedModification]
forall a. Semigroup a => a -> a -> a
<> (String -> UnexpectedModification)
-> [String] -> [UnexpectedModification]
forall a b. (a -> b) -> [a] -> [b]
map String -> UnexpectedModification
Modified [String]
changedFiles )
where
detectModification :: (FilePath, ByteString) -> IO (Maybe FilePath)
detectModification :: (String, ByteString) -> IO (Maybe String)
detectModification (String
filename, ByteString
manifestDigest) = do
let fullPath :: String
fullPath = String
topDir String -> ShowS
</> String
filename
Bool
fileExists <- String -> IO Bool
doesFileExist String
fullPath
if Bool
fileExists then do
ByteString
contents <- String -> IO ByteString
ByteStringLazy.readFile String
fullPath
if ByteString
manifestDigest ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString -> ByteString
Sha256.hashlazy ByteString
contents
then Maybe String -> IO (Maybe String)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
else Maybe String -> IO (Maybe String)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (String -> Maybe String
forall a. a -> Maybe a
Just String
filename)
else
Maybe String -> IO (Maybe String)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
readManifest :: FilePath -> IO (Maybe Manifest)
readManifest :: String -> IO (Maybe Manifest)
readManifest String
path = do
Either () (Maybe Manifest)
contentsE <- (IOError -> Maybe ())
-> IO (Maybe Manifest) -> IO (Either () (Maybe Manifest))
forall e b a.
Exception e =>
(e -> Maybe b) -> IO a -> IO (Either b a)
tryJust (Bool -> Maybe ()
forall (f :: Type -> Type). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> (IOError -> Bool) -> IOError -> Maybe ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOError -> Bool
isDoesNotExistError) (String -> IO (Maybe Manifest)
forall a. FromJSON a => String -> IO (Maybe a)
Aeson.decodeFileStrict String
path)
Maybe Manifest -> IO (Maybe Manifest)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ((() -> Maybe Manifest)
-> (Maybe Manifest -> Maybe Manifest)
-> Either () (Maybe Manifest)
-> Maybe Manifest
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Maybe Manifest -> () -> Maybe Manifest
forall a b. a -> b -> a
const Maybe Manifest
forall a. Maybe a
Nothing) Maybe Manifest -> Maybe Manifest
forall a. a -> a
id Either () (Maybe Manifest)
contentsE)
writeManifest :: FilePath -> Manifest -> IO ()
writeManifest :: String -> Manifest -> IO ()
writeManifest String
path = String -> ByteString -> IO ()
ByteStringLazy.writeFile String
path (ByteString -> IO ())
-> (Manifest -> ByteString) -> Manifest -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Manifest -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encodePretty
serializeManifest :: Manifest -> Text
serializeManifest :: Manifest -> Text
serializeManifest = Text -> Text
LText.toStrict (Text -> Text) -> (Manifest -> Text) -> Manifest -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
LText.decodeUtf8 (ByteString -> Text)
-> (Manifest -> ByteString) -> Manifest -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Manifest -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encodePretty