{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Scaffolding.Scaffolder (scaffold) where import Control.Arrow ((&&&)) import qualified Data.ByteString.Char8 as S import Data.Conduit (runResourceT, yield, ($$), ($$+-)) import Data.FileEmbed (embedFile) import Data.String (fromString) import qualified Data.Text as T import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.IO as TLIO import Text.ProjectTemplate (unpackTemplate, receiveFS) import System.IO import Text.Shakespeare.Text (renderTextUrl, textFile) import Network.HTTP.Conduit (withManager, http, parseUrl, responseBody) prompt :: (String -> Maybe a) -> IO a prompt f = do s <- getLine case f s of Just a -> return a Nothing -> do putStr "That was not a valid entry, please try again: " hFlush stdout prompt f data Backend = Sqlite | Postgresql | Mysql | MongoDB | Simple deriving (Eq, Read, Show, Enum, Bounded) puts :: LT.Text -> IO () puts s = TLIO.putStr (LT.init s) >> hFlush stdout backends :: [Backend] backends = [minBound .. maxBound] showBackend :: Backend -> String showBackend Sqlite = "s" showBackend Postgresql = "p" showBackend Mysql = "mysql" showBackend MongoDB = "mongo" showBackend Simple = "simple" readBackend :: String -> Maybe Backend readBackend s = lookup s $ map (showBackend &&& id) backends backendBS :: Backend -> S.ByteString backendBS Sqlite = $(embedFile "hsfiles/sqlite.hsfiles") backendBS Postgresql = $(embedFile "hsfiles/postgres.hsfiles") backendBS Mysql = $(embedFile "hsfiles/mysql.hsfiles") backendBS MongoDB = $(embedFile "hsfiles/mongo.hsfiles") backendBS Simple = $(embedFile "hsfiles/simple.hsfiles") -- | Is the character valid for a project name? validPN :: Char -> Bool validPN c | 'A' <= c && c <= 'Z' = True | 'a' <= c && c <= 'z' = True | '0' <= c && c <= '9' = True validPN '-' = True validPN _ = False scaffold :: IO () scaffold = do puts $ renderTextUrl undefined $(textFile "input/welcome.cg") project <- prompt $ \s -> if all validPN s && not (null s) && s /= "test" then Just s else Nothing let dir = project puts $ renderTextUrl undefined $(textFile "input/database.cg") ebackend' <- prompt $ \s -> if s == "url" then Just (Left ()) else fmap Right $ readBackend s ebackend <- case ebackend' of Left () -> do puts "Please enter the URL: " fmap Left $ prompt parseUrl Right backend -> return $ Right backend putStrLn "That's it! I'm creating your files now..." let sink = unpackTemplate (receiveFS $ fromString project) (T.replace "PROJECTNAME" (T.pack project)) case ebackend of Left req -> withManager $ \m -> do res <- http req m responseBody res $$+- sink Right backend -> runResourceT $ yield (backendBS backend) $$ sink TLIO.putStr $ LT.replace "PROJECTNAME" (LT.pack project) $ renderTextUrl undefined $(textFile "input/done.cg")