{-# LANGUAGE RecordWildCards #-}
module Achille.Recipe
( Recipe
, liftIO
, getInput
, getCurrentDir
, readText
, readBS
, saveFile
, saveFileAs
, copyFile
, copyFileAs
, copy
, write
, task
, debug
, callCommand
, runCommandWith
, toTimestamped
) where
import Control.Monad.IO.Class (liftIO)
import Data.Binary (Binary, encodeFile)
import Data.Functor (void)
import Data.Text (Text, pack)
import Data.Text.Encoding (decodeUtf8)
import Data.ByteString (ByteString)
import System.FilePath ((</>))
import Achille.Config
import Achille.Writable (Writable)
import Achille.Timestamped
import qualified Achille.Writable as Writable
import Achille.Internal as Internal
import Achille.Internal.IO (AchilleIO)
import qualified Achille.Internal.IO as AchilleIO
data Color = Red | Blue
color :: Color -> String -> String
color :: Color -> String -> String
color c :: Color
c x :: String
x = "\x1b[" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
start String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
x String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\x1b[0m"
where start :: String
start = case Color
c of
Red -> "31m"
Blue -> "34m"
getInput :: Applicative m
=> Recipe m a a
getInput :: Recipe m a a
getInput = (Context a -> m a) -> Recipe m a a
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached ((Context a -> m a) -> Recipe m a a)
-> (Context a -> m a) -> Recipe m a a
forall a b. (a -> b) -> a -> b
$ a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a) -> (Context a -> a) -> Context a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context a -> a
forall a. Context a -> a
inputValue
getCurrentDir :: Applicative m
=> Recipe m a FilePath
getCurrentDir :: Recipe m a String
getCurrentDir = (Context a -> m String) -> Recipe m a String
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached (String -> m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> m String)
-> (Context a -> String) -> Context a -> m String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context a -> String
forall a. Context a -> String
Internal.currentDir)
readText :: AchilleIO m
=> Recipe m FilePath Text
readText :: Recipe m String Text
readText = (Context String -> m Text) -> Recipe m String Text
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached \Context{..} ->
ByteString -> Text
decodeUtf8 (ByteString -> Text) -> m ByteString -> m Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> m ByteString
forall (m :: * -> *). AchilleIO m => String -> m ByteString
AchilleIO.readFile (String
inputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
inputValue)
readBS :: AchilleIO m => Recipe m FilePath ByteString
readBS :: Recipe m String ByteString
readBS = (Context String -> m ByteString) -> Recipe m String ByteString
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached \Context{..} ->
String -> m ByteString
forall (m :: * -> *). AchilleIO m => String -> m ByteString
AchilleIO.readFile (String
inputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
inputValue)
saveFile :: (AchilleIO m, Writable m a)
=> a -> Recipe m FilePath FilePath
saveFile :: a -> Recipe m String String
saveFile = (String -> String) -> a -> Recipe m String String
forall (m :: * -> *) a.
(AchilleIO m, Writable m a) =>
(String -> String) -> a -> Recipe m String String
saveFileAs String -> String
forall a. a -> a
id
saveFileAs :: (AchilleIO m, Writable m a)
=> (FilePath -> FilePath) -> a -> Recipe m FilePath FilePath
saveFileAs :: (String -> String) -> a -> Recipe m String String
saveFileAs mod :: String -> String
mod x :: a
x = (String -> a -> Recipe m String String)
-> a -> String -> Recipe m String String
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> a -> Recipe m String String
forall (m :: * -> *) b a.
(AchilleIO m, Writable m b) =>
String -> b -> Recipe m a String
write a
x (String -> Recipe m String String)
-> Recipe m String String -> Recipe m String String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> String
mod (String -> String)
-> Recipe m String String -> Recipe m String String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Recipe m String String
forall (m :: * -> *) a. Applicative m => Recipe m a a
getInput
copyFile :: AchilleIO m
=> Recipe m FilePath FilePath
copyFile :: Recipe m String String
copyFile = (String -> String) -> Recipe m String String
forall (m :: * -> *).
AchilleIO m =>
(String -> String) -> Recipe m String String
copyFileAs String -> String
forall a. a -> a
id
copyFileAs :: AchilleIO m
=> (FilePath -> FilePath) -> Recipe m FilePath FilePath
copyFileAs :: (String -> String) -> Recipe m String String
copyFileAs mod :: String -> String
mod = Recipe m String String
forall (m :: * -> *) a. Applicative m => Recipe m a a
getInput Recipe m String String
-> (String -> Recipe m String String) -> Recipe m String String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \from :: String
from -> String -> String -> Recipe m String String
forall (m :: * -> *) a.
AchilleIO m =>
String -> String -> Recipe m a String
copy String
from (String -> String
mod String
from)
copy :: AchilleIO m
=> FilePath -> FilePath -> Recipe m a FilePath
copy :: String -> String -> Recipe m a String
copy from :: String
from to :: String
to = (Context a -> m String) -> Recipe m a String
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached \Context{..} -> do
String -> String -> m ()
forall (m :: * -> *). AchilleIO m => String -> String -> m ()
AchilleIO.copyFile (String
inputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
from)
(String
outputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
to)
String -> m ()
forall (m :: * -> *). AchilleIO m => String -> m ()
AchilleIO.log (Color -> String -> String
color Color
Blue (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (String
currentDir String -> String -> String
</> String
from) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " → " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (String
currentDir String -> String -> String
</> String
to))
String -> m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
to
write :: (AchilleIO m, Writable m b)
=> FilePath -> b -> Recipe m a FilePath
write :: String -> b -> Recipe m a String
write to :: String
to x :: b
x = (Context a -> m String) -> Recipe m a String
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached \Context{..} -> do
String -> b -> m ()
forall (m :: * -> *) a. Writable m a => String -> a -> m ()
Writable.write (String
outputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
to) b
x
String -> m ()
forall (m :: * -> *). AchilleIO m => String -> m ()
AchilleIO.log (Color -> String -> String
color Color
Blue (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ "writing " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (String
currentDir String -> String -> String
</> String
to))
String -> m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
to
task :: Task m b -> Recipe m a b
task :: Task m b -> Recipe m a b
task (Recipe r :: Context () -> m (b, Cache)
r) = (Context a -> m (b, Cache)) -> Recipe m a b
forall (m :: * -> *) a b.
(Context a -> m (b, Cache)) -> Recipe m a b
Recipe (Context () -> m (b, Cache)
r (Context () -> m (b, Cache))
-> (Context a -> Context ()) -> Context a -> m (b, Cache)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context a -> Context ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void)
debug :: AchilleIO m
=> Show b => b -> Recipe m a ()
debug :: b -> Recipe m a ()
debug = (Context a -> m ()) -> Recipe m a ()
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached ((Context a -> m ()) -> Recipe m a ())
-> (b -> Context a -> m ()) -> b -> Recipe m a ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m () -> Context a -> m ()
forall a b. a -> b -> a
const (m () -> Context a -> m ())
-> (b -> m ()) -> b -> Context a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> m ()
forall (m :: * -> *). AchilleIO m => String -> m ()
AchilleIO.log (String -> m ()) -> (b -> String) -> b -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> String
forall a. Show a => a -> String
show
callCommand :: AchilleIO m
=> String -> Recipe m a ()
callCommand :: String -> Recipe m a ()
callCommand = (Context a -> m ()) -> Recipe m a ()
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached ((Context a -> m ()) -> Recipe m a ())
-> (String -> Context a -> m ()) -> String -> Recipe m a ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m () -> Context a -> m ()
forall a b. a -> b -> a
const (m () -> Context a -> m ())
-> (String -> m ()) -> String -> Context a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> m ()
forall (m :: * -> *). AchilleIO m => String -> m ()
AchilleIO.callCommand
runCommandWith :: AchilleIO m
=> (FilePath -> FilePath)
-> (FilePath -> FilePath -> String)
-> Recipe m FilePath FilePath
runCommandWith :: (String -> String)
-> (String -> String -> String) -> Recipe m String String
runCommandWith mod :: String -> String
mod cmd :: String -> String -> String
cmd = (Context String -> m String) -> Recipe m String String
forall (m :: * -> *) a b.
Functor m =>
(Context a -> m b) -> Recipe m a b
nonCached \Context{..} ->
let p' :: String
p' = String -> String
mod String
inputValue
in String -> m ()
forall (m :: * -> *). AchilleIO m => String -> m ()
AchilleIO.callCommand (String -> String -> String
cmd (String
inputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
inputValue)
(String
outputDir String -> String -> String
</> String
currentDir String -> String -> String
</> String
p'))
m () -> m String -> m String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
p'
toTimestamped :: Monad m => FilePath -> Recipe m a (Timestamped FilePath)
toTimestamped :: String -> Recipe m a (Timestamped String)
toTimestamped = Timestamped String -> Recipe m a (Timestamped String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Timestamped String -> Recipe m a (Timestamped String))
-> (String -> Timestamped String)
-> String
-> Recipe m a (Timestamped String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Timestamped String
forall a. IsTimestamped a => a -> Timestamped a
timestamped