module Shellify (printErrorAndReturnFailure, runShellify, calculateExpectedFiles) where

import Prelude hiding (readFile, writeFile)
import Options (Options())
import TemplateGeneration ( generateFlakeText, generateShellDotNixText, getRegistryDB)

import Control.Monad (guard, when)
import Data.Bool (bool)
import Data.Maybe (isNothing)
import Data.Text (pack, Text(), unpack)
import Data.Text.IO (hPutStrLn, readFile, writeFile)
import GHC.IO.Exception (ExitCode(ExitSuccess, ExitFailure))
import System.Directory (doesPathExist)
import System.Exit (exitWith)
import System.IO (stderr)

runShellify :: Options -> IO ()
runShellify :: Options -> IO ()
runShellify Options
opts =
     IO (Either Text Text)
getRegistryDB IO (Either Text Text) -> (Either Text Text -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
        (Text -> IO ()) -> (Text -> IO ()) -> Either Text Text -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
          (Text -> IO ()
forall {b}. Text -> IO b
printErrorAndReturnFailure (Text -> IO ()) -> (Text -> Text) -> Text -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"Error calling nix registry: " <>))
          (((Text, Text) -> IO ()) -> [(Text, Text)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Text, Text) -> IO ()
createAFile ([(Text, Text)] -> IO ())
-> (Text -> [(Text, Text)]) -> Text -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Options -> [(Text, Text)]
`calculateExpectedFiles` Options
opts))

createAFile :: (Text, Text) -> IO ()
createAFile :: (Text, Text) -> IO ()
createAFile (Text
name, Text
content) = do ExitCode
extCde <- FilePath -> Text -> IO ExitCode
createFile (Text -> FilePath
unpack Text
name) Text
content
                                 Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ExitCode
extCde ExitCode -> ExitCode -> Bool
forall a. Eq a => a -> a -> Bool
/= ExitCode
ExitSuccess)
                                   (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ ExitCode -> IO ()
forall a. ExitCode -> IO a
exitWith ExitCode
extCde

  where createFile :: FilePath -> Text -> IO ExitCode
        createFile :: FilePath -> Text -> IO ExitCode
createFile FilePath
fileName Text
expectedContents = do
          Maybe Text
fileContents <- (FilePath -> IO Text) -> Maybe FilePath -> IO (Maybe Text)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Maybe a -> f (Maybe b)
traverse FilePath -> IO Text
readFile (Maybe FilePath -> IO (Maybe Text))
-> (Bool -> Maybe FilePath) -> Bool -> IO (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe FilePath -> Maybe FilePath -> Bool -> Maybe FilePath
forall a. a -> a -> Bool -> a
bool Maybe FilePath
forall a. Maybe a
Nothing
                                                   (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
fileName)
                                                   (Bool -> IO (Maybe Text)) -> IO Bool -> IO (Maybe Text)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< FilePath -> IO Bool
doesPathExist FilePath
fileName
          Text -> IO ()
printError (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Maybe Text -> Text
actionDescription (FilePath -> Text
pack FilePath
fileName) Text
expectedContents Maybe Text
fileContents
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing Maybe Text
fileContents)
            (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Text -> IO ()
writeFile FilePath
fileName Text
expectedContents
          ExitCode -> IO ExitCode
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ExitCode -> IO ExitCode) -> ExitCode -> IO ExitCode
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text -> ExitCode
returnCode Text
expectedContents Maybe Text
fileContents

calculateExpectedFiles :: Text -> Options -> [(Text,Text)]
calculateExpectedFiles :: Text -> Options -> [(Text, Text)]
calculateExpectedFiles Text
registry Options
options =
     (Text
"shell.nix", Options -> Text
generateShellDotNixText Options
options)
      (Text, Text) -> [(Text, Text)] -> [(Text, Text)]
forall a. a -> [a] -> [a]
: [(Text, Text)]
-> (Text -> [(Text, Text)]) -> Maybe Text -> [(Text, Text)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
            []
            ((Text, Text) -> [(Text, Text)]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Text, Text) -> [(Text, Text)])
-> (Text -> (Text, Text)) -> Text -> [(Text, Text)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"flake.nix",))
            (Text -> Options -> Maybe Text
generateFlakeText Text
registry Options
options)

actionDescription :: Text -> Text -> Maybe Text -> Text
actionDescription :: Text -> Text -> Maybe Text -> Text
actionDescription Text
fName Text
_ Maybe Text
Nothing = Text
fName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" does not exist. Creating one"
actionDescription Text
fName Text
a (Just Text
b) | Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
b = Text
"The existing " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is good already"
actionDescription Text
fName Text
_ Maybe Text
_ = Text
"A " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" exists already. Delete it or move it and try again"

returnCode :: Text -> Maybe Text -> ExitCode
returnCode :: Text -> Maybe Text -> ExitCode
returnCode Text
_ Maybe Text
Nothing = ExitCode
ExitSuccess
returnCode Text
a (Just Text
b) | Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
b = ExitCode
ExitSuccess
returnCode Text
_ Maybe Text
_ = Int -> ExitCode
ExitFailure Int
1

printErrorAndReturnFailure :: Text -> IO b
printErrorAndReturnFailure Text
err = Text -> IO ()
printError Text
err IO () -> IO b -> IO b
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ExitCode -> IO b
forall a. ExitCode -> IO a
exitWith (Int -> ExitCode
ExitFailure Int
1)
printError :: Text -> IO ()
printError = Handle -> Text -> IO ()
hPutStrLn Handle
stderr