packages feed

ghcup-0.2.1.0: lib-opt/GHCup/OptParse/ChangeLog.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}

module GHCup.OptParse.ChangeLog where


import GHCup.Errors
import GHCup.OptParse.Common
import GHCup.Prelude
import GHCup.Input.Parsers
import GHCup.Prelude.Process   ( exec )
import GHCup.Prelude.String.QQ
import GHCup.Query.Metadata
import GHCup.Types

#if !MIN_VERSION_base(4,13,0)
import Control.Monad.Fail ( MonadFail )
#endif
import Control.Exception.Safe         ( MonadMask )
import Control.Monad.Reader
import Control.Monad.Trans.Resource
import Data.Char                      ( toLower )
import Data.Functor
import Data.Maybe
import Data.Variant.Excepts
import GHCup.Types.Optics
import Options.Applicative            hiding ( style, ParseError )
import Prelude                        hiding ( appendFile )
import System.Exit
import System.Process                 ( system )
import Text.PrettyPrint.HughesPJClass ( prettyShow )
import URI.ByteString                 ( serializeURIRef' )

import qualified Data.Text as T



    ---------------
    --[ Options ]--
    ---------------


data ChangeLogOptions = ChangeLogOptions
  { clOpen :: Bool
  , clTool :: Maybe Tool
  , clToolVer :: Maybe ToolVersion
  }
  deriving (Eq, Show)




    ---------------
    --[ Parsers ]--
    ---------------


changelogP :: Parser ChangeLogOptions
changelogP =
  (\x y -> ChangeLogOptions x y)
    <$> switch (short 'o' <> long "open" <> help "xdg-open the changelog url")
    <*> optional
          (option
            (eitherReader
              (\s' -> Right (Tool (fmap toLower s'))
              )
            )
            (short 't' <> long "tool" <> metavar "<ghc|cabal|hls|ghcup|stack>" <> help
              "Open changelog for given tool (default: ghc)"
              <> completer toolCompleter
            )
          )
    <*> optional (toolVersionTagArgument [] Nothing)



    --------------
    --[ Footer ]--
    --------------


changeLogFooter :: String
changeLogFooter = [s|Discussion:
  By default returns the URI of the ChangeLog of the latest GHC release.
  Pass '-o' to automatically open via xdg-open.|]



    ------------------
    --[ Entrypoint ]--
    ------------------



changelog :: ( Monad m
             , MonadMask m
             , MonadUnliftIO m
             , MonadFail m
             )
          => ChangeLogOptions
          -> (IO (AppState, IO ()), LeanAppState)
          -> m ExitCode
changelog ChangeLogOptions{..} (getAppState', leanAppstate) = run (do
  GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
  let tool = fromMaybe ghc clTool
  treq <- liftE $ resolveVersion clToolVer GLax tool
  let muri = getChangeLog dls tool $ _tvqTargetVer treq
  case muri of
    Nothing -> do
      lift $ logWarn $ "Could not find ChangeLog for " <> T.pack (prettyShow tool) <> ", version " <> T.pack (prettyShow treq)
    Just uri -> do
      pfreq <- lift getPlatformReq
      let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri
      if clOpen
        then do
          case _rPlatform pfreq of
            Darwin  -> lEM $ exec "open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
            Linux _ -> lEM $ exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
            FreeBSD -> lEM $ exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
            OpenBSD -> lEM $ exec "xdg-open" [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing
            Windows -> do
              let args = "start \"\" " ++ T.unpack (decUTF8Safe $ serializeURIRef' uri)
              c <- liftIO $ system args
              case c of
                 (ExitFailure xi) -> throwE $ NonZeroExit xi "cmd.exe" [args]
                 ExitSuccess -> pure ()
        else liftIO $ putStrLn uri'
  ) >>= \case
      VRight _ -> do
        pure ExitSuccess
      VLeft e -> do
        runLogger $ logError $ T.pack $ prettyHFError e
        pure $ ExitFailure 11
 where
  run action' = do
    (appstate', _) <- liftIO getAppState'
    flip runReaderT appstate'
                  . runResourceT
                  . runE
                    @'[ TagNotFound , DayNotFound , NextVerNotFound , NoToolVersionSet , ParseError, ProcessError ]
                  $ action'
  runLogger = flip runReaderT leanAppstate