module Rivet.Main where import Prelude hiding ((*>), (++)) import Control.Applicative ((<$>)) import Control.Monad (void, when) import Data.Char (isSpace) import Data.Configurator import Data.Configurator.Types import qualified Data.HashMap.Strict as M import Data.List (intercalate, isInfixOf) import Data.Monoid import qualified Data.Text as T import Data.Time.Clock import Data.Time.Format import Development.Shake hiding (doesFileExist) import System.Directory (createDirectoryIfMissing, doesFileExist, getCurrentDirectory) import System.Exit import System.IO import System.Process import Rivet.Common import qualified Rivet.Rules as Rules import qualified Rivet.Tasks as Tasks opts :: ShakeOptions opts = shakeOptions { shakeFiles = ".shake/" } getProjectName :: IO String getProjectName = (reverse . takeWhile (/= '/') . reverse) <$> getCurrentDirectory mainWith :: [Task] -> IO () mainWith tasks = do proj <- getProjectName shakeArgsWith opts [] $ \flags targets -> case targets of ("init":[]) -> do e <- doesFileExist "Rivetfile" if e then do putStrLn "Error: Rivetfile already exists. Only run 'rivet init' in empty directory." return Nothing else return $ Just $ do want ["init"] "init" ~> Tasks.init proj ("init":_) -> do putStrLn "Usage: rivet init" return Nothing _ -> do conf <- load [Required "Rivetfile"] commands <- (map (\(k,String v) -> (T.drop (length "commands.") k, v)) . filter (\(k,v) -> (T.pack "commands.") `T.isPrefixOf` k) . M.toList) <$> getMap conf deps <- lookupDefault [] conf (T.pack "dependencies") cabal <- lookupDefault "cabal " conf (T.pack "cabal-command") return $ Just $ do case targets of [] -> action $ liftIO $ putStrLn "Need a task. Run `rivet tasks` to see all tasks." ("test":_) -> want ["test"] ("db:new":_:[]) -> want ["db:new"] ("db:new":_) -> action $ liftIO (putStrLn "usage: rivet db:new migration_name") ("model:new":[]) -> action $ liftIO (putStrLn "usage: rivet model:new ModelName [field_name:field_type]*") ("model:new":_) -> want ["model:new"] ("db:migrate":_:[]) -> want ["db:migrate"] ("db:migrate":_:_) -> action $ liftIO (putStrLn "usage: rivet db:migrate [env]") ("db:migrate:down":_:[]) -> want ["db:migrate:down"] ("db:migrate:down":_:_) -> action $ liftIO (putStrLn "usage: rivet db:migrate:down [env]") ("db:status":_:[]) -> want ["db:status"] ("db:status":_:_) -> action $ liftIO (putStrLn "usage: rivet db:status [env]") (target:args) -> do mapM_ (\t -> if taskName t == target then if length args == taskNumArgs t then want [taskName t] else action $ liftIO (putStrLn $ "usage: rivet " ++ taskName t ++ " " ++ taskUsage t) else return ()) tasks when (not (target `elem` (map taskName tasks))) $ want targets Rules.addCommands commands Rules.addDependencies cabal deps Rules.addBinary cabal proj mapM_ (\t -> taskName t ~> taskBody t proj conf (tail targets)) tasks "cabal.sandbox.config" *> \_ -> cmd "cabal sandbox init" "run" ~> Tasks.run proj "test" ~> Tasks.test cabal targets "db" ~> Tasks.db proj conf "db:test" ~> Tasks.dbTest proj conf "db:create" ~> Tasks.dbCreate proj conf "db:new" ~> Tasks.dbNew targets "db:migrate" ~> Tasks.dbMigrate cabal proj conf (tail targets) "db:migrate:down" ~> Tasks.dbMigrateDown cabal proj conf (tail targets) "db:status" ~> Tasks.dbStatus cabal proj conf (tail targets) "repl" ~> Tasks.repl cabal "setup" ~> Tasks.setup cabal "crypt:edit" ~> Tasks.cryptEdit proj "crypt:show" ~> Tasks.cryptShow "crypt:setpass" ~> Tasks.cryptSetPass proj "tasks" ~> liftIO (mapM_ (putStrLn . ("rivet " ++)) $ ["init" ,"run" ,"test [pattern]" ,"db" ,"db:test" ,"db:create" ,"db:new migration_name" ,"db:migrate" ,"db:migrate:down" ,"db:status" ,"model:new ModelName" ,"repl" ,"setup" ] ++ map taskName tasks)