2020-04-09 17:53:22 +00:00
|
|
|
{-# LANGUAGE CPP #-}
|
2020-01-11 20:15:05 +00:00
|
|
|
{-# LANGUAGE DataKinds #-}
|
|
|
|
{-# LANGUAGE TypeApplications #-}
|
2020-08-05 19:50:39 +00:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2020-01-11 20:15:05 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
|
|
|
|
|
|
|
|
|
|
|
module Main where
|
|
|
|
|
2020-07-06 20:39:16 +00:00
|
|
|
#if defined(BRICK)
|
|
|
|
import BrickMain ( brickMain )
|
|
|
|
#endif
|
|
|
|
|
2021-10-15 20:24:23 +00:00
|
|
|
import GHCup.OptParse
|
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
import GHCup.Download
|
|
|
|
import GHCup.Errors
|
2020-04-10 15:36:27 +00:00
|
|
|
import GHCup.Platform
|
2020-01-11 20:15:05 +00:00
|
|
|
import GHCup.Types
|
|
|
|
import GHCup.Utils
|
|
|
|
import GHCup.Utils.Logger
|
|
|
|
import GHCup.Utils.Prelude
|
2020-07-04 19:49:59 +00:00
|
|
|
import GHCup.Utils.String.QQ
|
2020-01-11 20:15:05 +00:00
|
|
|
import GHCup.Version
|
|
|
|
|
2021-08-27 12:37:44 +00:00
|
|
|
import Cabal.Plan ( findPlanJson, SearchPlanJson(..) )
|
2021-02-22 20:55:05 +00:00
|
|
|
import Control.Concurrent
|
2021-07-21 13:43:45 +00:00
|
|
|
import Control.Concurrent.Async
|
2020-05-15 19:53:45 +00:00
|
|
|
import Control.Exception.Safe
|
2020-04-09 17:53:22 +00:00
|
|
|
#if !MIN_VERSION_base(4,13,0)
|
|
|
|
import Control.Monad.Fail ( MonadFail )
|
|
|
|
#endif
|
2020-01-11 20:15:05 +00:00
|
|
|
import Control.Monad.Reader
|
2021-08-27 12:37:44 +00:00
|
|
|
import Data.Aeson ( decodeStrict', Value )
|
|
|
|
import Data.Aeson.Encode.Pretty ( encodePretty )
|
2020-03-09 21:21:22 +00:00
|
|
|
import Data.Either
|
2020-03-17 00:58:59 +00:00
|
|
|
import Data.Functor
|
2020-04-18 13:05:05 +00:00
|
|
|
import Data.Maybe
|
2020-03-17 21:58:52 +00:00
|
|
|
import GHC.IO.Encoding
|
2020-01-11 20:15:05 +00:00
|
|
|
import Haskus.Utils.Variant.Excepts
|
2020-04-17 14:56:56 +00:00
|
|
|
import Language.Haskell.TH
|
2021-09-04 13:10:07 +00:00
|
|
|
import Language.Haskell.TH.Syntax ( Quasi(qAddDependentFile) )
|
2020-01-11 20:15:05 +00:00
|
|
|
import Options.Applicative hiding ( style )
|
2020-04-17 20:11:41 +00:00
|
|
|
import Options.Applicative.Help.Pretty ( text )
|
2020-01-11 20:15:05 +00:00
|
|
|
import Prelude hiding ( appendFile )
|
|
|
|
import System.Environment
|
|
|
|
import System.Exit
|
|
|
|
import System.IO hiding ( appendFile )
|
2021-03-01 23:15:03 +00:00
|
|
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
import qualified Data.ByteString as B
|
|
|
|
import qualified Data.Text as T
|
|
|
|
import qualified Data.Text.IO as T
|
|
|
|
import qualified Data.Text.Encoding as E
|
2021-10-30 11:23:02 +00:00
|
|
|
import qualified GHCup.Types as Types
|
2020-04-25 10:06:41 +00:00
|
|
|
|
2020-03-17 00:58:59 +00:00
|
|
|
|
2021-09-20 20:24:20 +00:00
|
|
|
|
2021-05-14 21:09:45 +00:00
|
|
|
toSettings :: Options -> IO (Settings, KeyBindings)
|
2020-10-24 20:03:00 +00:00
|
|
|
toSettings options = do
|
2021-09-24 21:11:51 +00:00
|
|
|
noColor <- isJust <$> lookupEnv "NO_COLOR"
|
2020-10-24 20:03:00 +00:00
|
|
|
userConf <- runE @'[ JSONError ] ghcupConfigFile >>= \case
|
|
|
|
VRight r -> pure r
|
|
|
|
VLeft (V (JSONDecodeError e)) -> do
|
|
|
|
B.hPut stderr ("Error decoding config file: " <> (E.encodeUtf8 . T.pack . show $ e))
|
|
|
|
pure defaultUserSettings
|
|
|
|
_ -> do
|
|
|
|
die "Unexpected error!"
|
2021-09-24 21:11:51 +00:00
|
|
|
pure $ mergeConf options userConf noColor
|
2020-10-24 20:03:00 +00:00
|
|
|
where
|
2021-09-24 21:11:51 +00:00
|
|
|
mergeConf :: Options -> UserSettings -> Bool -> (Settings, KeyBindings)
|
|
|
|
mergeConf Options{..} UserSettings{..} noColor =
|
2021-10-30 11:23:02 +00:00
|
|
|
let cache = fromMaybe (fromMaybe (Types.cache defaultSettings) uCache) optCache
|
|
|
|
metaCache = fromMaybe (fromMaybe (Types.metaCache defaultSettings) uMetaCache) optMetaCache
|
|
|
|
noVerify = fromMaybe (fromMaybe (Types.noVerify defaultSettings) uNoVerify) optNoVerify
|
|
|
|
verbose = fromMaybe (fromMaybe (Types.verbose defaultSettings) uVerbose) optVerbose
|
|
|
|
keepDirs = fromMaybe (fromMaybe (Types.keepDirs defaultSettings) uKeepDirs) optKeepDirs
|
2020-10-25 13:17:17 +00:00
|
|
|
downloader = fromMaybe (fromMaybe defaultDownloader uDownloader) optsDownloader
|
2020-10-24 20:03:00 +00:00
|
|
|
keyBindings = maybe defaultKeyBindings mergeKeys uKeyBindings
|
2021-10-30 11:23:02 +00:00
|
|
|
urlSource = maybe (fromMaybe (Types.urlSource defaultSettings) uUrlSource) OwnSource optUrlSource
|
|
|
|
noNetwork = fromMaybe (fromMaybe (Types.noNetwork defaultSettings) uNoNetwork) optNoNetwork
|
|
|
|
gpgSetting = fromMaybe (fromMaybe (Types.gpgSetting defaultSettings) uGPGSetting) optGpg
|
2021-05-14 21:09:45 +00:00
|
|
|
in (Settings {..}, keyBindings)
|
2020-10-24 20:03:00 +00:00
|
|
|
#if defined(INTERNAL_DOWNLOADER)
|
|
|
|
defaultDownloader = Internal
|
|
|
|
#else
|
|
|
|
defaultDownloader = Curl
|
|
|
|
#endif
|
|
|
|
mergeKeys :: UserKeyBindings -> KeyBindings
|
|
|
|
mergeKeys UserKeyBindings {..} =
|
|
|
|
let KeyBindings {..} = defaultKeyBindings
|
|
|
|
in KeyBindings {
|
|
|
|
bUp = fromMaybe bUp kUp
|
|
|
|
, bDown = fromMaybe bDown kDown
|
|
|
|
, bQuit = fromMaybe bQuit kQuit
|
|
|
|
, bInstall = fromMaybe bInstall kInstall
|
|
|
|
, bUninstall = fromMaybe bUninstall kUninstall
|
|
|
|
, bSet = fromMaybe bSet kSet
|
|
|
|
, bChangelog = fromMaybe bChangelog kChangelog
|
2021-05-14 22:31:36 +00:00
|
|
|
, bShowAllVersions = fromMaybe bShowAllVersions kShowAll
|
|
|
|
, bShowAllTools = fromMaybe bShowAllTools kShowAllTools
|
2020-10-24 20:03:00 +00:00
|
|
|
}
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-27 12:37:44 +00:00
|
|
|
plan_json :: String
|
2021-09-04 13:27:57 +00:00
|
|
|
plan_json = $( do
|
|
|
|
(fp, c) <- runIO (handleIO (\_ -> pure ("", "")) $ do
|
2021-08-27 12:37:44 +00:00
|
|
|
fp <- findPlanJson (ProjectRelativeToDir ".")
|
|
|
|
c <- B.readFile fp
|
|
|
|
(Just res) <- pure $ decodeStrict' @Value c
|
2021-09-04 13:27:57 +00:00
|
|
|
pure (fp, T.unpack $ decUTF8Safe' $ encodePretty res))
|
2021-10-15 20:24:23 +00:00
|
|
|
unless (null fp) $ qAddDependentFile fp
|
2021-09-04 13:27:57 +00:00
|
|
|
pure . LitE . StringL $ c)
|
2021-08-27 12:37:44 +00:00
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
2021-05-14 21:09:45 +00:00
|
|
|
-- https://gitlab.haskell.org/ghc/ghc/issues/8118
|
|
|
|
setLocaleEncoding utf8
|
|
|
|
|
|
|
|
void enableAnsiSupport
|
|
|
|
|
2020-04-17 16:54:21 +00:00
|
|
|
let versionHelp = infoOption
|
2021-10-15 20:24:23 +00:00
|
|
|
( "The GHCup Haskell installer, version " <> (head . lines $ describe_result)
|
2020-04-17 16:54:21 +00:00
|
|
|
)
|
2020-04-17 20:11:41 +00:00
|
|
|
(long "version" <> help "Show version" <> hidden)
|
2021-08-27 12:37:44 +00:00
|
|
|
let planJson = infoOption
|
|
|
|
plan_json
|
|
|
|
(long "plan-json" <> help "Show the build-time configuration" <> internal)
|
2020-04-17 14:56:56 +00:00
|
|
|
let numericVersionHelp = infoOption
|
|
|
|
numericVer
|
|
|
|
( long "numeric-version"
|
|
|
|
<> help "Show the numeric version (for use in scripts)"
|
2020-04-17 20:11:41 +00:00
|
|
|
<> hidden
|
2020-04-17 14:56:56 +00:00
|
|
|
)
|
2020-04-22 18:12:57 +00:00
|
|
|
let listCommands = infoOption
|
|
|
|
"install set rm install-cabal list upgrade compile debug-info tool-requirements changelog"
|
|
|
|
( long "list-commands"
|
|
|
|
<> help "List available commands for shell completion"
|
|
|
|
<> internal
|
|
|
|
)
|
2020-01-11 20:15:05 +00:00
|
|
|
|
2020-07-04 19:49:59 +00:00
|
|
|
let main_footer = [s|Discussion:
|
2020-04-17 20:11:41 +00:00
|
|
|
ghcup installs the Glasgow Haskell Compiler from the official
|
|
|
|
release channels, enabling you to easily switch between different
|
2020-04-22 14:14:10 +00:00
|
|
|
versions. It maintains a self-contained ~/.ghcup directory.
|
|
|
|
|
|
|
|
ENV variables:
|
|
|
|
* TMPDIR: where ghcup does the work (unpacking, building, ...)
|
|
|
|
* GHCUP_INSTALL_BASE_PREFIX: the base of ghcup (default: $HOME)
|
2020-10-25 09:54:57 +00:00
|
|
|
* GHCUP_USE_XDG_DIRS: set to anything to use XDG style directories
|
2020-04-17 20:11:41 +00:00
|
|
|
|
|
|
|
Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|
|
|
|
2020-04-17 14:56:56 +00:00
|
|
|
customExecParser
|
|
|
|
(prefs showHelpOnError)
|
2021-08-27 12:37:44 +00:00
|
|
|
(info (opts <**> helper <**> versionHelp <**> numericVersionHelp <**> planJson <**> listCommands)
|
2020-04-18 13:05:05 +00:00
|
|
|
(footerDoc (Just $ text main_footer))
|
|
|
|
)
|
2020-01-11 20:15:05 +00:00
|
|
|
>>= \opt@Options {..} -> do
|
2021-07-18 12:39:49 +00:00
|
|
|
dirs@Dirs{..} <- getAllDirs
|
2021-05-14 21:09:45 +00:00
|
|
|
|
2020-03-17 18:16:21 +00:00
|
|
|
-- create ~/.ghcup dir
|
2021-06-13 11:41:06 +00:00
|
|
|
ensureDirectories dirs
|
|
|
|
|
|
|
|
(settings, keybindings) <- toSettings opt
|
2020-03-17 18:16:21 +00:00
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
-- logger interpreter
|
2021-10-15 20:24:23 +00:00
|
|
|
logfile <- runReaderT initGHCupFileLogging dirs
|
2021-09-23 10:16:49 +00:00
|
|
|
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
2020-07-06 20:39:16 +00:00
|
|
|
let loggerConfig = LoggerConfig
|
2020-10-24 20:03:00 +00:00
|
|
|
{ lcPrintDebug = verbose settings
|
2021-09-23 10:16:49 +00:00
|
|
|
, consoleOutter = T.hPutStr stderr
|
|
|
|
, fileOutter =
|
2021-07-02 21:26:07 +00:00
|
|
|
case optCommand of
|
|
|
|
Nuke -> \_ -> pure ()
|
2021-08-30 20:41:58 +00:00
|
|
|
_ -> T.appendFile logfile
|
2021-09-23 10:16:49 +00:00
|
|
|
, fancyColors = not no_color
|
2020-01-11 20:15:05 +00:00
|
|
|
}
|
2021-08-30 20:41:58 +00:00
|
|
|
let leanAppstate = LeanAppState settings dirs keybindings loggerConfig
|
|
|
|
let runLogger = flip runReaderT leanAppstate
|
2021-09-23 10:16:49 +00:00
|
|
|
let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState)
|
2021-05-14 21:09:45 +00:00
|
|
|
|
2021-07-15 11:32:48 +00:00
|
|
|
|
|
|
|
-------------------------
|
|
|
|
-- Setting up appstate --
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
2021-07-18 12:39:49 +00:00
|
|
|
appState = do
|
|
|
|
pfreq <- (
|
|
|
|
runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest
|
|
|
|
) >>= \case
|
|
|
|
VRight r -> pure r
|
|
|
|
VLeft e -> do
|
|
|
|
runLogger
|
2021-08-30 20:41:58 +00:00
|
|
|
(logError $ T.pack $ prettyShow e)
|
2021-07-18 12:39:49 +00:00
|
|
|
exitWith (ExitFailure 2)
|
|
|
|
|
|
|
|
ghcupInfo <-
|
2021-08-30 20:41:58 +00:00
|
|
|
( flip runReaderT leanAppstate
|
2021-09-18 17:45:32 +00:00
|
|
|
. runE @'[DigestError, GPGError, JSONError , DownloadFailed, FileDoesNotExistError]
|
2021-10-15 20:24:23 +00:00
|
|
|
$ liftE getDownloadsF
|
2021-07-18 12:39:49 +00:00
|
|
|
)
|
|
|
|
>>= \case
|
|
|
|
VRight r -> pure r
|
|
|
|
VLeft e -> do
|
|
|
|
runLogger
|
2021-08-30 20:41:58 +00:00
|
|
|
(logError $ T.pack $ prettyShow e)
|
2021-07-18 12:39:49 +00:00
|
|
|
exitWith (ExitFailure 2)
|
2021-08-30 20:41:58 +00:00
|
|
|
let s' = AppState settings dirs keybindings ghcupInfo pfreq loggerConfig
|
2021-05-14 21:09:45 +00:00
|
|
|
|
2021-10-15 20:24:23 +00:00
|
|
|
race_ (liftIO $ runReaderT cleanupTrash s')
|
2021-08-30 20:41:58 +00:00
|
|
|
(threadDelay 5000000 >> runLogger (logWarn $ "Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in " <> T.pack recycleDir <> " manually"))
|
2021-07-21 13:43:45 +00:00
|
|
|
|
2021-07-26 16:13:20 +00:00
|
|
|
case optCommand of
|
|
|
|
Nuke -> pure ()
|
|
|
|
Whereis _ _ -> pure ()
|
|
|
|
DInfo -> pure ()
|
|
|
|
ToolRequirements -> pure ()
|
|
|
|
ChangeLog _ -> pure ()
|
2021-09-27 10:52:45 +00:00
|
|
|
UnSet _ -> pure ()
|
2021-07-26 16:13:20 +00:00
|
|
|
#if defined(BRICK)
|
|
|
|
Interactive -> pure ()
|
|
|
|
#endif
|
|
|
|
_ -> lookupEnv "GHCUP_SKIP_UPDATE_CHECK" >>= \case
|
2021-10-15 20:24:23 +00:00
|
|
|
Nothing -> runReaderT checkForUpdates s'
|
2021-07-26 16:13:20 +00:00
|
|
|
Just _ -> pure ()
|
2021-07-15 11:32:48 +00:00
|
|
|
|
2021-07-18 12:39:49 +00:00
|
|
|
-- TODO: always run for windows
|
2021-10-15 20:24:23 +00:00
|
|
|
siletRunLogger (flip runReaderT s' $ runE ensureGlobalTools) >>= \case
|
2021-07-18 12:39:49 +00:00
|
|
|
VRight _ -> pure ()
|
|
|
|
VLeft e -> do
|
|
|
|
runLogger
|
2021-08-30 20:41:58 +00:00
|
|
|
(logError $ T.pack $ prettyShow e)
|
2021-07-18 12:39:49 +00:00
|
|
|
exitWith (ExitFailure 30)
|
|
|
|
pure s'
|
2021-07-15 11:32:48 +00:00
|
|
|
|
2021-05-14 21:09:45 +00:00
|
|
|
|
2021-07-18 21:29:09 +00:00
|
|
|
#if defined(IS_WINDOWS)
|
|
|
|
-- FIXME: windows needs 'ensureGlobalTools', which requires
|
|
|
|
-- full appstate
|
|
|
|
runLeanAppState = runAppState
|
|
|
|
#else
|
2021-07-18 12:39:49 +00:00
|
|
|
runLeanAppState = flip runReaderT leanAppstate
|
2021-07-18 21:29:09 +00:00
|
|
|
#endif
|
2021-07-18 12:39:49 +00:00
|
|
|
runAppState action' = do
|
|
|
|
s' <- liftIO appState
|
2021-10-15 20:24:23 +00:00
|
|
|
runReaderT action' s'
|
2021-07-18 12:39:49 +00:00
|
|
|
|
2021-05-14 21:09:45 +00:00
|
|
|
|
2021-10-15 20:24:23 +00:00
|
|
|
-----------------
|
|
|
|
-- Run command --
|
|
|
|
-----------------
|
2020-05-10 22:18:53 +00:00
|
|
|
|
|
|
|
res <- case optCommand of
|
2020-07-06 20:39:16 +00:00
|
|
|
#if defined(BRICK)
|
2021-05-14 21:09:45 +00:00
|
|
|
Interactive -> do
|
2021-07-18 21:29:09 +00:00
|
|
|
s' <- appState
|
2021-08-30 20:41:58 +00:00
|
|
|
liftIO $ brickMain s' >> pure ExitSuccess
|
2020-07-06 20:39:16 +00:00
|
|
|
#endif
|
2021-10-15 20:24:23 +00:00
|
|
|
Install installCommand -> install installCommand settings appState runLogger
|
|
|
|
InstallCabalLegacy iopts -> install (Left (InstallCabal iopts)) settings appState runLogger
|
|
|
|
Set setCommand -> set setCommand runAppState runLeanAppState runLogger
|
|
|
|
UnSet unsetCommand -> unset unsetCommand runLeanAppState runLogger
|
|
|
|
List lo -> list lo no_color runAppState
|
|
|
|
Rm rmCommand -> rm rmCommand runAppState runLogger
|
|
|
|
DInfo -> dinfo runAppState runLogger
|
|
|
|
Compile compileCommand -> compile compileCommand settings runAppState runLogger
|
|
|
|
Config configCommand -> config configCommand settings keybindings runLogger
|
|
|
|
Whereis whereisOptions
|
|
|
|
whereisCommand -> whereis whereisCommand whereisOptions runAppState leanAppstate runLogger
|
|
|
|
Upgrade uOpts force' -> upgrade uOpts force' runAppState runLogger
|
|
|
|
ToolRequirements -> toolRequirements runAppState runLogger
|
|
|
|
ChangeLog changelogOpts -> changelog changelogOpts runAppState runLogger
|
|
|
|
Nuke -> nuke appState runLogger
|
|
|
|
Prefetch pfCom -> prefetch pfCom runAppState runLogger
|
|
|
|
GC gcOpts -> gc gcOpts runAppState runLogger
|
2021-06-18 09:39:01 +00:00
|
|
|
|
2020-04-17 16:26:55 +00:00
|
|
|
case res of
|
|
|
|
ExitSuccess -> pure ()
|
2020-04-17 18:50:23 +00:00
|
|
|
ef@(ExitFailure _) -> exitWith ef
|
2021-06-18 09:31:32 +00:00
|
|
|
|
2020-01-11 20:15:05 +00:00
|
|
|
pure ()
|
|
|
|
|
2020-04-17 16:26:55 +00:00
|
|
|
|