diff --git a/app/ghcup-gen/Main.hs b/app/ghcup-gen/Main.hs index 47ca21a..f5bae3f 100644 --- a/app/ghcup-gen/Main.hs +++ b/app/ghcup-gen/Main.hs @@ -11,21 +11,23 @@ module Main where import GHCup.Types -import GHCup.Types.Optics import GHCup.Errors import GHCup.Platform import GHCup.Utils.Dirs +import GHCup.Utils.Logger import GHCup.Types.JSON ( ) import Control.Monad.Trans.Reader ( runReaderT ) import Control.Monad.IO.Class import Data.Char ( toLower ) +import Data.Maybe #if !MIN_VERSION_base(4,13,0) import Data.Semigroup ( (<>) ) #endif import Options.Applicative hiding ( style ) import Haskus.Utils.Variant.Excepts import System.Console.Pretty +import System.Environment import System.Exit import System.IO ( stderr ) import Text.Regex.Posix @@ -114,9 +116,11 @@ com = subparser main :: IO () main = do - let loggerConfig = LoggerConfig { lcPrintDebug = True - , colorOutter = T.hPutStr stderr - , rawOutter = \_ -> pure () + no_color <- isJust <$> lookupEnv "NO_COLOR" + let loggerConfig = LoggerConfig { lcPrintDebug = True + , consoleOutter = T.hPutStr stderr + , fileOutter = \_ -> pure () + , fancyColors = not no_color } dirs <- liftIO getAllDirs let leanAppstate = LeanAppState (Settings True False Never Curl True GHCupURL False GPGNone) dirs defaultKeyBindings loggerConfig diff --git a/app/ghcup-gen/Validate.hs b/app/ghcup-gen/Validate.hs index 3aaeeb6..3e949e9 100644 --- a/app/ghcup-gen/Validate.hs +++ b/app/ghcup-gen/Validate.hs @@ -15,6 +15,7 @@ import GHCup.Errors import GHCup.Types import GHCup.Types.Optics import GHCup.Utils +import GHCup.Utils.Logger import GHCup.Utils.Version.QQ import Codec.Archive diff --git a/app/ghcup/BrickMain.hs b/app/ghcup/BrickMain.hs index 0ab825f..0981a10 100644 --- a/app/ghcup/BrickMain.hs +++ b/app/ghcup/BrickMain.hs @@ -13,9 +13,9 @@ module BrickMain where import GHCup import GHCup.Download import GHCup.Errors -import GHCup.Types.Optics hiding ( getGHCupInfo ) import GHCup.Types hiding ( LeanAppState(..) ) import GHCup.Utils +import GHCup.Utils.Logger import GHCup.Utils.Prelude ( decUTF8Safe ) import GHCup.Utils.File @@ -537,9 +537,10 @@ settings' :: IORef AppState {-# NOINLINE settings' #-} settings' = unsafePerformIO $ do dirs <- getAllDirs - let loggerConfig = LoggerConfig { lcPrintDebug = False - , colorOutter = \_ -> pure () - , rawOutter = \_ -> pure () + let loggerConfig = LoggerConfig { lcPrintDebug = False + , consoleOutter = \_ -> pure () + , fileOutter = \_ -> pure () + , fancyColors = True } newIORef $ AppState (Settings { cache = True , noVerify = False diff --git a/app/ghcup/Main.hs b/app/ghcup/Main.hs index b4eac9a..48b326d 100644 --- a/app/ghcup/Main.hs +++ b/app/ghcup/Main.hs @@ -1338,9 +1338,10 @@ tagCompleter :: Tool -> [String] -> Completer tagCompleter tool add = listIOCompleter $ do dirs' <- liftIO getAllDirs let loggerConfig = LoggerConfig - { lcPrintDebug = False - , colorOutter = mempty - , rawOutter = mempty + { lcPrintDebug = False + , consoleOutter = mempty + , fileOutter = mempty + , fancyColors = False } let appState = LeanAppState (Settings True False Never Curl False GHCupURL True GPGNone) @@ -1364,9 +1365,10 @@ versionCompleter :: Maybe ListCriteria -> Tool -> Completer versionCompleter criteria tool = listIOCompleter $ do dirs' <- liftIO getAllDirs let loggerConfig = LoggerConfig - { lcPrintDebug = False - , colorOutter = mempty - , rawOutter = mempty + { lcPrintDebug = False + , consoleOutter = mempty + , fileOutter = mempty + , fancyColors = False } let settings = Settings True False Never Curl False GHCupURL True GPGNone let leanAppState = LeanAppState @@ -1688,17 +1690,19 @@ Report bugs at |] -- logger interpreter logfile <- flip runReaderT dirs initGHCupFileLogging + no_color <- isJust <$> lookupEnv "NO_COLOR" let loggerConfig = LoggerConfig { lcPrintDebug = verbose settings - , colorOutter = T.hPutStr stderr - , rawOutter = + , consoleOutter = T.hPutStr stderr + , fileOutter = case optCommand of Nuke -> \_ -> pure () _ -> T.appendFile logfile + , fancyColors = not no_color } let leanAppstate = LeanAppState settings dirs keybindings loggerConfig let runLogger = flip runReaderT leanAppstate - let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { colorOutter = \_ -> pure () } } :: LeanAppState) + let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState) ------------------------- @@ -2336,7 +2340,7 @@ Report bugs at |] List ListOptions {..} -> runListGHC (do l <- listVersions loTool lCriteria - liftIO $ printListResult lRawFormat l + liftIO $ printListResult no_color lRawFormat l pure ExitSuccess ) @@ -2807,9 +2811,8 @@ fromVersion' (SetToolTag t') tool = throwE $ TagNotFound t' tool -printListResult :: Bool -> [ListResult] -> IO () -printListResult raw lr = do - no_color <- isJust <$> lookupEnv "NO_COLOR" +printListResult :: Bool -> Bool -> [ListResult] -> IO () +printListResult no_color raw lr = do let color | raw || no_color = flip const diff --git a/lib/GHCup.hs b/lib/GHCup.hs index 502d86e..e3c6543 100644 --- a/lib/GHCup.hs +++ b/lib/GHCup.hs @@ -34,6 +34,7 @@ import GHCup.Types.JSON ( ) import GHCup.Types.Optics import GHCup.Utils import GHCup.Utils.File +import GHCup.Utils.Logger import GHCup.Utils.Prelude import GHCup.Utils.String.QQ import GHCup.Utils.Version.QQ diff --git a/lib/GHCup/Download.hs b/lib/GHCup/Download.hs index 3cc22cd..505ab89 100644 --- a/lib/GHCup/Download.hs +++ b/lib/GHCup/Download.hs @@ -35,6 +35,7 @@ import GHCup.Types.Optics import GHCup.Types.JSON ( ) import GHCup.Utils.Dirs import GHCup.Utils.File +import GHCup.Utils.Logger import GHCup.Utils.Prelude import GHCup.Version diff --git a/lib/GHCup/Platform.hs b/lib/GHCup/Platform.hs index 4876498..99092bd 100644 --- a/lib/GHCup/Platform.hs +++ b/lib/GHCup/Platform.hs @@ -23,6 +23,7 @@ import GHCup.Types import GHCup.Types.Optics import GHCup.Types.JSON ( ) import GHCup.Utils.File +import GHCup.Utils.Logger import GHCup.Utils.Prelude import GHCup.Utils.String.QQ diff --git a/lib/GHCup/Types.hs b/lib/GHCup/Types.hs index 2516a03..b01b202 100644 --- a/lib/GHCup/Types.hs +++ b/lib/GHCup/Types.hs @@ -576,11 +576,12 @@ data LogLevel = Warn deriving (Eq, Ord, Show) data LoggerConfig = LoggerConfig - { lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter - , colorOutter :: T.Text -> IO () -- ^ how to write the color output - , rawOutter :: T.Text -> IO () -- ^ how to write the full raw output + { lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter + , consoleOutter :: T.Text -> IO () -- ^ how to write the console output + , fileOutter :: T.Text -> IO () -- ^ how to write the file output + , fancyColors :: Bool } deriving Show instance NFData LoggerConfig where - rnf (LoggerConfig !lcPrintDebug !_ !_) = rnf lcPrintDebug + rnf (LoggerConfig !lcPrintDebug !_ !_ !fancyColors) = rnf (lcPrintDebug, fancyColors) diff --git a/lib/GHCup/Types/JSON.hs b/lib/GHCup/Types/JSON.hs index 0dabf99..ab265ae 100644 --- a/lib/GHCup/Types/JSON.hs +++ b/lib/GHCup/Types/JSON.hs @@ -24,6 +24,8 @@ module GHCup.Types.JSON where import GHCup.Types import GHCup.Utils.MegaParsec import GHCup.Utils.Prelude +import GHCup.Utils.Logger () -- TH is broken shite and needs GHCup.Utils.Logger for linking, although we don't depend on the file. + -- This is due to the boot file. import Control.Applicative ( (<|>) ) import Data.Aeson diff --git a/lib/GHCup/Types/Optics.hs b/lib/GHCup/Types/Optics.hs index 7b1cdc7..f6887b2 100644 --- a/lib/GHCup/Types/Optics.hs +++ b/lib/GHCup/Types/Optics.hs @@ -23,12 +23,9 @@ import GHCup.Types import Control.Monad.Reader import Data.ByteString ( ByteString ) -import Data.Text ( Text ) import Optics import URI.ByteString -import System.Console.Pretty -import qualified Data.Text as T makePrisms ''Tool makePrisms ''Architecture @@ -117,80 +114,6 @@ getDirs :: ( MonadReader env m getDirs = gets @"dirs" -logInfo :: ( MonadReader env m - , LabelOptic' "loggerConfig" A_Lens env LoggerConfig - , MonadIO m - ) - => Text - -> m () -logInfo = logInternal Info - -logWarn :: ( MonadReader env m - , LabelOptic' "loggerConfig" A_Lens env LoggerConfig - , MonadIO m - ) - => Text - -> m () -logWarn = logInternal Warn - -logDebug :: ( MonadReader env m - , LabelOptic' "loggerConfig" A_Lens env LoggerConfig - , MonadIO m - ) - => Text - -> m () -logDebug = logInternal Debug - -logError :: ( MonadReader env m - , LabelOptic' "loggerConfig" A_Lens env LoggerConfig - , MonadIO m - ) - => Text - -> m () -logError = logInternal Error - - -logInternal :: ( MonadReader env m - , LabelOptic' "loggerConfig" A_Lens env LoggerConfig - , MonadIO m - ) => LogLevel - -> Text - -> m () -logInternal logLevel msg = do - LoggerConfig {..} <- gets @"loggerConfig" - let style' = case logLevel of - Debug -> style Bold . color Blue - Info -> style Bold . color Green - Warn -> style Bold . color Yellow - Error -> style Bold . color Red - let l = case logLevel of - Debug -> style' "[ Debug ]" - Info -> style' "[ Info ]" - Warn -> style' "[ Warn ]" - Error -> style' "[ Error ]" - let strs = T.split (== '\n') msg - let out = case strs of - [] -> T.empty - (x:xs) -> - foldr (\a b -> a <> "\n" <> b) mempty - . ((l <> " " <> x) :) - . fmap (\line' -> style' "[ ... ] " <> line' ) - $ xs - - when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug))) - $ liftIO $ colorOutter out - - -- raw output - let lr = case logLevel of - Debug -> "Debug:" - Info -> "Info:" - Warn -> "Warn:" - Error -> "Error:" - let outr = lr <> " " <> msg <> "\n" - liftIO $ rawOutter outr - - - getLogCleanup :: ( MonadReader env m , LabelOptic' "logCleanup" A_Lens env (IO ()) ) diff --git a/lib/GHCup/Utils.hs b/lib/GHCup/Utils.hs index 6546e5d..4b11bab 100644 --- a/lib/GHCup/Utils.hs +++ b/lib/GHCup/Utils.hs @@ -35,6 +35,7 @@ import GHCup.Types.Optics import GHCup.Types.JSON ( ) import GHCup.Utils.Dirs import GHCup.Utils.File +import GHCup.Utils.Logger import GHCup.Utils.MegaParsec import GHCup.Utils.Prelude import GHCup.Utils.String.QQ diff --git a/lib/GHCup/Utils/Dirs.hs b/lib/GHCup/Utils/Dirs.hs index d5f04f1..a22bd73 100644 --- a/lib/GHCup/Utils/Dirs.hs +++ b/lib/GHCup/Utils/Dirs.hs @@ -38,6 +38,7 @@ import GHCup.Types import GHCup.Types.JSON ( ) import GHCup.Types.Optics import GHCup.Utils.MegaParsec +import GHCup.Utils.Logger import GHCup.Utils.Prelude import Control.Exception.Safe diff --git a/lib/GHCup/Utils/File/Common.hs-boot b/lib/GHCup/Utils/File/Common.hs-boot new file mode 100644 index 0000000..5933883 --- /dev/null +++ b/lib/GHCup/Utils/File/Common.hs-boot @@ -0,0 +1,5 @@ +module GHCup.Utils.File.Common where + +import Text.Regex.Posix + +findFiles :: FilePath -> Regex -> IO [FilePath] diff --git a/lib/GHCup/Utils/File/Posix.hs b/lib/GHCup/Utils/File/Posix.hs index 441b442..a30397e 100644 --- a/lib/GHCup/Utils/File/Posix.hs +++ b/lib/GHCup/Utils/File/Posix.hs @@ -17,6 +17,7 @@ module GHCup.Utils.File.Posix where import GHCup.Utils.File.Common import GHCup.Utils.Prelude +import GHCup.Utils.Logger import GHCup.Types import GHCup.Types.Optics diff --git a/lib/GHCup/Utils/Logger.hs b/lib/GHCup/Utils/Logger.hs index 3d56c22..980485a 100644 --- a/lib/GHCup/Utils/Logger.hs +++ b/lib/GHCup/Utils/Logger.hs @@ -1,5 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedStrings #-} {-| Module : GHCup.Utils.Logger @@ -16,21 +18,97 @@ module GHCup.Utils.Logger where import GHCup.Types import GHCup.Types.Optics -import GHCup.Utils.File +import {-# SOURCE #-} GHCup.Utils.File.Common import GHCup.Utils.String.QQ import Control.Exception.Safe import Control.Monad import Control.Monad.IO.Class import Control.Monad.Reader +import Data.Text ( Text ) +import Optics import Prelude hiding ( appendFile ) +import System.Console.Pretty import System.FilePath import System.IO.Error import Text.Regex.Posix import qualified Data.ByteString as B import GHCup.Utils.Prelude +import qualified Data.Text as T +logInfo :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) + => Text + -> m () +logInfo = logInternal Info + +logWarn :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) + => Text + -> m () +logWarn = logInternal Warn + +logDebug :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) + => Text + -> m () +logDebug = logInternal Debug + +logError :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) + => Text + -> m () +logError = logInternal Error + + +logInternal :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) => LogLevel + -> Text + -> m () +logInternal logLevel msg = do + LoggerConfig {..} <- gets @"loggerConfig" + let color' c = if fancyColors then color c else id + let style' = case logLevel of + Debug -> style Bold . color' Blue + Info -> style Bold . color' Green + Warn -> style Bold . color' Yellow + Error -> style Bold . color' Red + let l = case logLevel of + Debug -> style' "[ Debug ]" + Info -> style' "[ Info ]" + Warn -> style' "[ Warn ]" + Error -> style' "[ Error ]" + let strs = T.split (== '\n') msg + let out = case strs of + [] -> T.empty + (x:xs) -> + foldr (\a b -> a <> "\n" <> b) mempty + . ((l <> " " <> x) :) + . fmap (\line' -> style' "[ ... ] " <> line' ) + $ xs + + when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug))) + $ liftIO $ consoleOutter out + + -- raw output + let lr = case logLevel of + Debug -> "Debug:" + Info -> "Info:" + Warn -> "Warn:" + Error -> "Error:" + let outr = lr <> " " <> msg <> "\n" + liftIO $ fileOutter outr initGHCupFileLogging :: ( MonadReader env m diff --git a/lib/GHCup/Utils/Logger.hs-boot b/lib/GHCup/Utils/Logger.hs-boot new file mode 100644 index 0000000..0995e40 --- /dev/null +++ b/lib/GHCup/Utils/Logger.hs-boot @@ -0,0 +1,21 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedStrings #-} + +module GHCup.Utils.Logger where + +import GHCup.Types + +import Control.Monad.IO.Class +import Control.Monad.Reader +import Data.Text ( Text ) +import Optics + +logWarn :: ( MonadReader env m + , LabelOptic' "loggerConfig" A_Lens env LoggerConfig + , MonadIO m + ) + => Text + -> m () + diff --git a/lib/GHCup/Utils/Prelude.hs b/lib/GHCup/Utils/Prelude.hs index be5e51f..ee06c0d 100644 --- a/lib/GHCup/Utils/Prelude.hs +++ b/lib/GHCup/Utils/Prelude.hs @@ -23,6 +23,7 @@ module GHCup.Utils.Prelude where import GHCup.Types #endif import GHCup.Types.Optics +import {-# SOURCE #-} GHCup.Utils.Logger import Control.Applicative import Control.Exception.Safe