-- -- Copyright © 2013-2015 Anchor Systems, Pty Ltd and Others -- -- The code in this file, and the program it is a part of, is -- made available to you by its authors as open source software: -- you can redistribute it and/or modify it under the terms of -- the 3-clause BSD licence. -- {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} module Git.Vogue where import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Data.Foldable import Data.Maybe import Data.Text.Lazy (Text) import qualified Data.Text.Lazy.IO as T import Data.Traversable import Formatting import Prelude hiding (elem, maximum, notElem) import System.Directory import System.Exit import Git.Vogue.Types -- | Execute a git-vogue command. runCommand :: forall m. (Applicative m, MonadIO m, Functor m) => VogueCommand -> SearchMode -> [PluginName] -- ^ Disabled plugins -> VCS m -> PluginDiscoverer m -> m () runCommand cmd search_mode disabled_plugins VCS{..} PluginDiscoverer{..} = go cmd where cd = getTopLevel >>= liftIO . setCurrentDirectory go CmdInit = do cd already_there <- checkHook if already_there then success "Pre-commit hook is already installed" else do installHook installed <- checkHook if installed then success "Successfully installed hook" else failure "Hook failed to install" go CmdVerify = do cd installed <- checkHook if installed then success "Pre-commit hook currently installed" else failure "Pre-commit hook not installed" go CmdPlugins = do liftIO $ T.putStrLn "git-vogue knows about the following plugins:\n" discoverPlugins >>= liftIO . traverse_ print go (CmdDisable plugin) = do plugins <- discoverPlugins if plugin `elem` fmap pluginName (filter (not . enabled) plugins) then success "Plugin already disabled" else if plugin `elem` fmap pluginName plugins then do disablePlugin plugin success "Disabled plugin" else failure "Unknown plugin" go (CmdEnable plugin) = do ps <- discoverPlugins if plugin `elem` fmap pluginName ps then if plugin `elem` (pluginName <$> filter (not . enabled) ps) then do enablePlugin plugin success "Enabled plugin" else success "Plugin already enabled" else failure "Unknown plugin" go CmdRunCheck = do (check_fs, all_fs, plugins) <- things rs <- for plugins $ \p -> do r <- runCheck p check_fs all_fs liftIO . T.putStrLn $ colorize p r return r exitWithWorst rs go CmdRunFix = do (check_fs, all_fs, plugins) <- things rs <- for plugins $ \p -> do r <- runCheck p check_fs all_fs case r of Failure{} -> do r' <- runFix p check_fs all_fs liftIO . T.putStrLn $ colorize p r' return $ Just r' _ -> return Nothing exitWithWorst (catMaybes rs) things = do cd check_fs <- getFiles search_mode when (null check_fs) (success "Vacuous success - Nothing to check") plugins <- filter ((`notElem` disabled_plugins) . pluginName) . filter enabled <$> discoverPlugins when (null check_fs) (success "Vacuous success - No plugins enabled") all_fs <- getFiles FindAll return (check_fs, all_fs, plugins) success, failure :: MonadIO m => Text -> m a success msg = liftIO (T.putStrLn msg >> exitSuccess) failure msg = liftIO (T.putStrLn msg >> exitFailure) -- | Output the results of a run and exit with an appropriate return code exitWithWorst :: MonadIO m => [Result] -> m () exitWithWorst [] = liftIO exitSuccess exitWithWorst rs = liftIO $ case maximum rs of Success{} -> exitSuccess Failure{} -> exitWith $ ExitFailure 1 Catastrophe{} -> exitWith $ ExitFailure 2 colorize :: Plugin a -> Result -> Text colorize Plugin{..} (Success txt) = format ("\x1b[32m" % text % " succeeded\x1b[0m with:\n" % text) (unPluginName pluginName) txt colorize Plugin{..} (Failure txt) = format ("\x1b[31m" % text % " failed\x1b[0m with:\n" % text) (unPluginName pluginName) txt colorize Plugin{..} (Catastrophe txt ret) = format ("\x1b[31m" % text % " exploded \x1b[0m with exit code " % int %":\n" % text) (unPluginName pluginName) txt ret