Work on correctly avoiding doing early work if later IO work does not need it
Not at all there
This commit is contained in:
parent
5862fe32bc
commit
0f0bde5f18
|
@ -43,6 +43,7 @@ library
|
||||||
, containers
|
, containers
|
||||||
, text
|
, text
|
||||||
, directory
|
, directory
|
||||||
|
, time
|
||||||
, blaze-html
|
, blaze-html
|
||||||
, pandoc-types
|
, pandoc-types
|
||||||
, pandoc
|
, pandoc
|
||||||
|
|
|
@ -3,7 +3,7 @@ pkgs.haskell.lib.overrideCabal
|
||||||
(haskell.callCabal2nix "byg" ./. { })
|
(haskell.callCabal2nix "byg" ./. { })
|
||||||
(_: {
|
(_: {
|
||||||
configureFlags = [
|
configureFlags = [
|
||||||
"--ghc-option=-Werror"
|
# "--ghc-option=-Werror"
|
||||||
"--ghc-option=-O2"
|
"--ghc-option=-O2"
|
||||||
];
|
];
|
||||||
doHaddock = false;
|
doHaddock = false;
|
||||||
|
|
|
@ -3,9 +3,11 @@ module DependencyRunner
|
||||||
( DepRunM
|
( DepRunM
|
||||||
, runDeps
|
, runDeps
|
||||||
, runDepRunMIO
|
, runDepRunMIO
|
||||||
|
, extractSndToken
|
||||||
|
, extractSndTokenAsList
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Types (evalFunctionIO)
|
import Types (evalFunctionIO, functionIOReads, functionIOWrites)
|
||||||
import Types.Value
|
import Types.Value
|
||||||
import Types.Token
|
import Types.Token
|
||||||
import Types.Dependency
|
import Types.Dependency
|
||||||
|
@ -13,65 +15,149 @@ import Types.Dependency
|
||||||
import Type.Reflection (Typeable)
|
import Type.Reflection (Typeable)
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Control.Monad (void, forM)
|
import Data.Maybe (catMaybes)
|
||||||
|
import Control.Monad (void, forM, filterM)
|
||||||
import Control.Monad.State (MonadState, MonadIO, StateT, evalStateT, get, modify, liftIO)
|
import Control.Monad.State (MonadState, MonadIO, StateT, evalStateT, get, modify, liftIO)
|
||||||
|
import Control.Monad.Writer (MonadWriter, WriterT, runWriterT, tell)
|
||||||
|
import System.Directory (getModificationTime)
|
||||||
|
import Data.Time.Clock (UTCTime(..))
|
||||||
|
import qualified System.Directory as SD
|
||||||
|
|
||||||
data ValueExistence = Evaluated Value
|
data LastUpdated = Never
|
||||||
| NotEvaluated (DepRunM Value)
|
| NeverDebug String
|
||||||
|
| NeverInput
|
||||||
|
| At UTCTime
|
||||||
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
newtype DepRunM a = DepRunM { unDepRunM :: StateT (Map Int ValueExistence) IO a }
|
data ValueExistence = Evaluated Value LastUpdated
|
||||||
deriving (Functor, Applicative, Monad, MonadIO, MonadState (Map Int ValueExistence))
|
| NotEvaluated (LastUpdated -> DepRunM (Maybe (Value, LastUpdated)))
|
||||||
|
|
||||||
|
newtype DepRunM a = DepRunM { unDepRunM :: WriterT [FilePath] (StateT (Map Int ValueExistence) IO) a }
|
||||||
|
deriving (Functor, Applicative, Monad, MonadIO,
|
||||||
|
MonadState (Map Int ValueExistence),
|
||||||
|
MonadWriter [FilePath])
|
||||||
|
|
||||||
runDeps :: [Dependency] -> DepRunM ()
|
runDeps :: [Dependency] -> DepRunM ()
|
||||||
runDeps = mapM_ runDep
|
runDeps = mapM_ runDep
|
||||||
|
|
||||||
runDepRunMIO :: DepRunM a -> IO a
|
runDepRunMIO :: DepRunM a -> IO (a, [FilePath])
|
||||||
runDepRunMIO m = evalStateT (unDepRunM m) M.empty
|
runDepRunMIO m = evalStateT (runWriterT (unDepRunM m)) M.empty
|
||||||
|
|
||||||
evaluate :: ValueExistence -> DepRunM Value
|
evaluate :: LastUpdated -> ValueExistence -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
evaluate = \case
|
evaluate luFuture = \case
|
||||||
Evaluated v -> pure v
|
Evaluated v lu -> pure (Just (v, lu))
|
||||||
NotEvaluated m -> m
|
NotEvaluated m -> m luFuture
|
||||||
|
|
||||||
runDep :: Dependency -> DepRunM ()
|
runDep :: Dependency -> DepRunM ()
|
||||||
runDep (Dependency _ a action _ b) =
|
runDep (Dependency _ a action _ b) =
|
||||||
if actionWritesAny action
|
if actionWritesAny action
|
||||||
then void m
|
then void (m Never)
|
||||||
else putTokenValue b $ NotEvaluated m
|
else putTokenValue b $ NotEvaluated m
|
||||||
where m :: DepRunM Value
|
where m :: LastUpdated -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
m = do
|
m luFuture = do
|
||||||
input <- getTokenValue a
|
m <- runAction action a luFuture
|
||||||
result <- runAction action input
|
case m of
|
||||||
putTokenValue b $ Evaluated result
|
Just (result, luResult) -> do
|
||||||
liftIO $ do
|
putTokenValue b $ Evaluated result luResult
|
||||||
putStrLn ("input: " ++ show input)
|
pure $ Just (result, luResult)
|
||||||
putStrLn ("action: " ++ show action)
|
Nothing ->
|
||||||
putStrLn ("output: " ++ show result)
|
pure Nothing
|
||||||
putStrLn "----------"
|
|
||||||
pure result
|
|
||||||
|
|
||||||
getTokenValueByIndex :: Int -> DepRunM Value
|
extractSndToken :: Token (a, b) -> Token b
|
||||||
getTokenValueByIndex i = do
|
extractSndToken = \case
|
||||||
|
TupleToken _ b ->
|
||||||
|
b
|
||||||
|
_ ->
|
||||||
|
error "unsupported"
|
||||||
|
|
||||||
|
extractSndTokenAsList :: (Show b, Typeable b) => Token (a, b) -> Token [b]
|
||||||
|
extractSndTokenAsList = ListToken . (: []) . extractSndToken
|
||||||
|
|
||||||
|
getTokenValueByIndex :: LastUpdated -> Int -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
|
getTokenValueByIndex luFuture i = do
|
||||||
m <- get
|
m <- get
|
||||||
evaluate (m M.! i)
|
case m M.!? i of
|
||||||
|
Nothing -> pure Nothing
|
||||||
|
Just x -> evaluate luFuture x
|
||||||
|
|
||||||
|
minimumOrNever :: [LastUpdated] -> LastUpdated
|
||||||
|
minimumOrNever = \case
|
||||||
|
[] -> Never
|
||||||
|
times -> minimum times
|
||||||
|
|
||||||
|
maximumOrNever :: [LastUpdated] -> LastUpdated
|
||||||
|
maximumOrNever = \case
|
||||||
|
[] -> Never
|
||||||
|
times -> maximum times
|
||||||
|
|
||||||
|
maximumOrNever' :: [UTCTime] -> LastUpdated
|
||||||
|
maximumOrNever' = maximumOrNever . map At
|
||||||
|
|
||||||
|
getTokenValueRaw :: LastUpdated -> Token a -> DepRunM (Maybe (a, LastUpdated))
|
||||||
|
getTokenValueRaw luFuture token = case token of
|
||||||
|
Token i -> do
|
||||||
|
m <- getTokenValueByIndex luFuture i
|
||||||
|
pure $ do (a, lu) <- m
|
||||||
|
pure (fromValue a, lu)
|
||||||
|
|
||||||
getTokenValueRaw :: Token a -> DepRunM a
|
|
||||||
getTokenValueRaw token = case token of
|
|
||||||
Token i ->
|
|
||||||
fromValue <$> getTokenValueByIndex i
|
|
||||||
TupleToken a b -> do
|
TupleToken a b -> do
|
||||||
(,) <$> getTokenValueRaw a <*> getTokenValueRaw b
|
m0 <- getTokenValueRaw luFuture a
|
||||||
ZipToken a b -> do
|
m1 <- getTokenValueRaw luFuture b
|
||||||
zip <$> getTokenValueRaw a <*> getTokenValueRaw b
|
case (m0, m1) of
|
||||||
ListToken ts -> do
|
(Just (a', luA), Just (b', luB)) ->
|
||||||
mapM getTokenValueRaw ts
|
pure $ Just ((a', b'), max luA luB)
|
||||||
NoToken ->
|
(Just (a', luA), Nothing) -> do -- | luA /= NeverInput -> do
|
||||||
pure ()
|
r <- getTokenValueRaw (NeverDebug (show (a', luA))) b
|
||||||
|
pure $ case r of
|
||||||
|
Nothing -> error ("unexpected " ++ show b ++ " (" ++ show (a', luA) ++ ")")
|
||||||
|
Just (b', luB) -> Just ((a', b'), max luA luB)
|
||||||
|
(Nothing, Just (b', luB)) -> do -- | luB /= NeverInput -> do
|
||||||
|
r <- getTokenValueRaw (NeverDebug (show (b', luB))) a
|
||||||
|
pure $ case r of
|
||||||
|
Nothing -> error "unexpected"
|
||||||
|
Just (a', luA) -> Just ((a', b'), max luA luB)
|
||||||
|
_ ->
|
||||||
|
pure $ Nothing
|
||||||
|
|
||||||
getTokenValue :: Token a -> DepRunM Value
|
ZipToken a b -> do
|
||||||
getTokenValue token = case token of
|
m0 <- getTokenValueRaw luFuture a
|
||||||
|
m1 <- getTokenValueRaw luFuture b
|
||||||
|
case (m0, m1) of
|
||||||
|
(Just (a', luA), Just (b', luB)) ->
|
||||||
|
pure $ Just (zip a' b', max luA luB)
|
||||||
|
(Just (a', luA), Nothing) -> do -- | luA /= NeverInput -> do
|
||||||
|
r <- getTokenValueRaw Never b
|
||||||
|
pure $ case r of
|
||||||
|
Nothing -> error "unexpected"
|
||||||
|
Just (b', luB) -> Just (zip a' b', max luA luB)
|
||||||
|
(Nothing, Just (b', luB)) -> do -- | luB /= NeverInput -> do
|
||||||
|
r <- getTokenValueRaw Never a
|
||||||
|
pure $ case r of
|
||||||
|
Nothing -> error "unexpected"
|
||||||
|
Just (a', luA) -> Just (zip a' b', max luA luB)
|
||||||
|
_ ->
|
||||||
|
pure $ Nothing
|
||||||
|
|
||||||
|
ListToken ts -> do
|
||||||
|
ms <- mapM (getTokenValueRaw luFuture) ts
|
||||||
|
if False -- null $ filter ((/= NeverInput) . snd) (catMaybes ms)
|
||||||
|
then pure Nothing
|
||||||
|
else do ms' <- case sequence ms of
|
||||||
|
Just x -> pure x
|
||||||
|
Nothing -> do r <- mapM (getTokenValueRaw Never) ts
|
||||||
|
case sequence r of
|
||||||
|
Nothing -> error "unexpected"
|
||||||
|
Just x -> pure x
|
||||||
|
let (as, lus) = unzip ms'
|
||||||
|
pure $ Just (as, maximumOrNever lus)
|
||||||
|
|
||||||
|
NoToken ->
|
||||||
|
pure $ Just ((), Never)
|
||||||
|
|
||||||
|
getTokenValue :: Token a -> LastUpdated -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
|
getTokenValue token luFuture = case token of
|
||||||
Token i ->
|
Token i ->
|
||||||
getTokenValueByIndex i
|
getTokenValueByIndex luFuture i
|
||||||
TupleToken _ _ ->
|
TupleToken _ _ ->
|
||||||
fromRaw token
|
fromRaw token
|
||||||
ZipToken _ _ ->
|
ZipToken _ _ ->
|
||||||
|
@ -80,26 +166,70 @@ getTokenValue token = case token of
|
||||||
fromRaw token
|
fromRaw token
|
||||||
NoToken ->
|
NoToken ->
|
||||||
fromRaw token
|
fromRaw token
|
||||||
where fromRaw :: (Typeable a, Show a) => Token a -> DepRunM Value
|
where fromRaw :: (Typeable a, Show a) => Token a -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
fromRaw = fmap toValue . getTokenValueRaw
|
fromRaw t = do
|
||||||
|
m <- getTokenValueRaw luFuture t
|
||||||
|
pure $ do (x, lu) <- m
|
||||||
|
pure (toValue x, lu)
|
||||||
|
|
||||||
putTokenValue :: Token a -> ValueExistence -> DepRunM ()
|
putTokenValue :: Token a -> ValueExistence -> DepRunM ()
|
||||||
putTokenValue t e = case t of
|
putTokenValue t v = case t of
|
||||||
Token i ->
|
Token i ->
|
||||||
modify $ M.insert i e
|
modify $ M.insert i v
|
||||||
NoToken ->
|
NoToken ->
|
||||||
pure ()
|
pure ()
|
||||||
_ ->
|
_ ->
|
||||||
error "unexpected"
|
error "unexpected"
|
||||||
|
|
||||||
runAction :: forall a b. Action a b -> Value -> DepRunM Value
|
maximumModTime :: [FilePath] -> DepRunM LastUpdated
|
||||||
runAction action input = case action of
|
maximumModTime paths = do
|
||||||
|
paths' <- filterM (liftIO . SD.doesPathExist) paths
|
||||||
|
times <- mapM (liftIO . getModificationTime) paths'
|
||||||
|
pure $ maximumOrNever' times
|
||||||
|
|
||||||
|
runAction :: forall a b. Action a b -> Token a -> LastUpdated
|
||||||
|
-> DepRunM (Maybe (Value, LastUpdated))
|
||||||
|
runAction action tokenInput luFuture = case action of
|
||||||
Function (F f) ->
|
Function (F f) ->
|
||||||
calc f
|
calc f
|
||||||
FunctionIO f ->
|
FunctionIO f -> do
|
||||||
calcM (liftIO . evalFunctionIO f)
|
m <- getTokenValueRaw luFuture $ functionIOWrites f tokenInput
|
||||||
|
case m of
|
||||||
|
Nothing ->
|
||||||
|
pure Nothing -- error "unexpected" -- wrong?
|
||||||
|
Just (writes, _writesLu) -> do
|
||||||
|
tell writes
|
||||||
|
lastWritten <- max luFuture <$> maximumModTime writes
|
||||||
|
result <- getTokenValue tokenInput lastWritten
|
||||||
|
case result of
|
||||||
|
Just (inputValue, luInput) -> do
|
||||||
|
let input = inputFromValue inputValue
|
||||||
|
lastUpdated <- max luInput <$> (maximumModTime $ functionIOReads f input)
|
||||||
|
if lastUpdated > lastWritten
|
||||||
|
then do liftIO $ do
|
||||||
|
putStrLn ("input: " ++ show input)
|
||||||
|
putStrLn ("input last updated: " ++ show luInput)
|
||||||
|
putStrLn ("IO function: " ++ show f)
|
||||||
|
putStrLn ("Source timestamp: " ++ show lastUpdated)
|
||||||
|
putStrLn ("Target timestamp: " ++ show lastWritten)
|
||||||
|
v <- toValue <$> (liftIO $ evalFunctionIO f input)
|
||||||
|
-- tell writes
|
||||||
|
let luResult = max luInput lastUpdated
|
||||||
|
liftIO $ do
|
||||||
|
putStrLn ("output: " ++ show v)
|
||||||
|
putStrLn ("output last updated: " ++ show luResult)
|
||||||
|
putStrLn "----------"
|
||||||
|
pure $ Just (v, luResult)
|
||||||
|
else do -- liftIO $ putStrLn ("Source timestamp "
|
||||||
|
-- ++ show lastUpdated
|
||||||
|
-- ++ " not newer than target timestamp "
|
||||||
|
-- ++ show lastWritten
|
||||||
|
-- ++ "; ignoring IO computation.")
|
||||||
|
pure Nothing -- (toValue (), lastWritten) -- assumes writing FunctionIO always return ()
|
||||||
|
Nothing ->
|
||||||
|
pure Nothing
|
||||||
Inject x ->
|
Inject x ->
|
||||||
pure $ toValue x
|
pure $ Just (toValue x, NeverInput)
|
||||||
FilterComp ->
|
FilterComp ->
|
||||||
calc (\(vs, mask) -> map fst $ filter snd $ zip vs mask)
|
calc (\(vs, mask) -> map fst $ filter snd $ zip vs mask)
|
||||||
UntupleFst ->
|
UntupleFst ->
|
||||||
|
@ -110,14 +240,28 @@ runAction action input = case action of
|
||||||
calc (map fst)
|
calc (map fst)
|
||||||
UnzipSnd ->
|
UnzipSnd ->
|
||||||
calc (map snd)
|
calc (map snd)
|
||||||
MapComp subDeps innerInput innerOutput ->
|
MapComp subDeps innerInput innerOutput -> do
|
||||||
(toValueRep (actionTargetType action) <$>)
|
m <- getTokenValue tokenInput luFuture
|
||||||
$ forM (fromValueRep (actionSourceType action) input) $ \x -> do
|
case m of
|
||||||
putTokenValue innerInput $ Evaluated $ toValue x
|
Nothing -> pure Nothing
|
||||||
runDeps subDeps
|
Just (inputValue, luInput) -> do
|
||||||
fromValue <$> getTokenValue innerOutput
|
let input = inputFromValue inputValue
|
||||||
where calcM :: (Typeable a, Typeable b, Show b) => (a -> DepRunM b) -> DepRunM Value
|
lastUpdated <- maximumModTime $ actionReads action input
|
||||||
calcM f = toValue <$> (f $ fromValueRep (actionSourceType action) input)
|
result <- forM input $ \x -> do
|
||||||
|
putTokenValue innerInput $ Evaluated (toValue x) (max luInput lastUpdated)
|
||||||
|
runDeps subDeps
|
||||||
|
m <- getTokenValue innerOutput luFuture
|
||||||
|
pure $ do (vOut, luOut) <- m
|
||||||
|
pure (fromValue vOut, luOut)
|
||||||
|
pure $ do result' <- sequence result
|
||||||
|
let (values, lus) = unzip result'
|
||||||
|
pure $ (toValueRep (actionTargetType action) values, maximumOrNever lus)
|
||||||
|
where inputFromValue :: Typeable a => Value -> a
|
||||||
|
inputFromValue = fromValueRep (actionSourceType action)
|
||||||
|
|
||||||
calc :: (Typeable a, Typeable b, Show b) => (a -> b) -> DepRunM Value
|
calc :: (Typeable a, Typeable b, Show b) => (a -> b) -> DepRunM (Maybe (Value, LastUpdated))
|
||||||
calc f = calcM (pure . f)
|
calc f = do
|
||||||
|
m <- getTokenValue tokenInput luFuture
|
||||||
|
pure $ do (inputValue, luInput) <- m
|
||||||
|
let input = inputFromValue inputValue
|
||||||
|
pure (toValue $ f input, luInput)
|
||||||
|
|
|
@ -6,9 +6,10 @@ module Functions.Image
|
||||||
, convertImage
|
, convertImage
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Types (IsFunctionIO(..), Token)
|
import Types (IsFunctionIO(..), Token(..))
|
||||||
import DependencyGenerator (DepGenM, TokenableTo(..), onTupleToken, toTupleToken,
|
import DependencyGenerator (DepGenM, TokenableTo(..), onTupleToken, toTupleToken,
|
||||||
runFunctionIO, runFunctionIO_)
|
runFunctionIO, runFunctionIO_)
|
||||||
|
import DependencyRunner (extractSndTokenAsList)
|
||||||
|
|
||||||
import qualified Codec.Picture as CP
|
import qualified Codec.Picture as CP
|
||||||
import qualified Codec.Picture.STBIR as CPS
|
import qualified Codec.Picture.STBIR as CPS
|
||||||
|
@ -31,7 +32,7 @@ instance IsFunctionIO OpenImage FilePath Image where
|
||||||
Left e -> error ("unexpected error: " ++ e)
|
Left e -> error ("unexpected error: " ++ e)
|
||||||
Right image -> pure $ ImageWrapper $ CP.convertRGB8 image
|
Right image -> pure $ ImageWrapper $ CP.convertRGB8 image
|
||||||
functionIOReads OpenImage s = [s]
|
functionIOReads OpenImage s = [s]
|
||||||
functionIOWrites OpenImage = const []
|
functionIOWrites OpenImage = const (ListToken [])
|
||||||
functionIOWritesAny OpenImage = False
|
functionIOWritesAny OpenImage = False
|
||||||
|
|
||||||
openImage :: TokenableTo FilePath a => a -> DepGenM (Token Image)
|
openImage :: TokenableTo FilePath a => a -> DepGenM (Token Image)
|
||||||
|
@ -43,7 +44,7 @@ instance IsFunctionIO SaveImage (Image, FilePath) () where
|
||||||
evalFunctionIO SaveImage (ImageWrapper image, s) =
|
evalFunctionIO SaveImage (ImageWrapper image, s) =
|
||||||
CP.saveJpgImage 90 s $ CP.ImageRGB8 image
|
CP.saveJpgImage 90 s $ CP.ImageRGB8 image
|
||||||
functionIOReads SaveImage = const []
|
functionIOReads SaveImage = const []
|
||||||
functionIOWrites SaveImage (_, s) = [s]
|
functionIOWrites SaveImage = extractSndTokenAsList
|
||||||
functionIOWritesAny SaveImage = True
|
functionIOWritesAny SaveImage = True
|
||||||
|
|
||||||
saveImage :: (TokenableTo Image a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
saveImage :: (TokenableTo Image a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
||||||
|
|
|
@ -12,8 +12,10 @@ module Functions.Paths
|
||||||
import Types (IsFunctionIO(..), Token(..))
|
import Types (IsFunctionIO(..), Token(..))
|
||||||
import DependencyGenerator (DepGenM, TokenableTo(..), onToken, onTupleToken, toTupleToken,
|
import DependencyGenerator (DepGenM, TokenableTo(..), onToken, onTupleToken, toTupleToken,
|
||||||
runFunctionIO, runFunctionIO_, untupleSndDepGenM)
|
runFunctionIO, runFunctionIO_, untupleSndDepGenM)
|
||||||
|
import DependencyRunner (extractSndTokenAsList)
|
||||||
|
|
||||||
import Data.Char (toLower)
|
import Data.Char (toLower)
|
||||||
|
import Control.Monad (when)
|
||||||
import qualified System.Directory as SD
|
import qualified System.Directory as SD
|
||||||
|
|
||||||
joinPaths :: (TokenableTo FilePath a, TokenableTo FilePath b) => a -> b -> DepGenM (Token FilePath)
|
joinPaths :: (TokenableTo FilePath a, TokenableTo FilePath b) => a -> b -> DepGenM (Token FilePath)
|
||||||
|
@ -37,8 +39,8 @@ data ListDirectory = ListDirectory deriving Show
|
||||||
instance IsFunctionIO ListDirectory FilePath [FilePath] where
|
instance IsFunctionIO ListDirectory FilePath [FilePath] where
|
||||||
evalFunctionIO ListDirectory s = SD.listDirectory s
|
evalFunctionIO ListDirectory s = SD.listDirectory s
|
||||||
functionIOReads ListDirectory s = [s]
|
functionIOReads ListDirectory s = [s]
|
||||||
functionIOWrites ListDirectory = const []
|
functionIOWrites ListDirectory = const (ListToken [])
|
||||||
functionIOWritesAny ListDirectory = False
|
functionIOWritesAny ListDirectory = False -- old: force triggering
|
||||||
|
|
||||||
listDirectory :: TokenableTo FilePath a => a -> DepGenM (Token [FilePath])
|
listDirectory :: TokenableTo FilePath a => a -> DepGenM (Token [FilePath])
|
||||||
listDirectory a = runFunctionIO ListDirectory =<< toToken a
|
listDirectory a = runFunctionIO ListDirectory =<< toToken a
|
||||||
|
@ -48,7 +50,7 @@ data IsDirectory = IsDirectory deriving Show
|
||||||
instance IsFunctionIO IsDirectory FilePath Bool where
|
instance IsFunctionIO IsDirectory FilePath Bool where
|
||||||
evalFunctionIO IsDirectory s = SD.doesDirectoryExist s
|
evalFunctionIO IsDirectory s = SD.doesDirectoryExist s
|
||||||
functionIOReads IsDirectory s = [s]
|
functionIOReads IsDirectory s = [s]
|
||||||
functionIOWrites IsDirectory = const []
|
functionIOWrites IsDirectory = const (ListToken [])
|
||||||
functionIOWritesAny IsDirectory = False
|
functionIOWritesAny IsDirectory = False
|
||||||
|
|
||||||
isDirectory :: TokenableTo FilePath a => a -> DepGenM (Token Bool)
|
isDirectory :: TokenableTo FilePath a => a -> DepGenM (Token Bool)
|
||||||
|
@ -57,10 +59,17 @@ isDirectory a = runFunctionIO IsDirectory =<< toToken a
|
||||||
|
|
||||||
data MakeDir = MakeDir deriving Show
|
data MakeDir = MakeDir deriving Show
|
||||||
instance IsFunctionIO MakeDir FilePath () where
|
instance IsFunctionIO MakeDir FilePath () where
|
||||||
evalFunctionIO MakeDir s =
|
evalFunctionIO MakeDir s = do
|
||||||
SD.createDirectory s
|
exists <- SD.doesPathExist s
|
||||||
|
when (not exists) $ SD.createDirectory s
|
||||||
functionIOReads MakeDir = const []
|
functionIOReads MakeDir = const []
|
||||||
functionIOWrites MakeDir s = [s]
|
functionIOWrites MakeDir s = ListToken [s]
|
||||||
|
|
||||||
|
|
||||||
|
-- Old: Don't consider a created
|
||||||
|
-- directory "written", as there is
|
||||||
|
-- no extra information than its name
|
||||||
|
-- and presence.
|
||||||
functionIOWritesAny MakeDir = True
|
functionIOWritesAny MakeDir = True
|
||||||
|
|
||||||
makeDir :: TokenableTo FilePath a => a -> DepGenM ()
|
makeDir :: TokenableTo FilePath a => a -> DepGenM ()
|
||||||
|
@ -72,7 +81,7 @@ instance IsFunctionIO CopyFile (FilePath, FilePath) () where
|
||||||
evalFunctionIO CopyFile (source, target) =
|
evalFunctionIO CopyFile (source, target) =
|
||||||
SD.copyFile source target
|
SD.copyFile source target
|
||||||
functionIOReads CopyFile (i, _) = [i]
|
functionIOReads CopyFile (i, _) = [i]
|
||||||
functionIOWrites CopyFile (_, o) = [o]
|
functionIOWrites CopyFile = extractSndTokenAsList
|
||||||
functionIOWritesAny CopyFile = True
|
functionIOWritesAny CopyFile = True
|
||||||
|
|
||||||
copyFile :: (TokenableTo FilePath a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
copyFile :: (TokenableTo FilePath a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
||||||
|
|
|
@ -3,9 +3,10 @@ module Functions.Text
|
||||||
, saveTextFile
|
, saveTextFile
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Types (IsFunctionIO(..), Token)
|
import Types (IsFunctionIO(..), Token(..))
|
||||||
import DependencyGenerator (DepGenM, TokenableTo(..), toTupleToken,
|
import DependencyGenerator (DepGenM, TokenableTo(..), toTupleToken,
|
||||||
runFunctionIO, runFunctionIO_)
|
runFunctionIO, runFunctionIO_)
|
||||||
|
import DependencyRunner (extractSndTokenAsList)
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
|
@ -14,7 +15,7 @@ data ReadTextFile = ReadTextFile deriving Show
|
||||||
instance IsFunctionIO ReadTextFile FilePath Text where
|
instance IsFunctionIO ReadTextFile FilePath Text where
|
||||||
evalFunctionIO ReadTextFile s = T.readFile s
|
evalFunctionIO ReadTextFile s = T.readFile s
|
||||||
functionIOReads ReadTextFile s = [s]
|
functionIOReads ReadTextFile s = [s]
|
||||||
functionIOWrites ReadTextFile = const []
|
functionIOWrites ReadTextFile = const (ListToken [])
|
||||||
functionIOWritesAny ReadTextFile = False
|
functionIOWritesAny ReadTextFile = False
|
||||||
|
|
||||||
readTextFile :: TokenableTo FilePath a => a -> DepGenM (Token Text)
|
readTextFile :: TokenableTo FilePath a => a -> DepGenM (Token Text)
|
||||||
|
@ -25,7 +26,7 @@ data SaveTextFile = SaveTextFile deriving Show
|
||||||
instance IsFunctionIO SaveTextFile (Text, FilePath) () where
|
instance IsFunctionIO SaveTextFile (Text, FilePath) () where
|
||||||
evalFunctionIO SaveTextFile (t, s) = T.writeFile s t
|
evalFunctionIO SaveTextFile (t, s) = T.writeFile s t
|
||||||
functionIOReads SaveTextFile = const []
|
functionIOReads SaveTextFile = const []
|
||||||
functionIOWrites SaveTextFile (_, s) = [s]
|
functionIOWrites SaveTextFile = extractSndTokenAsList
|
||||||
functionIOWritesAny SaveTextFile = True
|
functionIOWritesAny SaveTextFile = True
|
||||||
|
|
||||||
saveTextFile :: (TokenableTo Text a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
saveTextFile :: (TokenableTo Text a, TokenableTo FilePath b) => a -> b -> DepGenM ()
|
||||||
|
|
|
@ -16,8 +16,9 @@ main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
case args of
|
case args of
|
||||||
["run"] ->
|
["run"] -> do
|
||||||
DR.runDepRunMIO $ DR.runDeps dependencies
|
((), filesWritten) <- DR.runDepRunMIO $ DR.runDeps dependencies
|
||||||
|
putStrLn ("Files which could have been written: " ++ show filesWritten)
|
||||||
["tree"] ->
|
["tree"] ->
|
||||||
T.putStr $ D.formatDependencyTrees dependencies
|
T.putStr $ D.formatDependencyTrees dependencies
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -56,10 +56,10 @@ actionReads = \case
|
||||||
FunctionIO f -> functionIOReads f
|
FunctionIO f -> functionIOReads f
|
||||||
_ -> const []
|
_ -> const []
|
||||||
|
|
||||||
actionWrites :: Action a b -> a -> [FilePath]
|
actionWrites :: Action a b -> Token a -> Token [FilePath]
|
||||||
actionWrites = \case
|
actionWrites = \case
|
||||||
FunctionIO f -> functionIOWrites f
|
FunctionIO f -> functionIOWrites f
|
||||||
_ -> const []
|
_ -> const (ListToken [])
|
||||||
|
|
||||||
actionWritesAny :: Action a b -> Bool
|
actionWritesAny :: Action a b -> Bool
|
||||||
actionWritesAny = \case
|
actionWritesAny = \case
|
||||||
|
|
|
@ -3,10 +3,11 @@ module Types.Functions
|
||||||
( IsFunctionIO(..)
|
( IsFunctionIO(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Types.Token (Token)
|
||||||
import Type.Reflection (Typeable)
|
import Type.Reflection (Typeable)
|
||||||
|
|
||||||
class (Show f, Show a, Typeable a, Show b, Typeable b) => IsFunctionIO f a b | f -> a b where
|
class (Show f, Show a, Typeable a, Show b, Typeable b) => IsFunctionIO f a b | f -> a b where
|
||||||
evalFunctionIO :: f -> a -> IO b
|
evalFunctionIO :: f -> a -> IO b
|
||||||
functionIOReads :: f -> a -> [FilePath]
|
functionIOReads :: f -> a -> [FilePath]
|
||||||
functionIOWritesAny :: f -> Bool
|
functionIOWritesAny :: f -> Bool
|
||||||
functionIOWrites :: f -> a -> [FilePath]
|
functionIOWrites :: f -> Token a -> Token [FilePath]
|
||||||
|
|
2
om.md
2
om.md
|
@ -25,7 +25,7 @@ Klik på [Feed](/atom.xml)-fanen i toppen af siden for at tilgå et Atom-feed me
|
||||||
|
|
||||||
## Licens
|
## Licens
|
||||||
|
|
||||||
<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><span property="dct:title">Niels' mad</span> by <span property="cc:attributionName">Niels G. W. Serup</span> er licenseret under <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1" alt=""></a></p>
|
<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><span property="dct:title">Niels' mad</span> af <span property="cc:attributionName">Niels G. W. Serup</span> er licenseret under <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1" alt=""></a></p>
|
||||||
|
|
||||||
|
|
||||||
## Hjemmesidegenerator
|
## Hjemmesidegenerator
|
||||||
|
|
Loading…
Reference in New Issue